src/bun.js/bindings/v8/V8FunctionTemplate.h (115 lines of code) (raw):

#pragma once #include "v8.h" #include "V8Context.h" #include "V8Isolate.h" #include "V8Local.h" #include "V8MaybeLocal.h" #include "V8Value.h" #include "V8Signature.h" namespace v8 { class Function; struct ImplicitArgs { // v8-function-callback.h:168 void* holder; Isolate* isolate; Context* context; // overwritten by the callback TaggedPointer return_value; // holds the value passed for data in FunctionTemplate::New TaggedPointer target; void* new_target; }; // T = return value template<typename T> class FunctionCallbackInfo { // V8 treats this as an array of pointers ImplicitArgs* implicit_args; // index -1 is this TaggedPointer* values; int length; public: FunctionCallbackInfo(ImplicitArgs* implicit_args_, TaggedPointer* values_, int length_) : implicit_args(implicit_args_) , values(values_) , length(length_) { } }; using FunctionCallback = void (*)(const FunctionCallbackInfo<Value>&); enum class ConstructorBehavior { kThrow, kAllow, }; enum class SideEffectType { kHasSideEffect, kHasNoSideEffect, kHasSideEffectToReceiver, }; class CFunction { private: const void* address; const void* type_info; }; // If this inherited Template like it does in V8, the layout would be wrong for JSC HeapCell. // Inheritance shouldn't matter for the ABI. class FunctionTemplate : public JSC::InternalFunction { public: using Base = JSC::InternalFunction; BUN_EXPORT static Local<FunctionTemplate> New( Isolate* isolate, FunctionCallback callback = nullptr, Local<Value> data = Local<Value>(), Local<Signature> signature = Local<Signature>(), int length = 0, ConstructorBehavior behavior = ConstructorBehavior::kAllow, SideEffectType side_effect_type = SideEffectType::kHasSideEffect, const CFunction* c_function = nullptr, uint16_t instance_type = 0, uint16_t allowed_receiver_instance_type_range_start = 0, uint16_t allowed_receiver_instance_type_range_end = 0); BUN_EXPORT MaybeLocal<Function> GetFunction(Local<Context> context); static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject); template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { if constexpr (mode == JSC::SubspaceAccess::Concurrently) return nullptr; return WebCore::subspaceForImpl<FunctionTemplate, WebCore::UseCustomHeapCellType::No>( vm, [](auto& spaces) { return spaces.m_clientSubspaceForFunctionTemplate.get(); }, [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForFunctionTemplate = std::forward<decltype(space)>(space); }, [](auto& spaces) { return spaces.m_subspaceForFunctionTemplate.get(); }, [](auto& spaces, auto&& space) { spaces.m_subspaceForFunctionTemplate = std::forward<decltype(space)>(space); }); } DECLARE_INFO; DECLARE_VISIT_CHILDREN; friend class Function; FunctionCallback callback() const { return __internals.callback; } private: class Internals { private: FunctionCallback callback; JSC::WriteBarrier<JSC::Unknown> data; Internals(FunctionCallback callback_, JSC::VM& vm, FunctionTemplate* owner, JSC::JSValue data_) : callback(callback_) , data(vm, owner, data_) { } friend class FunctionTemplate; }; // only use from functions called directly on FunctionTemplate Internals __internals; FunctionTemplate* localToObjectPointer() { return reinterpret_cast<Data*>(this)->localToObjectPointer<FunctionTemplate>(); } const FunctionTemplate* localToObjectPointer() const { return reinterpret_cast<const Data*>(this)->localToObjectPointer<FunctionTemplate>(); } // only use from functions called on Local<FunctionTemplate> Internals& internals() { return localToObjectPointer()->__internals; } static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES functionCall(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame); FunctionTemplate(JSC::VM& vm, JSC::Structure* structure, FunctionCallback callback, JSC::JSValue data) : __internals(callback, vm, this, data) , Base(vm, structure, functionCall, JSC::callHostFunctionAsConstructor) { } // some kind of static trampoline }; }