@@ -816,6 +816,116 @@ void Worker::Unref(const FunctionCallbackInfo<Value>& args) {
816816 }
817817}
818818
819+ class WorkerHeapStatisticsTaker : public AsyncWrap {
820+ public:
821+ WorkerHeapStatisticsTaker (Environment* env, Local<Object> obj)
822+ : AsyncWrap(env, obj, AsyncWrap::PROVIDER_WORKERHEAPSTATISTICS) {}
823+
824+ SET_NO_MEMORY_INFO ()
825+ SET_MEMORY_INFO_NAME (WorkerHeapStatisticsTaker)
826+ SET_SELF_SIZE (WorkerHeapStatisticsTaker)
827+ };
828+
829+ void Worker::GetHeapStatistics (const FunctionCallbackInfo<Value>& args) {
830+ Worker* w;
831+ ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
832+
833+ Environment* env = w->env ();
834+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (w);
835+ Local<Object> wrap;
836+ if (!env->worker_heap_statistics_taker_template ()
837+ ->NewInstance (env->context ())
838+ .ToLocal (&wrap)) {
839+ return ;
840+ }
841+
842+ // The created WorkerHeapStatisticsTaker is an object owned by main
843+ // thread's Isolate, it can not be accessed by worker thread
844+ std::unique_ptr<BaseObjectPtr<WorkerHeapStatisticsTaker>> taker =
845+ std::make_unique<BaseObjectPtr<WorkerHeapStatisticsTaker>>(
846+ MakeDetachedBaseObject<WorkerHeapStatisticsTaker>(env, wrap));
847+
848+ // Interrupt the worker thread and take a snapshot, then schedule a call
849+ // on the parent thread that turns that snapshot into a readable stream.
850+ bool scheduled = w->RequestInterrupt ([taker = std::move (taker),
851+ env](Environment* worker_env) mutable {
852+ // We create a unique pointer to HeapStatistics so that the actual object
853+ // it's not copied in the lambda, but only the pointer is.
854+ auto heap_stats = std::make_unique<v8::HeapStatistics>();
855+ worker_env->isolate ()->GetHeapStatistics (heap_stats.get ());
856+
857+ // Here, the worker thread temporarily owns the WorkerHeapStatisticsTaker
858+ // object.
859+
860+ env->SetImmediateThreadsafe (
861+ [taker = std::move (taker),
862+ heap_stats = std::move (heap_stats)](Environment* env) mutable {
863+ Isolate* isolate = env->isolate ();
864+ HandleScope handle_scope (isolate);
865+ Context::Scope context_scope (env->context ());
866+
867+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (taker->get ());
868+
869+ Local<v8::Name> heap_stats_names[] = {
870+ FIXED_ONE_BYTE_STRING (isolate, " total_heap_size" ),
871+ FIXED_ONE_BYTE_STRING (isolate, " total_heap_size_executable" ),
872+ FIXED_ONE_BYTE_STRING (isolate, " total_physical_size" ),
873+ FIXED_ONE_BYTE_STRING (isolate, " total_available_size" ),
874+ FIXED_ONE_BYTE_STRING (isolate, " used_heap_size" ),
875+ FIXED_ONE_BYTE_STRING (isolate, " heap_size_limit" ),
876+ FIXED_ONE_BYTE_STRING (isolate, " malloced_memory" ),
877+ FIXED_ONE_BYTE_STRING (isolate, " peak_malloced_memory" ),
878+ FIXED_ONE_BYTE_STRING (isolate, " does_zap_garbage" ),
879+ FIXED_ONE_BYTE_STRING (isolate, " number_of_native_contexts" ),
880+ FIXED_ONE_BYTE_STRING (isolate, " number_of_detached_contexts" ),
881+ FIXED_ONE_BYTE_STRING (isolate, " total_global_handles_size" ),
882+ FIXED_ONE_BYTE_STRING (isolate, " used_global_handles_size" ),
883+ FIXED_ONE_BYTE_STRING (isolate, " external_memory" )};
884+
885+ // Define an array of property values
886+ Local<Value> heap_stats_values[] = {
887+ Number::New (isolate, heap_stats->total_heap_size ()),
888+ Number::New (isolate, heap_stats->total_heap_size_executable ()),
889+ Number::New (isolate, heap_stats->total_physical_size ()),
890+ Number::New (isolate, heap_stats->total_available_size ()),
891+ Number::New (isolate, heap_stats->used_heap_size ()),
892+ Number::New (isolate, heap_stats->heap_size_limit ()),
893+ Number::New (isolate, heap_stats->malloced_memory ()),
894+ Number::New (isolate, heap_stats->peak_malloced_memory ()),
895+ Boolean::New (isolate, heap_stats->does_zap_garbage ()),
896+ Number::New (isolate, heap_stats->number_of_native_contexts ()),
897+ Number::New (isolate, heap_stats->number_of_detached_contexts ()),
898+ Number::New (isolate, heap_stats->total_global_handles_size ()),
899+ Number::New (isolate, heap_stats->used_global_handles_size ()),
900+ Number::New (isolate, heap_stats->external_memory ())};
901+
902+ DCHECK_EQ (arraysize (heap_stats_names), arraysize (heap_stats_values));
903+
904+ // Create the object with the property names and values
905+ Local<Object> stats = Object::New (isolate,
906+ Null (isolate),
907+ heap_stats_names,
908+ heap_stats_values,
909+ arraysize (heap_stats_names));
910+
911+ Local<Value> args[] = {stats};
912+ taker->get ()->MakeCallback (
913+ env->ondone_string (), arraysize (args), args);
914+ // implicitly delete `taker`
915+ },
916+ CallbackFlags::kUnrefed );
917+
918+ // Now, the lambda is delivered to the main thread, as a result, the
919+ // WorkerHeapStatisticsTaker object is delivered to the main thread, too.
920+ });
921+
922+ if (scheduled) {
923+ args.GetReturnValue ().Set (wrap);
924+ } else {
925+ args.GetReturnValue ().Set (Local<Object>());
926+ }
927+ }
928+
819929void Worker::GetResourceLimits (const FunctionCallbackInfo<Value>& args) {
820930 Worker* w;
821931 ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
@@ -996,6 +1106,7 @@ void CreateWorkerPerIsolateProperties(IsolateData* isolate_data,
9961106 SetProtoMethod (isolate, w, " takeHeapSnapshot" , Worker::TakeHeapSnapshot);
9971107 SetProtoMethod (isolate, w, " loopIdleTime" , Worker::LoopIdleTime);
9981108 SetProtoMethod (isolate, w, " loopStartTime" , Worker::LoopStartTime);
1109+ SetProtoMethod (isolate, w, " getHeapStatistics" , Worker::GetHeapStatistics);
9991110
10001111 SetConstructorFunction (isolate, target, " Worker" , w);
10011112 }
@@ -1014,6 +1125,20 @@ void CreateWorkerPerIsolateProperties(IsolateData* isolate_data,
10141125 wst->InstanceTemplate ());
10151126 }
10161127
1128+ {
1129+ Local<FunctionTemplate> wst = NewFunctionTemplate (isolate, nullptr );
1130+
1131+ wst->InstanceTemplate ()->SetInternalFieldCount (
1132+ WorkerHeapSnapshotTaker::kInternalFieldCount );
1133+ wst->Inherit (AsyncWrap::GetConstructorTemplate (isolate_data));
1134+
1135+ Local<String> wst_string =
1136+ FIXED_ONE_BYTE_STRING (isolate, " WorkerHeapStatisticsTaker" );
1137+ wst->SetClassName (wst_string);
1138+ isolate_data->set_worker_heap_statistics_taker_template (
1139+ wst->InstanceTemplate ());
1140+ }
1141+
10171142 SetMethod (isolate, target, " getEnvMessagePort" , GetEnvMessagePort);
10181143}
10191144
@@ -1079,6 +1204,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
10791204 registry->Register (Worker::TakeHeapSnapshot);
10801205 registry->Register (Worker::LoopIdleTime);
10811206 registry->Register (Worker::LoopStartTime);
1207+ registry->Register (Worker::GetHeapStatistics);
10821208}
10831209
10841210} // anonymous namespace
0 commit comments