From ea20bebcb876a7f506838c26149a0dce816b19c6 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sat, 9 Jul 2022 18:41:07 +0530 Subject: [PATCH] fix(ext/ffi): allow opting out of fast ffi calls (#15131) --- cli/dts/lib.deno.unstable.d.ts | 2 ++ ext/ffi/lib.rs | 14 +++++++++++++- test_ffi/tests/ffi_types.ts | 2 +- test_ffi/tests/test.js | 6 +++++- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts index d82e07be09..2b4e1015a0 100644 --- a/cli/dts/lib.deno.unstable.d.ts +++ b/cli/dts/lib.deno.unstable.d.ts @@ -430,6 +430,8 @@ declare namespace Deno { result: Result; /** When true, function calls will run on a dedicated blocking thread and will return a Promise resolving to the `result`. */ nonblocking?: NonBlocking; + /** When true, function calls can safely callback into JS or trigger a GC event. Default is `false`. */ + callback?: boolean; } export interface ForeignStatic { diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs index d998c81383..a5a1567275 100644 --- a/ext/ffi/lib.rs +++ b/ext/ffi/lib.rs @@ -72,6 +72,7 @@ struct Symbol { ptr: libffi::middle::CodePtr, parameter_types: Vec, result_type: NativeType, + can_callback: bool, } #[allow(clippy::non_send_fields_in_send_ty)] @@ -433,6 +434,13 @@ struct ForeignFunction { result: NativeType, #[serde(rename = "nonblocking")] non_blocking: Option, + #[serde(rename = "callback")] + #[serde(default = "default_callback")] + callback: bool, +} + +fn default_callback() -> bool { + false } // ForeignStatic's name and type fields are read and used by @@ -599,6 +607,7 @@ where ptr, parameter_types: foreign_fn.parameters, result_type: foreign_fn.result, + can_callback: foreign_fn.callback, }); resource.symbols.insert(symbol_key, sym.clone()); @@ -689,7 +698,8 @@ fn make_sync_fn<'s>( ) -> v8::Local<'s, v8::Function> { let mut fast_ffi_templ = None; - if !sym.parameter_types.iter().any(|t| !is_fast_api(*t)) + if !sym.can_callback + && !sym.parameter_types.iter().any(|t| !is_fast_api(*t)) && is_fast_api(sym.result_type) { let mut args = sym @@ -941,6 +951,7 @@ where result_type, cif, ptr: fun_ptr, + .. } = symbol; let mut ffi_args: Vec = Vec::with_capacity(parameter_types.len()); @@ -1814,6 +1825,7 @@ fn op_ffi_call_nonblocking<'scope>( ptr, parameter_types, result_type, + .. } = symbol.clone(); ffi_call(call_args, &cif, ptr, ¶meter_types, result_type) }); diff --git a/test_ffi/tests/ffi_types.ts b/test_ffi/tests/ffi_types.ts index dde08155d1..172c429e84 100644 --- a/test_ffi/tests/ffi_types.ts +++ b/test_ffi/tests/ffi_types.ts @@ -5,7 +5,7 @@ const remote = Deno.dlopen( "dummy_lib.so", { - method1: { parameters: ["usize", "usize"], result: "void" }, + method1: { parameters: ["usize", "usize"], result: "void", callback: true }, method2: { parameters: [], result: "void" }, method3: { parameters: ["usize"], result: "void" }, method4: { parameters: ["isize"], result: "void" }, diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js index af2f522a68..94c2069c0f 100644 --- a/test_ffi/tests/test.js +++ b/test_ffi/tests/test.js @@ -164,10 +164,12 @@ const dylib = Deno.dlopen(libPath, { call_stored_function: { parameters: [], result: "void", + callback: true, }, call_stored_function_2: { parameters: ["u8"], result: "void", + callback: true, }, // Statics "static_u32": { @@ -372,12 +374,14 @@ assertThrows( "hi", ); +const { call_stored_function } = dylib.symbols; + dylib.symbols.call_fn_ptr(ptr(logCallback)); dylib.symbols.call_fn_ptr_many_parameters(ptr(logManyParametersCallback)); dylib.symbols.call_fn_ptr_return_u8(ptr(returnU8Callback)); dylib.symbols.call_fn_ptr_return_buffer(ptr(returnBufferCallback)); dylib.symbols.store_function(ptr(logCallback)); -dylib.symbols.call_stored_function(); +call_stored_function(); dylib.symbols.store_function_2(ptr(add10Callback)); dylib.symbols.call_stored_function_2(20);