From 3d6fa64f19e74924813ece5e5fbd53023342bac8 Mon Sep 17 00:00:00 2001 From: Aapo Alasuutari Date: Mon, 20 Jun 2022 14:06:04 +0300 Subject: feat(ext/ffi): Callbacks (#14663) This commit adds support for unstable FFI callbacks. A callback is registered using the `Deno.UnsafeCallback` API. The backing memory for the callback can be disposed of using `Deno.UnsafeCallback#close`. It is not safe to pass the callback after calling close. Callbacks from other than the isolate thread are not supported. Co-authored-by: Divy Srivastava Co-authored-by: Bert Belder --- cli/dts/lib.deno.unstable.d.ts | 94 +++++++++++++++++++++++++++++++++-- cli/tests/testdata/unstable_ffi_10.js | 2 +- cli/tests/testdata/unstable_ffi_11.js | 2 +- cli/tests/testdata/unstable_ffi_12.js | 2 +- cli/tests/testdata/unstable_ffi_13.js | 2 +- cli/tests/testdata/unstable_ffi_14.js | 2 +- cli/tests/testdata/unstable_ffi_15.js | 2 +- cli/tests/testdata/unstable_ffi_2.js | 13 ++--- cli/tests/testdata/unstable_ffi_3.js | 13 ++--- cli/tests/testdata/unstable_ffi_5.js | 2 +- cli/tests/testdata/unstable_ffi_6.js | 2 +- cli/tests/testdata/unstable_ffi_7.js | 2 +- cli/tests/testdata/unstable_ffi_8.js | 2 +- cli/tests/testdata/unstable_ffi_9.js | 2 +- 14 files changed, 110 insertions(+), 32 deletions(-) (limited to 'cli') diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts index 7ebd80422..3482d1c80 100644 --- a/cli/dts/lib.deno.unstable.d.ts +++ b/cli/dts/lib.deno.unstable.d.ts @@ -346,9 +346,14 @@ declare namespace Deno { | "f64" | "pointer"; + type NativeParameterType = + | NativeType + | NativeCallbackType; + /** A foreign function as defined by its parameter and result types */ export interface ForeignFunction< - Parameters extends readonly NativeType[] = readonly NativeType[], + Parameters extends readonly NativeParameterType[] = + readonly NativeParameterType[], Result extends NativeType = NativeType, NonBlocking extends boolean = boolean, > { @@ -391,11 +396,17 @@ declare namespace Deno { type StaticForeignFunctionParameter = T extends "void" ? void : T extends StaticNativeNumberType | StaticNativeBigIntType ? number | bigint - : T extends "pointer" ? Deno.UnsafePointer | Deno.TypedArray | null + : T extends "pointer" ? UnsafePointer | TypedArray | null + : T extends NativeCallbackType< + infer U extends readonly NativeType[], + infer V extends NativeParameterType + > ? UnsafeCallback | UnsafePointer | null : unknown; /** Infers a foreign function parameter list. */ - type StaticForeignFunctionParameters = [ + type StaticForeignFunctionParameters< + T extends readonly NativeParameterType[], + > = [ ...{ [K in keyof T]: StaticForeignFunctionParameter; }, @@ -513,6 +524,83 @@ declare namespace Deno { >; } + export interface UnsafeCallbackDefinition< + Parameters extends readonly NativeType[] = readonly NativeType[], + Result extends NativeParameterType = NativeParameterType, + > { + parameters: Parameters; + result: Result; + } + + interface NativeCallbackType< + Parameters extends readonly NativeType[] = readonly NativeType[], + Result extends NativeParameterType = NativeParameterType, + > { + readonly function: UnsafeCallbackDefinition; + } + + type UnsafeCallbackParameters = T extends [] + ? [] + : T extends + readonly [infer U extends NativeType, ...(infer V extends NativeType[])] + ? [ + UnsafeCallbackParameter, + ...UnsafeCallbackParameters, + ] + : never; + + type UnsafeCallbackParameter = T extends + StaticNativeBigIntType ? bigint + : T extends StaticNativeNumberType ? number + : T extends "pointer" ? UnsafePointer + : never; + + type UnsafeCallbackResult = T extends "void" + ? void + : T extends StaticNativeBigIntType ? number | bigint + : T extends StaticNativeNumberType ? number + : T extends "pointer" ? UnsafePointer | TypedArray | null + : T extends NativeCallbackType< + infer U extends readonly NativeType[], + infer V extends NativeParameterType + > ? UnsafeCallback | UnsafePointer | null + : never; + + type UnsafeCallbackFunction< + Parameters extends readonly NativeType[] = readonly NativeType[], + Result extends NativeParameterType = NativeParameterType, + > = Result extends NativeParameterType + ? Parameters extends readonly [] ? () => UnsafeCallbackResult + : Parameters extends readonly NativeType[] ? ( + ...args: UnsafeCallbackParameters + ) => UnsafeCallbackResult + : never + : never; + + /** + * **UNSTABLE**: Unsafe and new API, beware! + * + * An unsafe function pointer for passing JavaScript functions + * as C function pointers to ffi calls. + * + * The function pointer remains valid until the `close()` method is called. + */ + export class UnsafeCallback< + Parameters extends readonly NativeType[] = readonly NativeType[], + Result extends NativeParameterType = NativeParameterType, + > { + constructor( + definition: UnsafeCallbackDefinition, + callback: UnsafeCallbackFunction, + ); + + pointer: UnsafePointer; + definition: UnsafeCallbackDefinition; + callback: UnsafeCallbackFunction; + + close(): void; + } + /** A dynamic library resource */ export interface DynamicLibrary { /** All of the registered library along with functions for calling them */ diff --git a/cli/tests/testdata/unstable_ffi_10.js b/cli/tests/testdata/unstable_ffi_10.js index c7cafd3ea..e8fc9b3f0 100644 --- a/cli/tests/testdata/unstable_ffi_10.js +++ b/cli/tests/testdata/unstable_ffi_10.js @@ -1 +1 @@ -Deno.core.opSync("op_ffi_read_i16", [0, 0]); +Deno.core.opSync("op_ffi_read_i16", 0n); diff --git a/cli/tests/testdata/unstable_ffi_11.js b/cli/tests/testdata/unstable_ffi_11.js index 37bd75cc9..77c86109a 100644 --- a/cli/tests/testdata/unstable_ffi_11.js +++ b/cli/tests/testdata/unstable_ffi_11.js @@ -1 +1 @@ -Deno.core.opSync("op_ffi_read_u32", [0, 0]); +Deno.core.opSync("op_ffi_read_u32", 0n); diff --git a/cli/tests/testdata/unstable_ffi_12.js b/cli/tests/testdata/unstable_ffi_12.js index b05f92d39..65934a82f 100644 --- a/cli/tests/testdata/unstable_ffi_12.js +++ b/cli/tests/testdata/unstable_ffi_12.js @@ -1 +1 @@ -Deno.core.opSync("op_ffi_read_i32", [0, 0]); +Deno.core.opSync("op_ffi_read_i32", 0n); diff --git a/cli/tests/testdata/unstable_ffi_13.js b/cli/tests/testdata/unstable_ffi_13.js index a83b8dc18..0ab43781b 100644 --- a/cli/tests/testdata/unstable_ffi_13.js +++ b/cli/tests/testdata/unstable_ffi_13.js @@ -1 +1 @@ -Deno.core.opSync("op_ffi_read_u64", [0, 0]); +Deno.core.opSync("op_ffi_read_u64", 0n); diff --git a/cli/tests/testdata/unstable_ffi_14.js b/cli/tests/testdata/unstable_ffi_14.js index b39b99da5..b65a50a20 100644 --- a/cli/tests/testdata/unstable_ffi_14.js +++ b/cli/tests/testdata/unstable_ffi_14.js @@ -1 +1 @@ -Deno.core.opSync("op_ffi_read_f32", [0, 0]); +Deno.core.opSync("op_ffi_read_f32", 0n); diff --git a/cli/tests/testdata/unstable_ffi_15.js b/cli/tests/testdata/unstable_ffi_15.js index afd49b722..de9f29168 100644 --- a/cli/tests/testdata/unstable_ffi_15.js +++ b/cli/tests/testdata/unstable_ffi_15.js @@ -1 +1 @@ -Deno.core.opSync("op_ffi_read_f64", [0, 0]); +Deno.core.opSync("op_ffi_read_f64", 0n); diff --git a/cli/tests/testdata/unstable_ffi_2.js b/cli/tests/testdata/unstable_ffi_2.js index de392fa7d..fe3d9d709 100644 --- a/cli/tests/testdata/unstable_ffi_2.js +++ b/cli/tests/testdata/unstable_ffi_2.js @@ -1,10 +1,5 @@ -Deno.core.opSync("op_ffi_call_ptr", { - pointer: [0, 0], - def: { - name: null, - parameters: [], - result: "void", - }, +Deno.core.opSync("op_ffi_call_ptr", 0n, { + name: null, parameters: [], - buffers: [], -}); + result: "void", +}, []); diff --git a/cli/tests/testdata/unstable_ffi_3.js b/cli/tests/testdata/unstable_ffi_3.js index 4924d9d67..a8f7f4180 100644 --- a/cli/tests/testdata/unstable_ffi_3.js +++ b/cli/tests/testdata/unstable_ffi_3.js @@ -1,10 +1,5 @@ -Deno.core.opAsync("op_ffi_call_ptr_nonblocking", { - pointer: [0, 0], - def: { - name: null, - parameters: [], - result: "void", - }, +Deno.core.opAsync("op_ffi_call_ptr_nonblocking", 0n, { + name: null, parameters: [], - buffers: [], -}); + result: "void", +}, []); diff --git a/cli/tests/testdata/unstable_ffi_5.js b/cli/tests/testdata/unstable_ffi_5.js index 447ff5842..dc494023d 100644 --- a/cli/tests/testdata/unstable_ffi_5.js +++ b/cli/tests/testdata/unstable_ffi_5.js @@ -1 +1 @@ -Deno.core.opSync("op_ffi_buf_copy_into", [[0, 0], new Uint8Array(0), 0]); +Deno.core.opSync("op_ffi_buf_copy_into", 0n, new Uint8Array(0), 0); diff --git a/cli/tests/testdata/unstable_ffi_6.js b/cli/tests/testdata/unstable_ffi_6.js index cc791b8f0..c66681225 100644 --- a/cli/tests/testdata/unstable_ffi_6.js +++ b/cli/tests/testdata/unstable_ffi_6.js @@ -1 +1 @@ -Deno.core.opSync("op_ffi_cstr_read", [0, 0]); +Deno.core.opSync("op_ffi_cstr_read", 0n); diff --git a/cli/tests/testdata/unstable_ffi_7.js b/cli/tests/testdata/unstable_ffi_7.js index 02ef455ee..a0c27a71c 100644 --- a/cli/tests/testdata/unstable_ffi_7.js +++ b/cli/tests/testdata/unstable_ffi_7.js @@ -1 +1 @@ -Deno.core.opSync("op_ffi_read_u8", [0, 0]); +Deno.core.opSync("op_ffi_read_u8", 0n); diff --git a/cli/tests/testdata/unstable_ffi_8.js b/cli/tests/testdata/unstable_ffi_8.js index d250c9f21..7c51f8aa3 100644 --- a/cli/tests/testdata/unstable_ffi_8.js +++ b/cli/tests/testdata/unstable_ffi_8.js @@ -1 +1 @@ -Deno.core.opSync("op_ffi_read_i8", [0, 0]); +Deno.core.opSync("op_ffi_read_i8", 0n); diff --git a/cli/tests/testdata/unstable_ffi_9.js b/cli/tests/testdata/unstable_ffi_9.js index f21a4cdbf..7798e4d2c 100644 --- a/cli/tests/testdata/unstable_ffi_9.js +++ b/cli/tests/testdata/unstable_ffi_9.js @@ -1 +1 @@ -Deno.core.opSync("op_ffi_read_u16", [0, 0]); +Deno.core.opSync("op_ffi_read_u16", 0n); -- cgit v1.2.3