@@ -330,37 +330,29 @@ bool IsFastLibraryGuardSupported() {
330330#endif
331331}
332332
333- std::unique_ptr<FastFFIMetadata> CreateFastFFIMetadata (const FFIFunction& fn,
334- const bool * closed,
335- v8::Isolate* isolate) {
336- // Bail early if executable memory allocation doesn't work on this process
337- // (missing MAP_JIT entitlement, hardened runtime, SELinux execmem, etc.).
338- // The self-test runs once and caches the result.
339- if (!IsJitMemorySupported ()) {
340- return nullptr ;
341- }
342-
333+ v8::Maybe<std::unique_ptr<FastFFIMetadata>> CreateFastFFIMetadata (
334+ const FFIFunction& fn, const bool * closed, v8::Isolate* isolate) {
343335 // Check signature-level eligibility (type checks, register caps, platform
344- // support). Returning nullptr here lets the caller fall back to SharedBuffer
336+ // support). Null metadata lets the caller fall back to SharedBuffer
345337 // or the generic libffi path.
346338 const char * eligibility_reason;
347339 if (!IsFastCallEligible (fn, &eligibility_reason)) {
348- return nullptr ;
340+ return v8::Just (std::unique_ptr<FastFFIMetadata>()) ;
349341 }
350342
351- // Reject unsupported result types first. Returning nullptr means the caller
343+ // Reject unsupported result types first. Null metadata means the caller
352344 // can still fall back to SharedBuffer or the generic libffi path.
353345 FastFFIType result;
354346 if (!FastScalarTypeFromName (fn.return_type_name , &result)) {
355- return nullptr ;
347+ return v8::Just (std::unique_ptr<FastFFIMetadata>()) ;
356348 }
357349 if (fn.args .size () != fn.arg_type_names .size ()) {
358- return nullptr ;
350+ return v8::Just (std::unique_ptr<FastFFIMetadata>()) ;
359351 }
360352 // Keep the initial Fast API implementation bounded to signatures V8 and the
361353 // platform trampolines can describe without stack argument support.
362354 if (fn.arg_type_names .size () > 8 ) {
363- return nullptr ;
355+ return v8::Just (std::unique_ptr<FastFFIMetadata>()) ;
364356 }
365357
366358 std::vector<FastFFIType> args;
@@ -373,25 +365,35 @@ std::unique_ptr<FastFFIMetadata> CreateFastFFIMetadata(const FFIFunction& fn,
373365 for (const std::string& name : fn.arg_type_names ) {
374366 FastFFIType type;
375367 if (!FastArgTypeFromName (name, &type)) {
376- return nullptr ;
368+ return v8::Just (std::unique_ptr<FastFFIMetadata>()) ;
377369 }
378370 if (type == FastFFIType::kVoid ) {
379- return nullptr ;
371+ return v8::Just (std::unique_ptr<FastFFIMetadata>()) ;
380372 }
381373 needs_bigint = needs_bigint || NeedsBigIntRepresentation (type);
382374 needs_callback_options =
383375 needs_callback_options || type == FastFFIType::kBuffer ;
384376 args.push_back (type);
385377 }
386378
379+ // Check RX memory only after signature and platform eligibility, so ordinary
380+ // unsupported signatures can still use the non-generated invocation paths.
381+ if (!IsJitMemorySupported ()) {
382+ THROW_ERR_RX_MEMORY_NOT_SUPPORTED (
383+ isolate,
384+ " Executable memory is not supported in this environment, "
385+ " but is required for FFI Fast API calls" );
386+ return v8::Nothing<std::unique_ptr<FastFFIMetadata>>();
387+ }
388+
387389 auto metadata = std::make_unique<FastFFIMetadata>();
388390 // The platform-specific trampoline is the executable entrypoint V8 calls.
389391 // If the platform rejects the signature, the whole fast metadata object is
390392 // discarded and the caller chooses another invocation path.
391393 FastFFITrampolineConfig config{fn.ptr , closed, isolate};
392394 if (!node_ffi_create_fast_trampoline (
393395 config, args.data (), args.size (), result, &metadata->trampoline )) {
394- return nullptr ;
396+ return v8::Just (std::unique_ptr<FastFFIMetadata>()) ;
395397 }
396398
397399 metadata->arg_info .reserve (args.size () + 1 );
@@ -418,7 +420,7 @@ std::unique_ptr<FastFFIMetadata> CreateFastFFIMetadata(const FFIFunction& fn,
418420 metadata->c_function =
419421 v8::CFunction (metadata->trampoline .code , metadata->c_function_info .get ());
420422 metadata->guards_library = guards_library;
421- return metadata;
423+ return v8::Just ( std::move ( metadata)) ;
422424}
423425
424426} // namespace node::ffi
0 commit comments