/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/node_ffi.h
212 строк
8 KB
Trivikram Kamat
ffi: reuse the callable created per symbol
10 авг 2026, 02:18
10 авг 2026, 02:18
bf2f995
Код
Авторство
О чём код?
#pragma once #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "base_object.h" #include "ffi.h" #include "ffi/fast.h" #include "uv.h" #include <cstdint> #include <memory> #include <string> #include <thread> #include <unordered_map> #include <vector> // libffi only accelerates reusable call plans on x86-64 System V. Other // targets implement the API by calling ffi_call(), which adds no benefit. #if defined(FFI_VERSION_NUMBER) && FFI_VERSION_NUMBER >= 30700 && \ defined(__x86_64__) && !defined(__ILP32__) && !defined(X86_WIN64) && \ !defined(_WIN32) #define NODE_FFI_HAS_FAST_CALL_PLAN 1 #endif namespace node::ffi { class DynamicLibrary; struct FFIFunction; struct FFIFunction { FFIFunction() = default; FFIFunction(const FFIFunction&) = delete; FFIFunction& operator=(const FFIFunction&) = delete; FFIFunction(FFIFunction&&) = delete; FFIFunction& operator=(FFIFunction&&) = delete; bool closed = false; void* ptr = nullptr; ffi_cif cif = {}; std::vector<ffi_type*> args; ffi_type* return_type = nullptr; std::vector<std::string> arg_type_names; std::string return_type_name; #if defined(NODE_FFI_HAS_FAST_CALL_PLAN) // The plan borrows cif, so it must remain uniquely owned by this instance. std::unique_ptr<ffi_call_plan, decltype(&ffi_call_plan_free)> call_plan{ nullptr, ffi_call_plan_free}; #endif void Invoke(void* result, void** values); }; class FFIFunctionInfo final : public BaseObject { public: enum InternalFields { kLibrary = BaseObject::kInternalFieldCount, kInternalFieldCount }; FFIFunctionInfo(Environment* env, v8::Local<v8::Object> object, std::shared_ptr<FFIFunction> fn, DynamicLibrary* library); void MemoryInfo(MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(FFIFunctionInfo) SET_SELF_SIZE(FFIFunctionInfo) static BaseObjectPtr<FFIFunctionInfo> Create(Environment* env, std::shared_ptr<FFIFunction> fn, DynamicLibrary* library); static v8::Local<v8::FunctionTemplate> GetConstructorTemplate( IsolateData* isolate_data); private: std::shared_ptr<FFIFunction> fn; std::shared_ptr<v8::BackingStore> sb_backing; std::unique_ptr<FastFFIMetadata> fast_metadata; std::unique_ptr<FastFFIMetadata> fast_buffer_metadata; friend class DynamicLibrary; }; struct FFICallback { DynamicLibrary* owner; Environment* env; std::thread::id thread_id; v8::Global<v8::Function> fn; ffi_closure* closure; void* ptr; ffi_cif cif; std::vector<ffi_type*> args; ffi_type* return_type; ~FFICallback() { if (!fn.IsEmpty()) { fn.Reset(); } if (closure != nullptr) { ffi_closure_free(closure); closure = nullptr; } } }; struct ResolvedFunction { std::string name; std::shared_ptr<FFIFunction> fn; bool should_cache_symbol; bool should_cache_function; }; class DynamicLibrary : public BaseObject { public: DynamicLibrary(Environment* env, v8::Local<v8::Object> object); ~DynamicLibrary() override; void MemoryInfo(MemoryTracker* tracker) const override; static v8::Local<v8::FunctionTemplate> GetConstructorTemplate( Environment* env); static void New(const v8::FunctionCallbackInfo<v8::Value>& args); static void Close(const v8::FunctionCallbackInfo<v8::Value>& args); static void InvokeFunction(const v8::FunctionCallbackInfo<v8::Value>& args); static void InvokeFunctionSB(const v8::FunctionCallbackInfo<v8::Value>& args); static void InvokeCallback(ffi_cif* cif, void* ret, void** args, void* user_data); static void GetPath(const v8::FunctionCallbackInfo<v8::Value>& args); static void GetFunction(const v8::FunctionCallbackInfo<v8::Value>& args); static void GetFunctions(const v8::FunctionCallbackInfo<v8::Value>& args); static void GetSymbol(const v8::FunctionCallbackInfo<v8::Value>& args); static void GetSymbols(const v8::FunctionCallbackInfo<v8::Value>& args); static void RegisterCallback(const v8::FunctionCallbackInfo<v8::Value>& args); static void UnregisterCallback( const v8::FunctionCallbackInfo<v8::Value>& args); static void RefCallback(const v8::FunctionCallbackInfo<v8::Value>& args); static void UnrefCallback(const v8::FunctionCallbackInfo<v8::Value>& args); SET_MEMORY_INFO_NAME(DynamicLibrary) SET_SELF_SIZE(DynamicLibrary) private: void Close(); v8::Maybe<void*> ResolveSymbol(Environment* env, const std::string& name); struct PreparedFunction { std::shared_ptr<FFIFunction> fn; bool should_cache_symbol; bool should_cache_function; }; v8::Maybe<PreparedFunction> PrepareFunction(Environment* env, const std::string& name, v8::Local<v8::Object> signature); v8::MaybeLocal<v8::Function> CreateFunction( Environment* env, const std::string& name, const std::shared_ptr<FFIFunction>& fn); static void CleanupFunctionInfo( const v8::WeakCallbackInfo<FFIFunctionInfo>& data); bool is_closed() const; uv_lib_t lib_ = {}; std::string path_; std::unordered_map<std::string, void*> symbols_; std::unordered_map<std::string, std::shared_ptr<FFIFunction>> functions_; // Callables created for `functions_`, so repeated resolution of the same // symbol reuses one wrapper instead of emitting another trampoline. The // handles are weak: an entry disappears once user code drops the wrapper, // which keeps the map from rooting the library through the wrapper's // FFIFunctionInfo. std::unordered_map<std::string, v8::Global<v8::Function>> function_wrappers_; std::unordered_map<void*, std::unique_ptr<FFICallback>> callbacks_; }; void GetInt8(const v8::FunctionCallbackInfo<v8::Value>& args); void GetUint8(const v8::FunctionCallbackInfo<v8::Value>& args); void GetInt16(const v8::FunctionCallbackInfo<v8::Value>& args); void GetUint16(const v8::FunctionCallbackInfo<v8::Value>& args); void GetInt32(const v8::FunctionCallbackInfo<v8::Value>& args); void GetUint32(const v8::FunctionCallbackInfo<v8::Value>& args); void GetInt64(const v8::FunctionCallbackInfo<v8::Value>& args); void GetUint64(const v8::FunctionCallbackInfo<v8::Value>& args); void GetFloat32(const v8::FunctionCallbackInfo<v8::Value>& args); void GetFloat64(const v8::FunctionCallbackInfo<v8::Value>& args); void SetInt8(const v8::FunctionCallbackInfo<v8::Value>& args); void SetUint8(const v8::FunctionCallbackInfo<v8::Value>& args); void SetInt16(const v8::FunctionCallbackInfo<v8::Value>& args); void SetUint16(const v8::FunctionCallbackInfo<v8::Value>& args); void SetInt32(const v8::FunctionCallbackInfo<v8::Value>& args); void SetUint32(const v8::FunctionCallbackInfo<v8::Value>& args); void SetInt64(const v8::FunctionCallbackInfo<v8::Value>& args); void SetUint64(const v8::FunctionCallbackInfo<v8::Value>& args); void SetFloat32(const v8::FunctionCallbackInfo<v8::Value>& args); void SetFloat64(const v8::FunctionCallbackInfo<v8::Value>& args); void ToString(const v8::FunctionCallbackInfo<v8::Value>& args); void ToBuffer(const v8::FunctionCallbackInfo<v8::Value>& args); void ToArrayBuffer(const v8::FunctionCallbackInfo<v8::Value>& args); void ExportBytes(const v8::FunctionCallbackInfo<v8::Value>& args); void GetRawPointer(const v8::FunctionCallbackInfo<v8::Value>& args); void GetCurrentEventLoop(const v8::FunctionCallbackInfo<v8::Value>& args); } // namespace node::ffi #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS