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