@@ -771,28 +771,49 @@ void Worker::TakeHeapSnapshot(const FunctionCallbackInfo<Value>& args) { |
771 | 771 | ->NewInstance(env->context()).ToLocal(&wrap)) { |
772 | 772 | return; |
773 | 773 | } |
774 | | - BaseObjectPtr<WorkerHeapSnapshotTaker> taker = |
775 | | - MakeDetachedBaseObject<WorkerHeapSnapshotTaker>(env, wrap); |
| 774 | + |
| 775 | + // The created WorkerHeapSnapshotTaker is an object owned by main |
| 776 | + // thread's Isolate, it can not be accessed by worker thread |
| 777 | + std::unique_ptr<BaseObjectPtr<WorkerHeapSnapshotTaker>> taker = |
| 778 | + std::make_unique<BaseObjectPtr<WorkerHeapSnapshotTaker>>( |
| 779 | + MakeDetachedBaseObject<WorkerHeapSnapshotTaker>(env, wrap)); |
776 | 780 |
|
777 | 781 | // Interrupt the worker thread and take a snapshot, then schedule a call |
778 | 782 | // on the parent thread that turns that snapshot into a readable stream. |
779 | | - bool scheduled = w->RequestInterrupt([taker, env](Environment* worker_env) { |
780 | | - heap::HeapSnapshotPointer snapshot { |
781 | | - worker_env->isolate()->GetHeapProfiler()->TakeHeapSnapshot() }; |
| 783 | + bool scheduled = w->RequestInterrupt([taker = std::move(taker), |
| 784 | + env](Environment* worker_env) mutable { |
| 785 | + heap::HeapSnapshotPointer snapshot{ |
| 786 | + worker_env->isolate()->GetHeapProfiler()->TakeHeapSnapshot()}; |
782 | 787 | CHECK(snapshot); |
| 788 | + |
| 789 | + // Here, the worker thread temporarily owns the WorkerHeapSnapshotTaker |
| 790 | + // object. |
| 791 | + |
783 | 792 | env->SetImmediateThreadsafe( |
784 | | - [taker, snapshot = std::move(snapshot)](Environment* env) mutable { |
| 793 | + [taker = std::move(taker), |
| 794 | + snapshot = std::move(snapshot)](Environment* env) mutable { |
785 | 795 | HandleScope handle_scope(env->isolate()); |
786 | 796 | Context::Scope context_scope(env->context()); |
787 | 797 |
|
788 | | - AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope(taker.get()); |
789 | | - BaseObjectPtr<AsyncWrap> stream = heap::CreateHeapSnapshotStream( |
790 | | - env, std::move(snapshot)); |
791 | | - Local<Value> args[] = { stream->object() }; |
792 | | - taker->MakeCallback(env->ondone_string(), arraysize(args), args); |
793 | | - }, CallbackFlags::kUnrefed); |
| 798 | + AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope(taker->get()); |
| 799 | + BaseObjectPtr<AsyncWrap> stream = |
| 800 | + heap::CreateHeapSnapshotStream(env, std::move(snapshot)); |
| 801 | + Local<Value> args[] = {stream->object()}; |
| 802 | + taker->get()->MakeCallback( |
| 803 | + env->ondone_string(), arraysize(args), args); |
| 804 | + // implicitly delete `taker` |
| 805 | + }, |
| 806 | + CallbackFlags::kUnrefed); |
| 807 | + |
| 808 | + // Now, the lambda is delivered to the main thread, as a result, the |
| 809 | + // WorkerHeapSnapshotTaker object is delivered to the main thread, too. |
794 | 810 | }); |
795 | | - args.GetReturnValue().Set(scheduled ? taker->object() : Local<Object>()); |
| 811 | + |
| 812 | + if (scheduled) { |
| 813 | + args.GetReturnValue().Set(wrap); |
| 814 | + } else { |
| 815 | + args.GetReturnValue().Set(Local<Object>()); |
| 816 | + } |
796 | 817 | } |
797 | 818 |
|
798 | 819 | void Worker::LoopIdleTime(const FunctionCallbackInfo<Value>& args) { |
|