diff --git a/src/bun.js/bindings/NapiRef.cpp b/src/bun.js/bindings/NapiRef.cpp index d33ac46cef..c1c114c933 100644 --- a/src/bun.js/bindings/NapiRef.cpp +++ b/src/bun.js/bindings/NapiRef.cpp @@ -37,7 +37,7 @@ void NapiRef::unref() void NapiRef::clear() { NAPI_LOG("ref clear %p", this); - finalizer.call(env, nativeObject); + finalizer.call(env.get(), nativeObject); globalObject.clear(); weakValueRef.clear(); strongRef.clear(); diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 378e747beb..3bbb9d55f2 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -3519,7 +3519,7 @@ GlobalObject::PromiseFunctions GlobalObject::promiseHandlerID(Zig::FFIFunction h napi_env GlobalObject::makeNapiEnv(const napi_module& mod) { - m_napiEnvs.append(std::make_unique(this, mod)); + m_napiEnvs.append(adoptRef(new napi_env__(this, mod))); return m_napiEnvs.last().get(); } diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index 6366c7ba92..2860824baf 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -60,6 +60,9 @@ class GlobalInternals; #include "BakeAdditionsToGlobalObject.h" #include "WriteBarrierList.h" +struct napi_env__; +using NapiEnv = WTF::RefPtr; + namespace Bun { class JSCommonJSExtensions; class InternalModuleRegistry; @@ -724,7 +727,7 @@ public: // De-optimization once `require("module").runMain` is written to bool hasOverriddenModuleRunMain = false; - WTF::Vector> m_napiEnvs; + WTF::Vector m_napiEnvs; napi_env makeNapiEnv(const napi_module&); napi_env makeNapiEnvForFFI(); bool hasNapiFinalizers() const; diff --git a/src/bun.js/bindings/napi.cpp b/src/bun.js/bindings/napi.cpp index b06b4a2b6f..314b3af06a 100644 --- a/src/bun.js/bindings/napi.cpp +++ b/src/bun.js/bindings/napi.cpp @@ -1126,9 +1126,11 @@ extern "C" napi_status napi_add_finalizer(napi_env env, napi_value js_object, *result = toNapi(ref); } else { // Otherwise, it's cheaper to just call .addFinalizer. - vm.heap.addFinalizer(object, [env, finalize_cb, native_object, finalize_hint](JSCell* cell) -> void { + // Capture env as RefPtr - automatically refs on capture, unrefs on destruction + NapiEnv envRef = env; + vm.heap.addFinalizer(object, [envRef = WTFMove(envRef), finalize_cb, native_object, finalize_hint](JSCell* cell) -> void { NAPI_LOG("finalizer %p", finalize_hint); - env->doFinalizer(finalize_cb, native_object, finalize_hint); + envRef->doFinalizer(finalize_cb, native_object, finalize_hint); }); } diff --git a/src/bun.js/bindings/napi.h b/src/bun.js/bindings/napi.h index f5a54314fe..085dc97560 100644 --- a/src/bun.js/bindings/napi.h +++ b/src/bun.js/bindings/napi.h @@ -168,7 +168,7 @@ static bool equal(napi_async_cleanup_hook_handle one, napi_async_cleanup_hook_ha } while (0) // Named this way so we can manipulate napi_env values directly (since napi_env is defined as a pointer to struct napi_env__) -struct napi_env__ { +struct napi_env__ : public RefCounted { public: napi_env__(Zig::GlobalObject* globalObject, const napi_module& napiModule) : m_globalObject(globalObject) @@ -506,6 +506,8 @@ private: } }; +using NapiEnv = WTF::RefPtr; + extern "C" void napi_internal_cleanup_env_cpp(napi_env); extern "C" void napi_internal_remove_finalizer(napi_env, napi_finalize callback, void* hint, void* data); @@ -659,9 +661,9 @@ public: void unref(); void clear(); - NapiRef(napi_env env, uint32_t count, Bun::NapiFinalizer finalizer) - : env(env) - , globalObject(JSC::Weak(env->globalObject())) + NapiRef(napi_env rawEnv, uint32_t count, Bun::NapiFinalizer finalizer) + : env(rawEnv) + , globalObject(JSC::Weak(rawEnv->globalObject())) , finalizer(WTFMove(finalizer)) , refCount(count) { @@ -708,14 +710,14 @@ public: // calling the finalizer Bun::NapiFinalizer saved_finalizer = this->finalizer; this->finalizer.clear(); - saved_finalizer.call(env, nativeObject, !env->mustDeferFinalizers() || !env->inGC()); + saved_finalizer.call(env.get(), nativeObject, !env->mustDeferFinalizers() || !env->inGC()); } ~NapiRef() { NAPI_LOG("destruct napi ref %p", this); if (boundCleanup) { - boundCleanup->deactivate(env); + boundCleanup->deactivate(env.get()); boundCleanup = nullptr; } @@ -728,7 +730,7 @@ public: weakValueRef.clear(); } - napi_env env = nullptr; + NapiEnv env = nullptr; JSC::Weak globalObject; NapiWeakValue weakValueRef; JSC::Strong strongRef;