@@ -319,118 +319,85 @@ MaybeLocal<Function> DynamicLibrary::CreateFunction(
319319 if (fc_ok) {
320320 auto bundle = node::ffi::fastcall::BuildCFunctionInfo (*fn);
321321 {
322- auto stub = node::ffi::fastcall::EmitForwarder (
323- isolate, fn->ptr , bundle.arg_classes , bundle.result_class );
324- if (!stub.has_value ()) {
325- // Warn at most once per process: a single FFI app may register hundreds
326- // of functions, and the failure cause (mprotect / SELinux / hardened
327- // runtime) is the same for every call. Repeated warnings would flood
328- // logs without adding signal.
329- static std::atomic<bool > warned{false };
330- if (!warned.exchange (true , std::memory_order_acq_rel)) {
331- if (ProcessEmitWarning (env,
332- " FFI fast-call stub emission failed for an eligible "
333- " signature; falling back to libffi for this and possibly "
334- " future calls. This usually indicates a JIT memory or "
335- " permission issue (mprotect/SELinux/hardened runtime)." )
336- .IsNothing ()) {
337- return MaybeLocal<Function>();
338- }
322+ // Register the dlsym'd target function pointer directly with V8 as the
323+ // C function. With CFunctionInfo built using HasReceiver=kNo, V8's fast-
324+ // call lowering omits the JS receiver from the C call — so no receiver-
325+ // strip stub is needed. The target's plain C signature matches the
326+ // CFunctionInfo exactly.
327+ v8::CFunction cfun (fn->ptr , bundle.info );
328+ v8::Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New (
329+ isolate,
330+ DynamicLibrary::InvokeFunction,
331+ data,
332+ v8::Local<v8::Signature>(),
333+ static_cast <int >(fn->args .size ()),
334+ v8::ConstructorBehavior::kThrow ,
335+ v8::SideEffectType::kHasSideEffect ,
336+ &cfun);
337+ v8::Local<v8::Function> fc_fn;
338+ if (tmpl->GetFunction (context).ToLocal (&fc_fn)) {
339+ bool metadata_ok = true ;
340+
341+ v8::Local<v8::ArrayBuffer> alive_ab = AliveBuffer (isolate);
342+ if (!fc_fn->DefineOwnProperty (
343+ context, env->ffi_fastcall_alive_symbol (),
344+ alive_ab, internal_attrs)
345+ .FromMaybe (false )) {
346+ metadata_ok = false ;
339347 }
340- // fall through to libffi path
341- } else {
342- v8::CFunction cfun (stub->entry , bundle.info );
343- v8::Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New (
344- isolate,
345- DynamicLibrary::InvokeFunction,
346- data,
347- v8::Local<v8::Signature>(),
348- static_cast <int >(fn->args .size ()),
349- v8::ConstructorBehavior::kThrow ,
350- v8::SideEffectType::kHasSideEffect ,
351- &cfun);
352- v8::Local<v8::Function> fc_fn;
353- if (tmpl->GetFunction (context).ToLocal (&fc_fn)) {
354- // Build all V8 values before touching `info` fields, so that on
355- // any failure we can free the stub and return cleanly without
356- // leaking JIT memory.
357- bool metadata_ok = true ;
358-
359- // Alive ArrayBuffer.
360- v8::Local<v8::ArrayBuffer> alive_ab = AliveBuffer (isolate);
361- if (!fc_fn->DefineOwnProperty (
362- context, env->ffi_fastcall_alive_symbol (),
363- alive_ab, internal_attrs)
364- .FromMaybe (false )) {
365- metadata_ok = false ;
366- }
367-
368- // Build the slow-invoke v8::Function for the wrapper's pointer
369- // fallback path.
370- Local<Function> slow_fn;
371- if (metadata_ok &&
372- !Function::New (context, DynamicLibrary::InvokeFunction, data)
373- .ToLocal (&slow_fn)) {
374- metadata_ok = false ;
375- }
376- if (metadata_ok &&
377- !fc_fn->DefineOwnProperty (
378- context, env->ffi_fastcall_invoke_slow_symbol (),
379- slow_fn, internal_attrs)
380- .FromMaybe (false )) {
381- metadata_ok = false ;
382- }
383-
384- // Attach params and result type names.
385- Local<Value> params_arr;
386- if (metadata_ok &&
387- !ToV8Value (context, fn->arg_type_names , isolate)
388- .ToLocal (¶ms_arr)) {
389- metadata_ok = false ;
390- }
391- if (metadata_ok &&
392- !fc_fn->DefineOwnProperty (
393- context, env->ffi_fastcall_params_symbol (),
394- params_arr, internal_attrs)
395- .FromMaybe (false )) {
396- metadata_ok = false ;
397- }
398- Local<Value> result_str;
399- if (metadata_ok &&
400- !ToV8Value (context, fn->return_type_name , isolate)
401- .ToLocal (&result_str)) {
402- metadata_ok = false ;
403- }
404- if (metadata_ok &&
405- !fc_fn->DefineOwnProperty (
406- context, env->ffi_fastcall_result_symbol (),
407- result_str, internal_attrs)
408- .FromMaybe (false )) {
409- metadata_ok = false ;
410- }
411-
412- if (!metadata_ok) {
413- // Free the stub to avoid a JIT memory leak.
414- node::ffi::fastcall::JitMemory::Get (isolate)
415- ->Free (*stub);
416- return MaybeLocal<Function>();
417- }
418-
419- // All metadata attached successfully. Populate fast-call state.
420- info->fast = std::make_unique<FastCallState>(
421- isolate, slow_fn, stub->entry , stub->alloc_size ,
422- std::make_unique<node::ffi::fastcall::CFunctionInfoBundle>(
423- std::move (bundle)));
424- ret = fc_fn;
425- } else {
426- // Template-to-function failed (V8 has a pending exception). Free the
427- // stub since we won't use it; mirror the metadata-fail path and
428- // propagate the empty MaybeLocal so the caller surfaces the V8
429- // exception.
430- node::ffi::fastcall::JitMemory::Get (isolate)
431- ->Free (*stub);
348+
349+ Local<Function> slow_fn;
350+ if (metadata_ok &&
351+ !Function::New (context, DynamicLibrary::InvokeFunction, data)
352+ .ToLocal (&slow_fn)) {
353+ metadata_ok = false ;
354+ }
355+ if (metadata_ok &&
356+ !fc_fn->DefineOwnProperty (
357+ context, env->ffi_fastcall_invoke_slow_symbol (),
358+ slow_fn, internal_attrs)
359+ .FromMaybe (false )) {
360+ metadata_ok = false ;
361+ }
362+
363+ Local<Value> params_arr;
364+ if (metadata_ok &&
365+ !ToV8Value (context, fn->arg_type_names , isolate)
366+ .ToLocal (¶ms_arr)) {
367+ metadata_ok = false ;
368+ }
369+ if (metadata_ok &&
370+ !fc_fn->DefineOwnProperty (
371+ context, env->ffi_fastcall_params_symbol (),
372+ params_arr, internal_attrs)
373+ .FromMaybe (false )) {
374+ metadata_ok = false ;
375+ }
376+ Local<Value> result_str;
377+ if (metadata_ok &&
378+ !ToV8Value (context, fn->return_type_name , isolate)
379+ .ToLocal (&result_str)) {
380+ metadata_ok = false ;
381+ }
382+ if (metadata_ok &&
383+ !fc_fn->DefineOwnProperty (
384+ context, env->ffi_fastcall_result_symbol (),
385+ result_str, internal_attrs)
386+ .FromMaybe (false )) {
387+ metadata_ok = false ;
388+ }
389+
390+ if (!metadata_ok) {
432391 return MaybeLocal<Function>();
433392 }
393+
394+ info->fast = std::make_unique<FastCallState>(
395+ isolate, slow_fn, /* stub=*/ nullptr , /* alloc_size=*/ 0 ,
396+ std::make_unique<node::ffi::fastcall::CFunctionInfoBundle>(
397+ std::move (bundle)));
398+ ret = fc_fn;
399+ } else {
400+ return MaybeLocal<Function>();
434401 }
435402 }
436403 }
0 commit comments