@@ -538,13 +538,19 @@ class AsyncContext {
538538 public:
539539 AsyncContext (node_napi_env env,
540540 v8::Local<v8::Object> resource_object,
541- v8::Local<v8::String> resource_name)
541+ const v8::Local<v8::String> resource_name,
542+ bool externally_managed_resource)
542543 : env_(env) {
543544 async_id_ = node_env ()->new_async_id ();
544545 trigger_async_id_ = node_env ()->get_default_trigger_async_id ();
545546 v8::Isolate* isolate = node_env ()->isolate ();
546547 resource_.Reset (isolate, resource_object);
547548 context_frame_.Reset (isolate, node::async_context_frame::current (isolate));
549+ lost_reference_ = false ;
550+ if (externally_managed_resource) {
551+ resource_.SetWeak (
552+ this , AsyncContext::WeakCallback, v8::WeakCallbackType::kParameter );
553+ }
548554
549555 node::AsyncWrap::EmitAsyncInit (node_env (),
550556 resource_object,
@@ -553,13 +559,18 @@ class AsyncContext {
553559 trigger_async_id_);
554560 }
555561
556- ~AsyncContext () { node::AsyncWrap::EmitDestroy (node_env (), async_id_); }
562+ ~AsyncContext () {
563+ resource_.Reset ();
564+ lost_reference_ = true ;
565+ node::AsyncWrap::EmitDestroy (node_env (), async_id_);
566+ }
557567
558568 inline v8::MaybeLocal<v8::Value> MakeCallback (
559569 v8::Local<v8::Object> recv,
560570 const v8::Local<v8::Function> callback,
561571 int argc,
562572 v8::Local<v8::Value> argv[]) {
573+ EnsureReference ();
563574 return node::InternalMakeCallback (
564575 node_env (),
565576 resource (),
@@ -572,11 +583,21 @@ class AsyncContext {
572583 }
573584
574585 inline napi_callback_scope OpenCallbackScope () {
586+ EnsureReference ();
575587 auto scope = new HeapAllocatedCallbackScope (this );
576588 env_->open_callback_scopes ++;
577589 return scope->to_opaque ();
578590 }
579591
592+ inline void EnsureReference () {
593+ if (lost_reference_) {
594+ const v8::HandleScope handle_scope (node_env ()->isolate ());
595+ resource_.Reset (node_env ()->isolate (),
596+ v8::Object::New (node_env ()->isolate ()));
597+ lost_reference_ = false ;
598+ }
599+ }
600+
580601 inline node::Environment* node_env () { return env_->node_env (); }
581602 inline v8::Local<v8::Object> resource () {
582603 return resource_.Get (node_env ()->isolate ());
@@ -588,10 +609,15 @@ class AsyncContext {
588609 static inline void CloseCallbackScope (node_napi_env env,
589610 napi_callback_scope s) {
590611 delete HeapAllocatedCallbackScope::FromOpaque (s);
591- CHECK_GT (env->open_callback_scopes , 0 );
592612 env->open_callback_scopes --;
593613 }
594614
615+ static void WeakCallback (const v8::WeakCallbackInfo<AsyncContext>& data) {
616+ AsyncContext* async_context = data.GetParameter ();
617+ async_context->resource_ .Reset ();
618+ async_context->lost_reference_ = true ;
619+ }
620+
595621 private:
596622 class HeapAllocatedCallbackScope final {
597623 public:
@@ -603,11 +629,15 @@ class AsyncContext {
603629 }
604630
605631 explicit HeapAllocatedCallbackScope (AsyncContext* async_context)
606- cs_(async_context->node_env (),
607- &async_context->resource_storage_,
608- async_context->async_context()) {}
632+ : resource_storage_(async_context->node_env ()->isolate(),
633+ async_context->resource_.Get(
634+ async_context->node_env ()->isolate())),
635+ cs_(async_context->node_env (),
636+ &resource_storage_,
637+ async_context->async_context()) {}
609638
610639 private:
640+ v8::Global<v8::Object> resource_storage_;
611641 node::CallbackScope cs_;
612642 };
613643
@@ -913,17 +943,23 @@ napi_status NAPI_CDECL napi_async_init(napi_env env,
913943 v8::Local<v8::Context> context = env->context ();
914944
915945 v8::Local<v8::Object> v8_resource;
946+ bool externally_managed_resource;
916947 if (async_resource != nullptr ) {
917948 CHECK_TO_OBJECT (env, context, v8_resource, async_resource);
949+ externally_managed_resource = true ;
918950 } else {
919951 v8_resource = v8::Object::New (isolate);
952+ externally_managed_resource = false ;
920953 }
921954
922955 v8::Local<v8::String> v8_resource_name;
923956 CHECK_TO_STRING (env, context, v8_resource_name, async_resource_name);
924957
925- v8impl::AsyncContext* async_context = new v8impl::AsyncContext (
926- reinterpret_cast <node_napi_env>(env), v8_resource, v8_resource_name);
958+ v8impl::AsyncContext* async_context =
959+ new v8impl::AsyncContext (reinterpret_cast <node_napi_env>(env),
960+ v8_resource,
961+ v8_resource_name,
962+ externally_managed_resource);
927963
928964 *result = reinterpret_cast <napi_async_context>(async_context);
929965
0 commit comments