#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 "WebCoreJSBuiltinInternals.h" #include "JavaScriptCore/CallFrame.h" #include "js_native_api_types.h" #include "JavaScriptCore/JSWeakValue.h" #include "JSFFIFunction.h" namespace JSC { class JSGlobalObject; } namespace Zig { using namespace JSC; static inline JSValue toJS(napi_value val) { return JSC::JSValue::decode(reinterpret_cast(val)); } static inline Zig::GlobalObject* toJS(napi_env val) { return reinterpret_cast(val); } static inline napi_value toNapi(JSC::EncodedJSValue val) { return reinterpret_cast(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(val); } class NapiFinalizer { public: void* finalize_hint = nullptr; napi_finalize finalize_cb; void call(JSC::JSGlobalObject* globalObject, void* data); }; class NapiRef : public RefCounted, public CanMakeWeakPtr { WTF_MAKE_FAST_ALLOCATED; public: void ref(); void unref(); void clear(); NapiRef(JSC::JSGlobalObject* global, uint32_t count) { globalObject = JSC::Weak(global); strongRef = {}; weakValueRef.clear(); refCount = count; } JSC::JSValue value() const { if (refCount == 0) { if (!weakValueRef.isSet()) { return JSC::JSValue {}; } if (weakValue.isString()) { return JSC::JSValue(weakValue.string()); } if (weakValue.isObject()) { return JSC::JSValue(weakValue.object()); } return weakValue.primitive(); } return strongRef.get(); } ~NapiRef() { if (this->refCount > 0) { this->refCount = 1; this->unref(); } } JSC::Weak globalObject; JSC::JSWeakValue weakValueRef; JSC::Strong strongRef; NapiFinalizer finalizer; uint32_t refCount = 0; }; static inline napi_ref toNapi(NapiRef* val) { return reinterpret_cast(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(cell)->NapiClass::~NapiClass(); } template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { if constexpr (mode == JSC::SubspaceAccess::Concurrently) return nullptr; return WebCore::subspaceForImpl( 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; }; static inline NapiRef* toJS(napi_ref val) { return reinterpret_cast(val); } }