#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 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&); 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 New( Isolate* isolate, FunctionCallback callback = nullptr, Local data = Local(), Local signature = Local(), 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 GetFunction(Local context); static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject); 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_clientSubspaceForFunctionTemplate.get(); }, [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForFunctionTemplate = std::forward(space); }, [](auto& spaces) { return spaces.m_subspaceForFunctionTemplate.get(); }, [](auto& spaces, auto&& space) { spaces.m_subspaceForFunctionTemplate = std::forward(space); }); } DECLARE_INFO; DECLARE_VISIT_CHILDREN; friend class Function; FunctionCallback callback() const { return __internals.callback; } private: class Internals { private: FunctionCallback callback; JSC::WriteBarrier 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(this)->localToObjectPointer(); } const FunctionTemplate* localToObjectPointer() const { return reinterpret_cast(this)->localToObjectPointer(); } // only use from functions called on Local 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 }; }