diff options
Diffstat (limited to 'src/bun.js/bindings/napi.h')
-rw-r--r-- | src/bun.js/bindings/napi.h | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/src/bun.js/bindings/napi.h b/src/bun.js/bindings/napi.h new file mode 100644 index 000000000..754c34ec4 --- /dev/null +++ b/src/bun.js/bindings/napi.h @@ -0,0 +1,242 @@ +#pragma once + +namespace Zig { +class GlobalObject; +} + +#include "root.h" +#include "JavaScriptCore/JSFunction.h" +#include "JavaScriptCore/VM.h" + +#include "headers-handwritten.h" +#include "BunClientData.h" +#include "JavaScriptCore/CallFrame.h" +#include "js_native_api_types.h" +#include "JavaScriptCore/JSWeakValue.h" +#include "JSFFIFunction.h" + +namespace JSC { +class JSGlobalObject; +class JSSourceCode; +} + +namespace Napi { +JSC::SourceCode generateSourceCode(WTF::String keyString, JSC::VM& vm, JSC::JSObject* object, JSC::JSGlobalObject* globalObject); +} + +namespace Zig { + +using namespace JSC; + +static inline JSValue toJS(napi_value val) +{ + return JSC::JSValue::decode(reinterpret_cast<JSC::EncodedJSValue>(val)); +} + +static inline Zig::GlobalObject* toJS(napi_env val) +{ + return reinterpret_cast<Zig::GlobalObject*>(val); +} + +static inline napi_value toNapi(JSC::EncodedJSValue val) +{ + return reinterpret_cast<napi_value>(val); +} + +static inline napi_value toNapi(JSC::JSValue val) +{ + return toNapi(JSC::JSValue::encode(val)); +} + +static inline napi_env toNapi(JSC::JSGlobalObject* val) +{ + return reinterpret_cast<napi_env>(val); +} + +class NapiFinalizer { +public: + void* finalize_hint = nullptr; + napi_finalize finalize_cb; + + void call(JSC::JSGlobalObject* globalObject, void* data); +}; + +class NapiRef : public RefCounted<NapiRef>, public CanMakeWeakPtr<NapiRef> { + WTF_MAKE_FAST_ALLOCATED; + +public: + void ref(); + void unref(); + void clear(); + + NapiRef(JSC::JSGlobalObject* global, uint32_t count) + { + globalObject = JSC::Weak<JSC::JSGlobalObject>(global); + strongRef = {}; + weakValueRef.clear(); + refCount = count; + } + + JSC::JSValue value() const + { + if (refCount == 0) { + if (!weakValueRef.isSet()) { + return JSC::JSValue {}; + } + + if (weakValueRef.isString()) { + return JSC::JSValue(weakValueRef.string()); + } + + if (weakValueRef.isObject()) { + return JSC::JSValue(weakValueRef.object()); + } + + return weakValueRef.primitive(); + } + + return strongRef.get(); + } + + ~NapiRef() + { + if (this->refCount > 0) { + this->refCount = 1; + this->unref(); + } + } + + JSC::Weak<JSC::JSGlobalObject> globalObject; + JSC::JSWeakValue weakValueRef; + JSC::Strong<JSC::Unknown> strongRef; + NapiFinalizer finalizer; + void* data = nullptr; + uint32_t refCount = 0; +}; + +static inline napi_ref toNapi(NapiRef* val) +{ + return reinterpret_cast<napi_ref>(val); +} + +class NapiClass final : public JSC::JSFunction { +public: + using Base = JSFunction; + + static constexpr unsigned StructureFlags = Base::StructureFlags; + static constexpr bool needsDestruction = false; + static void destroy(JSCell* cell) + { + static_cast<NapiClass*>(cell)->NapiClass::~NapiClass(); + } + + template<typename, SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return WebCore::subspaceForImpl<NapiClass, WebCore::UseCustomHeapCellType::No>( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForNapiClass.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForNapiClass = WTFMove(space); }, + [](auto& spaces) { return spaces.m_subspaceForNapiClass.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForNapiClass = WTFMove(space); }); + } + + DECLARE_EXPORT_INFO; + + JS_EXPORT_PRIVATE static NapiClass* create(VM&, Zig::GlobalObject*, const char* utf8name, + size_t length, + napi_callback constructor, + void* data, + size_t property_count, + const napi_property_descriptor* properties); + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + ASSERT(globalObject); + return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info()); + } + + static CallData getConstructData(JSCell* cell); + + FFIFunction constructor() + { + return m_constructor; + } + + void* dataPtr = nullptr; + FFIFunction m_constructor = nullptr; + +private: + NapiClass(VM& vm, NativeExecutable* executable, JSC::JSGlobalObject* global, Structure* structure) + : Base(vm, executable, global, structure) + { + } + void finishCreation(VM&, NativeExecutable*, unsigned length, const String& name, napi_callback constructor, + void* data, + size_t property_count, + const napi_property_descriptor* properties); + + DECLARE_VISIT_CHILDREN; +}; + +class NapiPrototype : public JSC::JSDestructibleObject { +public: + using Base = JSC::JSDestructibleObject; + + static constexpr unsigned StructureFlags = Base::StructureFlags; + static constexpr bool needsDestruction = true; + + template<typename CellType, SubspaceAccess> + static CompleteSubspace* subspaceFor(VM& vm) + { + return &vm.destructibleObjectSpace(); + } + + DECLARE_INFO; + + static NapiPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) + { + NapiPrototype* footprint = new (NotNull, allocateCell<NapiPrototype>(vm)) NapiPrototype(vm, structure); + footprint->finishCreation(vm); + return footprint; + } + + static NapiPrototype* create(VM& vm, JSGlobalObject* globalObject) + { + Structure* structure = createStructure(vm, globalObject, globalObject->objectPrototype()); + return create(vm, globalObject, structure); + } + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + ASSERT(globalObject); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + NapiPrototype* subclass(JSC::JSObject* newTarget) + { + auto& vm = this->vm(); + auto* structure = InternalFunction::createSubclassStructure(globalObject(), + newTarget, + this->structure()); + NapiPrototype* footprint = new (NotNull, allocateCell<NapiPrototype>(vm)) NapiPrototype(vm, structure); + footprint->finishCreation(vm); + return footprint; + } + + NapiRef* napiRef = nullptr; + +private: + NapiPrototype(VM& vm, Structure* structure) + : Base(vm, structure) + { + } +}; + +static inline NapiRef* toJS(napi_ref val) +{ + return reinterpret_cast<NapiRef*>(val); +} + +}
\ No newline at end of file |