mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
Refactor napi_env to use Ref-counted NapiEnv (#23940)
### What does this PR do? Replaces raw napi_env pointers with WTF::Ref<NapiEnv> for improved memory management and safety. Updates related classes, function signatures, and finalizer handling to use reference counting. Adds ref/deref methods to NapiEnv and integrates them in Zig and C++ code paths, ensuring proper lifecycle management for N-API environments. ### How did you verify your code works?
This commit is contained in:
@@ -39,7 +39,7 @@ typedef _Bool bool;
|
||||
#define false 0
|
||||
|
||||
#ifndef SRC_JS_NATIVE_API_TYPES_H_
|
||||
typedef struct napi_env__ *napi_env;
|
||||
typedef struct NapiEnv *napi_env;
|
||||
typedef int64_t napi_value;
|
||||
typedef enum {
|
||||
napi_ok,
|
||||
@@ -67,7 +67,7 @@ typedef enum {
|
||||
} napi_status;
|
||||
BUN_FFI_IMPORT void* NapiHandleScope__open(void* napi_env, bool detached);
|
||||
BUN_FFI_IMPORT void NapiHandleScope__close(void* napi_env, void* handleScope);
|
||||
BUN_FFI_IMPORT extern struct napi_env__ Bun__thisFFIModuleNapiEnv;
|
||||
BUN_FFI_IMPORT extern struct NapiEnv Bun__thisFFIModuleNapiEnv;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -637,7 +637,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionDlopen, (JSC::JSGlobalObject * globalOb
|
||||
auto env = globalObject->makeNapiEnv(nmodule);
|
||||
env->filename = filename_cstr;
|
||||
|
||||
auto encoded = reinterpret_cast<EncodedJSValue>(napi_register_module_v1(env, reinterpret_cast<napi_value>(exportsValue)));
|
||||
auto encoded = reinterpret_cast<EncodedJSValue>(napi_register_module_v1(env.ptr(), reinterpret_cast<napi_value>(exportsValue)));
|
||||
if (env->throwPendingException()) {
|
||||
return {};
|
||||
}
|
||||
@@ -656,7 +656,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionDlopen, (JSC::JSGlobalObject * globalOb
|
||||
// TODO: think about the finalizer here
|
||||
// currently we do not dealloc napi modules so we don't have to worry about it right now
|
||||
auto* meta = new Bun::NapiModuleMeta(globalObject->m_pendingNapiModuleDlopenHandle);
|
||||
Bun::NapiExternal* napi_external = Bun::NapiExternal::create(vm, globalObject->NapiExternalStructure(), meta, nullptr, env, nullptr);
|
||||
Bun::NapiExternal* napi_external = Bun::NapiExternal::create(vm, globalObject->NapiExternalStructure(), meta, nullptr, nullptr, env.ptr());
|
||||
bool success = resultObject->putDirect(vm, WebCore::builtinNames(vm).napiDlopenHandlePrivateName(), napi_external, JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
|
||||
ASSERT(success);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
@@ -37,7 +37,7 @@ void NapiRef::unref()
|
||||
void NapiRef::clear()
|
||||
{
|
||||
NAPI_LOG("ref clear %p", this);
|
||||
finalizer.call(env, nativeObject);
|
||||
finalizer.call(env.ptr(), nativeObject);
|
||||
globalObject.clear();
|
||||
weakValueRef.clear();
|
||||
strongRef.clear();
|
||||
|
||||
@@ -3517,10 +3517,10 @@ GlobalObject::PromiseFunctions GlobalObject::promiseHandlerID(Zig::FFIFunction h
|
||||
}
|
||||
}
|
||||
|
||||
napi_env GlobalObject::makeNapiEnv(const napi_module& mod)
|
||||
Ref<NapiEnv> GlobalObject::makeNapiEnv(const napi_module& mod)
|
||||
{
|
||||
m_napiEnvs.append(std::make_unique<napi_env__>(this, mod));
|
||||
return m_napiEnvs.last().get();
|
||||
m_napiEnvs.append(NapiEnv::create(this, mod));
|
||||
return m_napiEnvs.last();
|
||||
}
|
||||
|
||||
napi_env GlobalObject::makeNapiEnvForFFI()
|
||||
@@ -3534,7 +3534,7 @@ napi_env GlobalObject::makeNapiEnvForFFI()
|
||||
.nm_priv = nullptr,
|
||||
.reserved = {},
|
||||
});
|
||||
return out;
|
||||
return &out.leakRef();
|
||||
}
|
||||
|
||||
bool GlobalObject::hasNapiFinalizers() const
|
||||
|
||||
@@ -724,8 +724,8 @@ public:
|
||||
// De-optimization once `require("module").runMain` is written to
|
||||
bool hasOverriddenModuleRunMain = false;
|
||||
|
||||
WTF::Vector<std::unique_ptr<napi_env__>> m_napiEnvs;
|
||||
napi_env makeNapiEnv(const napi_module&);
|
||||
WTF::Vector<WTF::Ref<NapiEnv>> m_napiEnvs;
|
||||
Ref<NapiEnv> makeNapiEnv(const napi_module&);
|
||||
napi_env makeNapiEnvForFFI();
|
||||
bool hasNapiFinalizers() const;
|
||||
|
||||
|
||||
@@ -698,7 +698,7 @@ void Napi::executePendingNapiModule(Zig::GlobalObject* globalObject)
|
||||
ASSERT(globalObject->m_pendingNapiModule);
|
||||
|
||||
auto& mod = *globalObject->m_pendingNapiModule;
|
||||
napi_env env = globalObject->makeNapiEnv(mod);
|
||||
Ref<NapiEnv> env = globalObject->makeNapiEnv(mod);
|
||||
auto keyStr = WTF::String::fromUTF8(mod.nm_modname);
|
||||
JSValue pendingNapiModule = globalObject->m_pendingNapiModuleAndExports[0].get();
|
||||
JSObject* object = (pendingNapiModule && pendingNapiModule.isObject()) ? pendingNapiModule.getObject()
|
||||
@@ -727,7 +727,7 @@ void Napi::executePendingNapiModule(Zig::GlobalObject* globalObject)
|
||||
JSValue resultValue;
|
||||
|
||||
if (mod.nm_register_func) {
|
||||
resultValue = toJS(mod.nm_register_func(env, toNapi(object, globalObject)));
|
||||
resultValue = toJS(mod.nm_register_func(env.ptr(), toNapi(object, globalObject)));
|
||||
} else {
|
||||
JSValue errorInstance = createError(globalObject, makeString("Module has no declared entry point."_s));
|
||||
globalObject->m_pendingNapiModuleAndExports[0].set(vm, globalObject, errorInstance);
|
||||
@@ -751,7 +751,7 @@ void Napi::executePendingNapiModule(Zig::GlobalObject* globalObject)
|
||||
auto* meta = new Bun::NapiModuleMeta(globalObject->m_pendingNapiModuleDlopenHandle);
|
||||
|
||||
// TODO: think about the finalizer here
|
||||
Bun::NapiExternal* napi_external = Bun::NapiExternal::create(vm, globalObject->NapiExternalStructure(), meta, nullptr, env, nullptr);
|
||||
Bun::NapiExternal* napi_external = Bun::NapiExternal::create(vm, globalObject->NapiExternalStructure(), meta, nullptr, nullptr, env.ptr());
|
||||
|
||||
bool success = resultValue.getObject()->putDirect(vm, WebCore::builtinNames(vm).napiDlopenHandlePrivateName(), napi_external, JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
|
||||
ASSERT(success);
|
||||
@@ -791,7 +791,7 @@ static void wrap_cleanup(napi_env env, void* data, void* hint)
|
||||
{
|
||||
auto* ref = reinterpret_cast<NapiRef*>(data);
|
||||
ASSERT(ref->boundCleanup != nullptr);
|
||||
ref->boundCleanup->deactivate(env);
|
||||
ref->boundCleanup->deactivate(*env);
|
||||
ref->boundCleanup = nullptr;
|
||||
ref->callFinalizer();
|
||||
}
|
||||
@@ -842,7 +842,7 @@ extern "C" napi_status napi_wrap(napi_env env,
|
||||
NAPI_RETURN_EARLY_IF_FALSE(env, existing_wrap == nullptr, napi_invalid_arg);
|
||||
|
||||
// create a new weak reference (refcount 0)
|
||||
auto* ref = new NapiRef(env, 0, Bun::NapiFinalizer { finalize_cb, finalize_hint });
|
||||
auto* ref = new NapiRef(*env, 0, Bun::NapiFinalizer { finalize_cb, finalize_hint });
|
||||
// In case the ref's finalizer is never called, we'll add a finalizer to execute on exit.
|
||||
const auto& bound_cleanup = env->addFinalizer(wrap_cleanup, native_object, ref);
|
||||
ref->boundCleanup = &bound_cleanup;
|
||||
@@ -852,7 +852,7 @@ extern "C" napi_status napi_wrap(napi_env env,
|
||||
napi_instance->napiRef = ref;
|
||||
} else {
|
||||
// wrap the ref in an external so that it can serve as a JSValue
|
||||
auto* external = Bun::NapiExternal::create(JSC::getVM(globalObject), globalObject->NapiExternalStructure(), ref, nullptr, env, nullptr);
|
||||
auto* external = Bun::NapiExternal::create(JSC::getVM(globalObject), globalObject->NapiExternalStructure(), ref, nullptr, nullptr, env);
|
||||
jsc_object->putDirect(vm, propertyName, JSValue(external));
|
||||
}
|
||||
|
||||
@@ -1082,7 +1082,7 @@ extern "C" napi_status napi_create_reference(napi_env env, napi_value value,
|
||||
can_be_weak = false;
|
||||
}
|
||||
|
||||
auto* ref = new NapiRef(env, initial_refcount, Bun::NapiFinalizer {});
|
||||
auto* ref = new NapiRef(*env, initial_refcount, Bun::NapiFinalizer {});
|
||||
ref->setValueInitial(val, can_be_weak);
|
||||
|
||||
*result = toNapi(ref);
|
||||
@@ -1119,14 +1119,14 @@ extern "C" napi_status napi_add_finalizer(napi_env env, napi_value js_object,
|
||||
|
||||
if (result) {
|
||||
// If they're expecting a Ref, use the ref.
|
||||
auto* ref = new NapiRef(env, 0, Bun::NapiFinalizer { finalize_cb, finalize_hint });
|
||||
auto* ref = new NapiRef(*env, 0, Bun::NapiFinalizer { finalize_cb, finalize_hint });
|
||||
// TODO(@heimskr): consider detecting whether the value can't be weak, as we do in napi_create_reference.
|
||||
ref->setValueInitial(object, true);
|
||||
ref->nativeObject = native_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 {
|
||||
vm.heap.addFinalizer(object, [env = WTF::Ref<NapiEnv>(*env), finalize_cb, native_object, finalize_hint](JSCell* cell) -> void {
|
||||
NAPI_LOG("finalizer %p", finalize_hint);
|
||||
env->doFinalizer(finalize_cb, native_object, finalize_hint);
|
||||
});
|
||||
@@ -1991,7 +1991,7 @@ extern "C" napi_status napi_create_external_buffer(napi_env env, size_t length,
|
||||
|
||||
Zig::GlobalObject* globalObject = toJS(env);
|
||||
|
||||
auto arrayBuffer = ArrayBuffer::createFromBytes({ reinterpret_cast<const uint8_t*>(data), length }, createSharedTask<void(void*)>([env, finalize_hint, finalize_cb](void* p) {
|
||||
auto arrayBuffer = ArrayBuffer::createFromBytes({ reinterpret_cast<const uint8_t*>(data), length }, createSharedTask<void(void*)>([env = WTF::Ref<NapiEnv>(*env), finalize_hint, finalize_cb](void* p) {
|
||||
NAPI_LOG("external buffer finalizer");
|
||||
env->doFinalizer(finalize_cb, p, finalize_hint);
|
||||
}));
|
||||
@@ -2303,7 +2303,7 @@ extern "C" napi_status napi_create_external(napi_env env, void* data,
|
||||
JSC::VM& vm = JSC::getVM(globalObject);
|
||||
|
||||
auto* structure = globalObject->NapiExternalStructure();
|
||||
JSValue value = Bun::NapiExternal::create(vm, structure, data, finalize_hint, env, finalize_cb);
|
||||
JSValue value = Bun::NapiExternal::create(vm, structure, data, finalize_hint, finalize_cb, env);
|
||||
JSC::EnsureStillAliveScope ensureStillAlive(value);
|
||||
*result = toNapi(value, globalObject);
|
||||
NAPI_RETURN_SUCCESS(env);
|
||||
@@ -2902,4 +2902,14 @@ extern "C" bool NapiEnv__getAndClearPendingException(napi_env env, JSC::EncodedJ
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" void NapiEnv__ref(napi_env env)
|
||||
{
|
||||
env->ref();
|
||||
}
|
||||
|
||||
extern "C" void NapiEnv__deref(napi_env env)
|
||||
{
|
||||
env->deref();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -168,9 +168,11 @@ 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 NapiEnv : public WTF::RefCounted<NapiEnv> {
|
||||
WTF_MAKE_STRUCT_TZONE_ALLOCATED(NapiEnv);
|
||||
|
||||
public:
|
||||
napi_env__(Zig::GlobalObject* globalObject, const napi_module& napiModule)
|
||||
NapiEnv(Zig::GlobalObject* globalObject, const napi_module& napiModule)
|
||||
: m_globalObject(globalObject)
|
||||
, m_napiModule(napiModule)
|
||||
, m_vm(JSC::getVM(globalObject))
|
||||
@@ -178,7 +180,12 @@ public:
|
||||
napi_internal_register_cleanup_zig(this);
|
||||
}
|
||||
|
||||
~napi_env__()
|
||||
static Ref<NapiEnv> create(Zig::GlobalObject* globalObject, const napi_module& napiModule)
|
||||
{
|
||||
return adoptRef(*new NapiEnv(globalObject, napiModule));
|
||||
}
|
||||
|
||||
~NapiEnv()
|
||||
{
|
||||
delete[] filename;
|
||||
}
|
||||
@@ -434,12 +441,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void deactivate(napi_env env) const
|
||||
void deactivate(NapiEnv& env) const
|
||||
{
|
||||
if (env->isFinishingFinalizers()) {
|
||||
if (env.isFinishingFinalizers()) {
|
||||
active = false;
|
||||
} else {
|
||||
env->removeFinalizer(*this);
|
||||
env.removeFinalizer(*this);
|
||||
// At this point the BoundFinalizer has been destroyed, but because we're not doing anything else here it's safe.
|
||||
// https://isocpp.org/wiki/faq/freestore-mgmt#delete-this
|
||||
}
|
||||
@@ -451,7 +458,7 @@ public:
|
||||
}
|
||||
|
||||
struct Hash {
|
||||
std::size_t operator()(const napi_env__::BoundFinalizer& bound) const
|
||||
std::size_t operator()(const NapiEnv::BoundFinalizer& bound) const
|
||||
{
|
||||
constexpr std::hash<void*> hasher;
|
||||
constexpr std::ptrdiff_t magic = 0x9e3779b9;
|
||||
@@ -659,7 +666,7 @@ public:
|
||||
void unref();
|
||||
void clear();
|
||||
|
||||
NapiRef(napi_env env, uint32_t count, Bun::NapiFinalizer finalizer)
|
||||
NapiRef(Ref<NapiEnv>&& env, uint32_t count, Bun::NapiFinalizer finalizer)
|
||||
: env(env)
|
||||
, globalObject(JSC::Weak<JSC::JSGlobalObject>(env->globalObject()))
|
||||
, finalizer(WTFMove(finalizer))
|
||||
@@ -708,7 +715,7 @@ 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.ptr(), nativeObject, !env->mustDeferFinalizers() || !env->inGC());
|
||||
}
|
||||
|
||||
~NapiRef()
|
||||
@@ -728,12 +735,12 @@ public:
|
||||
weakValueRef.clear();
|
||||
}
|
||||
|
||||
napi_env env = nullptr;
|
||||
WTF::Ref<NapiEnv> env;
|
||||
JSC::Weak<JSC::JSGlobalObject> globalObject;
|
||||
NapiWeakValue weakValueRef;
|
||||
JSC::Strong<JSC::Unknown> strongRef;
|
||||
Bun::NapiFinalizer finalizer;
|
||||
const napi_env__::BoundFinalizer* boundCleanup = nullptr;
|
||||
const NapiEnv::BoundFinalizer* boundCleanup = nullptr;
|
||||
void* nativeObject = nullptr;
|
||||
uint32_t refCount = 0;
|
||||
bool releaseOnWeaken = false;
|
||||
|
||||
@@ -5,8 +5,8 @@ namespace Bun {
|
||||
|
||||
NapiExternal::~NapiExternal()
|
||||
{
|
||||
ASSERT(m_env);
|
||||
m_finalizer.call(m_env, m_value, !m_env->mustDeferFinalizers());
|
||||
auto* env = m_env.get();
|
||||
m_finalizer.call(env, m_value, env && !env->mustDeferFinalizers());
|
||||
}
|
||||
|
||||
void NapiExternal::destroy(JSC::JSCell* cell)
|
||||
@@ -14,6 +14,6 @@ void NapiExternal::destroy(JSC::JSCell* cell)
|
||||
static_cast<NapiExternal*>(cell)->~NapiExternal();
|
||||
}
|
||||
|
||||
const ClassInfo NapiExternal::s_info = { "External"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(NapiExternal) };
|
||||
const ClassInfo NapiExternal::s_info = { "NapiExternal"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(NapiExternal) };
|
||||
|
||||
}
|
||||
|
||||
@@ -22,8 +22,9 @@ class NapiExternal : public JSC::JSDestructibleObject {
|
||||
using Base = JSC::JSDestructibleObject;
|
||||
|
||||
public:
|
||||
NapiExternal(JSC::VM& vm, JSC::Structure* structure)
|
||||
NapiExternal(JSC::VM& vm, JSC::Structure* structure, WTF::RefPtr<NapiEnv> env)
|
||||
: Base(vm, structure)
|
||||
, m_env(env)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -53,11 +54,11 @@ public:
|
||||
JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
|
||||
}
|
||||
|
||||
static NapiExternal* create(JSC::VM& vm, JSC::Structure* structure, void* value, void* finalizer_hint, napi_env env, napi_finalize callback)
|
||||
static NapiExternal* create(JSC::VM& vm, JSC::Structure* structure, void* value, void* finalizer_hint, napi_finalize callback, WTF::RefPtr<NapiEnv> env = nullptr)
|
||||
{
|
||||
NapiExternal* accessor = new (NotNull, JSC::allocateCell<NapiExternal>(vm)) NapiExternal(vm, structure);
|
||||
NapiExternal* accessor = new (NotNull, JSC::allocateCell<NapiExternal>(vm)) NapiExternal(vm, structure, env);
|
||||
|
||||
accessor->finishCreation(vm, value, finalizer_hint, env, callback);
|
||||
accessor->finishCreation(vm, value, finalizer_hint, callback);
|
||||
|
||||
#if ASSERT_ENABLED
|
||||
if (auto* callFrame = vm.topCallFrame) {
|
||||
@@ -81,11 +82,10 @@ public:
|
||||
return accessor;
|
||||
}
|
||||
|
||||
void finishCreation(JSC::VM& vm, void* value, void* finalizer_hint, napi_env env, napi_finalize callback)
|
||||
void finishCreation(JSC::VM& vm, void* value, void* finalizer_hint, napi_finalize callback)
|
||||
{
|
||||
Base::finishCreation(vm);
|
||||
m_value = value;
|
||||
m_env = env;
|
||||
m_finalizer = NapiFinalizer { callback, finalizer_hint };
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public:
|
||||
|
||||
void* m_value;
|
||||
NapiFinalizer m_finalizer;
|
||||
napi_env m_env;
|
||||
WTF::RefPtr<NapiEnv> m_env;
|
||||
|
||||
#if ASSERT_ENABLED
|
||||
String sourceOriginURL = String();
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
namespace Bun {
|
||||
|
||||
void NapiFinalizer::call(napi_env env, void* data, bool immediate)
|
||||
void NapiFinalizer::call(WTF::RefPtr<NapiEnv> env, void* data, bool immediate)
|
||||
{
|
||||
if (m_callback) {
|
||||
NAPI_LOG_CURRENT_FUNCTION;
|
||||
if (immediate) {
|
||||
m_callback(env, data, m_hint);
|
||||
m_callback(env.get(), data, m_hint);
|
||||
} else {
|
||||
napi_internal_enqueue_finalizer(env, m_callback, data, m_hint);
|
||||
napi_internal_enqueue_finalizer(env.get(), m_callback, data, m_hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
|
||||
NapiFinalizer() = default;
|
||||
|
||||
void call(napi_env env, void* data, bool immediate = false);
|
||||
void call(WTF::RefPtr<NapiEnv> env, void* data, bool immediate = false);
|
||||
void clear();
|
||||
|
||||
inline napi_finalize callback() const { return m_callback; }
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "BunClientData.h"
|
||||
#include "root.h"
|
||||
|
||||
typedef struct napi_env__* napi_env;
|
||||
typedef struct NapiEnv* napi_env;
|
||||
|
||||
namespace Bun {
|
||||
|
||||
|
||||
@@ -13,86 +13,86 @@ typedef uint16_t char16_t;
|
||||
|
||||
// JSVM API types are all opaque pointers for ABI stability
|
||||
// typedef undefined structs instead of void* for compile time type safety
|
||||
typedef struct napi_env__ *napi_env;
|
||||
typedef struct napi_value__ *napi_value;
|
||||
typedef struct napi_ref__ *napi_ref;
|
||||
typedef struct napi_handle_scope__ *napi_handle_scope;
|
||||
typedef struct napi_escapable_handle_scope__ *napi_escapable_handle_scope;
|
||||
typedef struct napi_callback_info__ *napi_callback_info;
|
||||
typedef struct napi_deferred__ *napi_deferred;
|
||||
typedef struct NapiEnv* napi_env;
|
||||
typedef struct napi_value__* napi_value;
|
||||
typedef struct napi_ref__* napi_ref;
|
||||
typedef struct napi_handle_scope__* napi_handle_scope;
|
||||
typedef struct napi_escapable_handle_scope__* napi_escapable_handle_scope;
|
||||
typedef struct napi_callback_info__* napi_callback_info;
|
||||
typedef struct napi_deferred__* napi_deferred;
|
||||
|
||||
typedef enum {
|
||||
napi_default = 0,
|
||||
napi_writable = 1 << 0,
|
||||
napi_enumerable = 1 << 1,
|
||||
napi_configurable = 1 << 2,
|
||||
napi_default = 0,
|
||||
napi_writable = 1 << 0,
|
||||
napi_enumerable = 1 << 1,
|
||||
napi_configurable = 1 << 2,
|
||||
|
||||
// Used with napi_define_class to distinguish static properties
|
||||
// from instance properties. Ignored by napi_define_properties.
|
||||
napi_static = 1 << 10,
|
||||
// Used with napi_define_class to distinguish static properties
|
||||
// from instance properties. Ignored by napi_define_properties.
|
||||
napi_static = 1 << 10,
|
||||
|
||||
#if NAPI_VERSION >= 8
|
||||
// Default for class methods.
|
||||
napi_default_method = napi_writable | napi_configurable,
|
||||
// Default for class methods.
|
||||
napi_default_method = napi_writable | napi_configurable,
|
||||
|
||||
// Default for object properties, like in JS obj[prop].
|
||||
napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable,
|
||||
// Default for object properties, like in JS obj[prop].
|
||||
napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable,
|
||||
#endif // NAPI_VERSION >= 8
|
||||
} napi_property_attributes;
|
||||
|
||||
typedef enum {
|
||||
// ES6 types (corresponds to typeof)
|
||||
napi_undefined,
|
||||
napi_null,
|
||||
napi_boolean,
|
||||
napi_number,
|
||||
napi_string,
|
||||
napi_symbol,
|
||||
napi_object,
|
||||
napi_function,
|
||||
napi_external,
|
||||
napi_bigint,
|
||||
// ES6 types (corresponds to typeof)
|
||||
napi_undefined,
|
||||
napi_null,
|
||||
napi_boolean,
|
||||
napi_number,
|
||||
napi_string,
|
||||
napi_symbol,
|
||||
napi_object,
|
||||
napi_function,
|
||||
napi_external,
|
||||
napi_bigint,
|
||||
} napi_valuetype;
|
||||
|
||||
typedef enum {
|
||||
napi_int8_array,
|
||||
napi_uint8_array,
|
||||
napi_uint8_clamped_array,
|
||||
napi_int16_array,
|
||||
napi_uint16_array,
|
||||
napi_int32_array,
|
||||
napi_uint32_array,
|
||||
napi_float32_array,
|
||||
napi_float64_array,
|
||||
napi_bigint64_array,
|
||||
napi_biguint64_array,
|
||||
napi_int8_array,
|
||||
napi_uint8_array,
|
||||
napi_uint8_clamped_array,
|
||||
napi_int16_array,
|
||||
napi_uint16_array,
|
||||
napi_int32_array,
|
||||
napi_uint32_array,
|
||||
napi_float32_array,
|
||||
napi_float64_array,
|
||||
napi_bigint64_array,
|
||||
napi_biguint64_array,
|
||||
} napi_typedarray_type;
|
||||
|
||||
typedef enum {
|
||||
napi_ok,
|
||||
napi_invalid_arg,
|
||||
napi_object_expected,
|
||||
napi_string_expected,
|
||||
napi_name_expected,
|
||||
napi_function_expected,
|
||||
napi_number_expected,
|
||||
napi_boolean_expected,
|
||||
napi_array_expected,
|
||||
napi_generic_failure,
|
||||
napi_pending_exception,
|
||||
napi_cancelled,
|
||||
napi_escape_called_twice,
|
||||
napi_handle_scope_mismatch,
|
||||
napi_callback_scope_mismatch,
|
||||
napi_queue_full,
|
||||
napi_closing,
|
||||
napi_bigint_expected,
|
||||
napi_date_expected,
|
||||
napi_arraybuffer_expected,
|
||||
napi_detachable_arraybuffer_expected,
|
||||
napi_would_deadlock, // unused
|
||||
napi_no_external_buffers_allowed,
|
||||
napi_cannot_run_js,
|
||||
napi_ok,
|
||||
napi_invalid_arg,
|
||||
napi_object_expected,
|
||||
napi_string_expected,
|
||||
napi_name_expected,
|
||||
napi_function_expected,
|
||||
napi_number_expected,
|
||||
napi_boolean_expected,
|
||||
napi_array_expected,
|
||||
napi_generic_failure,
|
||||
napi_pending_exception,
|
||||
napi_cancelled,
|
||||
napi_escape_called_twice,
|
||||
napi_handle_scope_mismatch,
|
||||
napi_callback_scope_mismatch,
|
||||
napi_queue_full,
|
||||
napi_closing,
|
||||
napi_bigint_expected,
|
||||
napi_date_expected,
|
||||
napi_arraybuffer_expected,
|
||||
napi_detachable_arraybuffer_expected,
|
||||
napi_would_deadlock, // unused
|
||||
napi_no_external_buffers_allowed,
|
||||
napi_cannot_run_js,
|
||||
} napi_status;
|
||||
// Note: when adding a new enum value to `napi_status`, please also update
|
||||
// * `constexpr int last_status` in the definition of `napi_get_last_error_info()'
|
||||
@@ -101,55 +101,55 @@ typedef enum {
|
||||
// message explaining the error.
|
||||
|
||||
typedef napi_value (*napi_callback)(napi_env env, napi_callback_info info);
|
||||
typedef void (*napi_finalize)(napi_env env, void *finalize_data,
|
||||
void *finalize_hint);
|
||||
typedef void (*napi_finalize)(napi_env env, void* finalize_data,
|
||||
void* finalize_hint);
|
||||
|
||||
typedef struct {
|
||||
// One of utf8name or name should be NULL.
|
||||
const char *utf8name;
|
||||
napi_value name;
|
||||
// One of utf8name or name should be NULL.
|
||||
const char* utf8name;
|
||||
napi_value name;
|
||||
|
||||
napi_callback method;
|
||||
napi_callback getter;
|
||||
napi_callback setter;
|
||||
napi_value value;
|
||||
napi_callback method;
|
||||
napi_callback getter;
|
||||
napi_callback setter;
|
||||
napi_value value;
|
||||
|
||||
napi_property_attributes attributes;
|
||||
void *data;
|
||||
napi_property_attributes attributes;
|
||||
void* data;
|
||||
} napi_property_descriptor;
|
||||
|
||||
typedef struct {
|
||||
const char *error_message;
|
||||
void *engine_reserved;
|
||||
uint32_t engine_error_code;
|
||||
napi_status error_code;
|
||||
const char* error_message;
|
||||
void* engine_reserved;
|
||||
uint32_t engine_error_code;
|
||||
napi_status error_code;
|
||||
} napi_extended_error_info;
|
||||
|
||||
#if NAPI_VERSION >= 6
|
||||
typedef enum {
|
||||
napi_key_include_prototypes,
|
||||
napi_key_own_only
|
||||
napi_key_include_prototypes,
|
||||
napi_key_own_only
|
||||
} napi_key_collection_mode;
|
||||
|
||||
typedef enum {
|
||||
napi_key_all_properties = 0,
|
||||
napi_key_writable = 1,
|
||||
napi_key_enumerable = 1 << 1,
|
||||
napi_key_configurable = 1 << 2,
|
||||
napi_key_skip_strings = 1 << 3,
|
||||
napi_key_skip_symbols = 1 << 4
|
||||
napi_key_all_properties = 0,
|
||||
napi_key_writable = 1,
|
||||
napi_key_enumerable = 1 << 1,
|
||||
napi_key_configurable = 1 << 2,
|
||||
napi_key_skip_strings = 1 << 3,
|
||||
napi_key_skip_symbols = 1 << 4
|
||||
} napi_key_filter;
|
||||
|
||||
typedef enum {
|
||||
napi_key_keep_numbers,
|
||||
napi_key_numbers_to_strings
|
||||
napi_key_keep_numbers,
|
||||
napi_key_numbers_to_strings
|
||||
} napi_key_conversion;
|
||||
#endif // NAPI_VERSION >= 6
|
||||
|
||||
#if NAPI_VERSION >= 8
|
||||
typedef struct {
|
||||
uint64_t lower;
|
||||
uint64_t upper;
|
||||
uint64_t lower;
|
||||
uint64_t upper;
|
||||
} napi_type_tag;
|
||||
#endif // NAPI_VERSION >= 8
|
||||
|
||||
|
||||
@@ -55,9 +55,19 @@ pub const NapiEnv = opaque {
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn ref(self: *NapiEnv) void {
|
||||
NapiEnv__ref(self);
|
||||
}
|
||||
|
||||
pub fn deref(self: *NapiEnv) void {
|
||||
NapiEnv__deref(self);
|
||||
}
|
||||
|
||||
extern fn NapiEnv__globalObject(*NapiEnv) *jsc.JSGlobalObject;
|
||||
extern fn NapiEnv__getAndClearPendingException(*NapiEnv, *JSValue) bool;
|
||||
extern fn napi_internal_get_version(*NapiEnv) u32;
|
||||
extern fn NapiEnv__deref(*NapiEnv) void;
|
||||
extern fn NapiEnv__ref(*NapiEnv) void;
|
||||
};
|
||||
|
||||
fn envIsNull() napi_status {
|
||||
@@ -1660,6 +1670,7 @@ pub const ThreadSafeFunction = struct {
|
||||
|
||||
this.callback.deinit();
|
||||
this.queue.deinit();
|
||||
this.env.deref();
|
||||
bun.destroy(this);
|
||||
}
|
||||
|
||||
@@ -1757,6 +1768,7 @@ pub export fn napi_create_threadsafe_function(
|
||||
// nodejs by default keeps the event loop alive until the thread-safe function is unref'd
|
||||
function.ref();
|
||||
function.tracker.didSchedule(vm.global);
|
||||
function.env.ref();
|
||||
|
||||
result.* = function;
|
||||
return env.ok();
|
||||
|
||||
Reference in New Issue
Block a user