diff options
Diffstat (limited to 'test_ffi')
-rw-r--r-- | test_ffi/src/lib.rs | 225 | ||||
-rw-r--r-- | test_ffi/tests/bench.js | 503 | ||||
-rw-r--r-- | test_ffi/tests/ffi_types.ts | 132 | ||||
-rw-r--r-- | test_ffi/tests/integration_tests.rs | 16 | ||||
-rw-r--r-- | test_ffi/tests/test.js | 205 |
5 files changed, 1079 insertions, 2 deletions
diff --git a/test_ffi/src/lib.rs b/test_ffi/src/lib.rs index 9a06e29e7..5b813cd01 100644 --- a/test_ffi/src/lib.rs +++ b/test_ffi/src/lib.rs @@ -114,8 +114,233 @@ pub extern "C" fn get_sleep_blocking_ptr() -> *const c_void { } #[no_mangle] +pub extern "C" fn call_fn_ptr(func: Option<extern "C" fn()>) { + if func.is_none() { + return; + } + let func = func.unwrap(); + func(); +} + +#[no_mangle] +pub extern "C" fn call_fn_ptr_many_parameters( + func: Option< + extern "C" fn(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, *const u8), + >, +) { + if func.is_none() { + return; + } + let func = func.unwrap(); + func(1, -1, 2, -2, 3, -3, 4, -4, 0.5, -0.5, BUFFER.as_ptr()); +} + +#[no_mangle] +pub extern "C" fn call_fn_ptr_return_u8(func: Option<extern "C" fn() -> u8>) { + if func.is_none() { + return; + } + let func = func.unwrap(); + println!("u8: {}", func()); +} + +#[allow(clippy::not_unsafe_ptr_arg_deref)] +#[no_mangle] +pub extern "C" fn call_fn_ptr_return_buffer( + func: Option<extern "C" fn() -> *const u8>, +) { + if func.is_none() { + return; + } + let func = func.unwrap(); + let ptr = func(); + let buf = unsafe { std::slice::from_raw_parts(ptr, 8) }; + println!("buf: {:?}", buf); +} + +static mut STORED_FUNCTION: Option<extern "C" fn()> = None; +static mut STORED_FUNCTION_2: Option<extern "C" fn(u8) -> u8> = None; + +#[no_mangle] +pub extern "C" fn store_function(func: Option<extern "C" fn()>) { + unsafe { STORED_FUNCTION = func }; + if func.is_none() { + println!("STORED_FUNCTION cleared"); + } +} + +#[no_mangle] +pub extern "C" fn store_function_2(func: Option<extern "C" fn(u8) -> u8>) { + unsafe { STORED_FUNCTION_2 = func }; + if func.is_none() { + println!("STORED_FUNCTION_2 cleared"); + } +} + +#[no_mangle] +pub extern "C" fn call_stored_function() { + unsafe { + if STORED_FUNCTION.is_none() { + return; + } + STORED_FUNCTION.unwrap()(); + } +} + +#[no_mangle] +pub extern "C" fn call_stored_function_2(arg: u8) { + unsafe { + if STORED_FUNCTION_2.is_none() { + return; + } + println!("{}", STORED_FUNCTION_2.unwrap()(arg)); + } +} + +// FFI performance helper functions +#[no_mangle] +pub extern "C" fn nop() {} + +#[no_mangle] +pub extern "C" fn nop_u8(_a: u8) {} + +#[no_mangle] +pub extern "C" fn nop_i8(_a: i8) {} + +#[no_mangle] +pub extern "C" fn nop_u16(_a: u16) {} + +#[no_mangle] +pub extern "C" fn nop_i16(_a: i16) {} + +#[no_mangle] +pub extern "C" fn nop_u32(_a: u32) {} + +#[no_mangle] +pub extern "C" fn nop_i32(_a: i32) {} + +#[no_mangle] +pub extern "C" fn nop_u64(_a: u64) {} + +#[no_mangle] +pub extern "C" fn nop_i64(_a: i64) {} + +#[no_mangle] +pub extern "C" fn nop_usize(_a: usize) {} + +#[no_mangle] +pub extern "C" fn nop_isize(_a: isize) {} + +#[no_mangle] +pub extern "C" fn nop_f32(_a: f32) {} + +#[no_mangle] +pub extern "C" fn nop_f64(_a: f64) {} + +#[no_mangle] +pub extern "C" fn nop_buffer(_buffer: *mut [u8; 8]) {} + +#[no_mangle] +pub extern "C" fn return_u8() -> u8 { + 255 +} + +#[no_mangle] +pub extern "C" fn return_i8() -> i8 { + -128 +} + +#[no_mangle] +pub extern "C" fn return_u16() -> u16 { + 65535 +} + +#[no_mangle] +pub extern "C" fn return_i16() -> i16 { + -32768 +} + +#[no_mangle] +pub extern "C" fn return_u32() -> u32 { + 4294967295 +} + +#[no_mangle] +pub extern "C" fn return_i32() -> i32 { + -2147483648 +} + +#[no_mangle] +pub extern "C" fn return_u64() -> u64 { + 18446744073709551615 +} + +#[no_mangle] +pub extern "C" fn return_i64() -> i64 { + -9223372036854775808 +} + +#[no_mangle] +pub extern "C" fn return_usize() -> usize { + 18446744073709551615 +} + +#[no_mangle] +pub extern "C" fn return_isize() -> isize { + -9223372036854775808 +} + +#[no_mangle] +pub extern "C" fn return_f32() -> f32 { + #[allow(clippy::excessive_precision)] + 0.20298023223876953125 +} + +#[no_mangle] +pub extern "C" fn return_f64() -> f64 { + 1e-10 +} + +// Parameters iteration + +#[no_mangle] +pub extern "C" fn nop_many_parameters( + _: u8, + _: i8, + _: u16, + _: i16, + _: u32, + _: i32, + _: u64, + _: i64, + _: usize, + _: isize, + _: f32, + _: f64, + _: *mut [u8; 8], + _: u8, + _: i8, + _: u16, + _: i16, + _: u32, + _: i32, + _: u64, + _: i64, + _: usize, + _: isize, + _: f32, + _: f64, + _: *mut [u8; 8], +) { +} + +// Statics +#[no_mangle] pub static static_u32: u32 = 42; +#[no_mangle] +pub static static_i64: i64 = -1242464576485; + #[repr(C)] pub struct Structure { _data: u32, diff --git a/test_ffi/tests/bench.js b/test_ffi/tests/bench.js new file mode 100644 index 000000000..398732cc8 --- /dev/null +++ b/test_ffi/tests/bench.js @@ -0,0 +1,503 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +// deno-lint-ignore-file + +const targetDir = Deno.execPath().replace(/[^\/\\]+$/, ""); +const [libPrefix, libSuffix] = { + darwin: ["lib", "dylib"], + linux: ["lib", "so"], + windows: ["", "dll"], +}[Deno.build.os]; +const libPath = `${targetDir}/${libPrefix}test_ffi.${libSuffix}`; + +const dylib = Deno.dlopen(libPath, { + "nop": { parameters: [], result: "void" }, + "nop_u8": { parameters: ["u8"], result: "void" }, + "nop_i8": { parameters: ["i8"], result: "void" }, + "nop_u16": { parameters: ["u16"], result: "void" }, + "nop_i16": { parameters: ["i16"], result: "void" }, + "nop_u32": { parameters: ["u32"], result: "void" }, + "nop_i32": { parameters: ["i32"], result: "void" }, + "nop_u64": { parameters: ["u64"], result: "void" }, + "nop_i64": { parameters: ["i64"], result: "void" }, + "nop_usize": { parameters: ["usize"], result: "void" }, + "nop_isize": { parameters: ["isize"], result: "void" }, + "nop_f32": { parameters: ["f32"], result: "void" }, + "nop_f64": { parameters: ["f64"], result: "void" }, + "nop_buffer": { parameters: ["pointer"], result: "void" }, + "return_u8": { parameters: [], result: "u8" }, + "return_i8": { parameters: [], result: "i8" }, + "return_u16": { parameters: [], result: "u16" }, + "return_i16": { parameters: [], result: "i16" }, + "return_u32": { parameters: [], result: "u32" }, + "return_i32": { parameters: [], result: "i32" }, + "return_u64": { parameters: [], result: "u64" }, + "return_i64": { parameters: [], result: "i64" }, + "return_usize": { parameters: [], result: "usize" }, + "return_isize": { parameters: [], result: "isize" }, + "return_f32": { parameters: [], result: "f32" }, + "return_f64": { parameters: [], result: "f64" }, + "return_buffer": { parameters: [], result: "pointer" }, + // Nonblocking calls + "nop_nonblocking": { name: "nop", parameters: [], result: "void" }, + "nop_u8_nonblocking": { name: "nop_u8", parameters: ["u8"], result: "void" }, + "nop_i8_nonblocking": { name: "nop_i8", parameters: ["i8"], result: "void" }, + "nop_u16_nonblocking": { + name: "nop_u16", + parameters: ["u16"], + result: "void", + }, + "nop_i16_nonblocking": { + name: "nop_i16", + parameters: ["i16"], + result: "void", + }, + "nop_u32_nonblocking": { + name: "nop_u32", + parameters: ["u32"], + result: "void", + }, + "nop_i32_nonblocking": { + name: "nop_i32", + parameters: ["i32"], + result: "void", + }, + "nop_u64_nonblocking": { + name: "nop_u64", + parameters: ["u64"], + result: "void", + }, + "nop_i64_nonblocking": { + name: "nop_i64", + parameters: ["i64"], + result: "void", + }, + "nop_usize_nonblocking": { + name: "nop_usize", + parameters: ["usize"], + result: "void", + }, + "nop_isize_nonblocking": { + name: "nop_isize", + parameters: ["isize"], + result: "void", + }, + "nop_f32_nonblocking": { + name: "nop_f32", + parameters: ["f32"], + result: "void", + }, + "nop_f64_nonblocking": { + name: "nop_f64", + parameters: ["f64"], + result: "void", + }, + "nop_buffer_nonblocking": { + name: "nop_buffer", + parameters: ["pointer"], + result: "void", + }, + "return_u8_nonblocking": { name: "return_u8", parameters: [], result: "u8" }, + "return_i8_nonblocking": { name: "return_i8", parameters: [], result: "i8" }, + "return_u16_nonblocking": { + name: "return_u16", + parameters: [], + result: "u16", + }, + "return_i16_nonblocking": { + name: "return_i16", + parameters: [], + result: "i16", + }, + "return_u32_nonblocking": { + name: "return_u32", + parameters: [], + result: "u32", + }, + "return_i32_nonblocking": { + name: "return_i32", + parameters: [], + result: "i32", + }, + "return_u64_nonblocking": { + name: "return_u64", + parameters: [], + result: "u64", + }, + "return_i64_nonblocking": { + name: "return_i64", + parameters: [], + result: "i64", + }, + "return_usize_nonblocking": { + name: "return_usize", + parameters: [], + result: "usize", + }, + "return_isize_nonblocking": { + name: "return_isize", + parameters: [], + result: "isize", + }, + "return_f32_nonblocking": { + name: "return_f32", + parameters: [], + result: "f32", + }, + "return_f64_nonblocking": { + name: "return_f64", + parameters: [], + result: "f64", + }, + "return_buffer_nonblocking": { + name: "return_buffer", + parameters: [], + result: "pointer", + }, + // Parameter checking + "nop_many_parameters": { + parameters: [ + "u8", + "i8", + "u16", + "i16", + "u32", + "i32", + "u64", + "i64", + "usize", + "isize", + "f32", + "f64", + "pointer", + "u8", + "i8", + "u16", + "i16", + "u32", + "i32", + "u64", + "i64", + "usize", + "isize", + "f32", + "f64", + "pointer", + ], + result: "void", + }, + "nop_many_parameters_nonblocking": { + name: "nop_many_parameters", + parameters: [ + "u8", + "i8", + "u16", + "i16", + "u32", + "i32", + "u64", + "i64", + "usize", + "isize", + "f32", + "f64", + "pointer", + "u8", + "i8", + "u16", + "i16", + "u32", + "i32", + "u64", + "i64", + "usize", + "isize", + "f32", + "f64", + "pointer", + ], + result: "void", + nonblocking: true, + }, +}); + +Deno.bench("nop()", () => { + dylib.symbols.nop(); +}); + +Deno.bench("nop_u8()", () => { + dylib.symbols.nop_u8(100); +}); + +Deno.bench("nop_i8()", () => { + dylib.symbols.nop_i8(100); +}); + +Deno.bench("nop_u16()", () => { + dylib.symbols.nop_u16(100); +}); + +Deno.bench("nop_i16()", () => { + dylib.symbols.nop_i16(100); +}); + +Deno.bench("nop_u32()", () => { + dylib.symbols.nop_u32(100); +}); + +Deno.bench("nop_i32()", () => { + dylib.symbols.nop_i32(100); +}); + +Deno.bench("nop_u64()", () => { + dylib.symbols.nop_u64(100); +}); + +Deno.bench("nop_i64()", () => { + dylib.symbols.nop_i64(100); +}); + +Deno.bench("nop_usize()", () => { + dylib.symbols.nop_usize(100); +}); + +Deno.bench("nop_isize()", () => { + dylib.symbols.nop_isize(100); +}); + +Deno.bench("nop_f32()", () => { + dylib.symbols.nop_f32(100); +}); + +Deno.bench("nop_f64()", () => { + dylib.symbols.nop_f64(100); +}); + +const buffer = new Uint8Array(8).fill(5); +Deno.bench("nop_buffer()", () => { + dylib.symbols.nop_buffer(buffer); +}); + +Deno.bench("return_u8()", () => { + dylib.symbols.return_u8(); +}); + +Deno.bench("return_i8()", () => { + dylib.symbols.return_i8(); +}); + +Deno.bench("return_u16()", () => { + dylib.symbols.return_u16(); +}); + +Deno.bench("return_i16()", () => { + dylib.symbols.return_i16(); +}); + +Deno.bench("return_u32()", () => { + dylib.symbols.return_u32(); +}); + +Deno.bench("return_i32()", () => { + dylib.symbols.return_i32(); +}); + +Deno.bench("return_u64()", () => { + dylib.symbols.return_u64(); +}); + +Deno.bench("return_i64()", () => { + dylib.symbols.return_i64(); +}); + +Deno.bench("return_usize()", () => { + dylib.symbols.return_usize(); +}); + +Deno.bench("return_isize()", () => { + dylib.symbols.return_isize(); +}); + +Deno.bench("return_f32()", () => { + dylib.symbols.return_f32(); +}); + +Deno.bench("return_f64()", () => { + dylib.symbols.return_f64(); +}); + +Deno.bench("return_buffer()", () => { + dylib.symbols.return_buffer(); +}); + +// Nonblocking calls + +Deno.bench("nop_nonblocking()", async () => { + await dylib.symbols.nop_nonblocking(); +}); + +Deno.bench("nop_u8_nonblocking()", async () => { + await dylib.symbols.nop_u8_nonblocking(100); +}); + +Deno.bench("nop_i8_nonblocking()", async () => { + await dylib.symbols.nop_i8_nonblocking(100); +}); + +Deno.bench("nop_u16_nonblocking()", async () => { + await dylib.symbols.nop_u16_nonblocking(100); +}); + +Deno.bench("nop_i16_nonblocking()", async () => { + await dylib.symbols.nop_i16_nonblocking(100); +}); + +Deno.bench("nop_u32_nonblocking()", async () => { + await dylib.symbols.nop_u32_nonblocking(100); +}); + +Deno.bench("nop_i32_nonblocking()", async () => { + await dylib.symbols.nop_i32_nonblocking(100); +}); + +Deno.bench("nop_u64_nonblocking()", async () => { + await dylib.symbols.nop_u64_nonblocking(100); +}); + +Deno.bench("nop_i64_nonblocking()", async () => { + await dylib.symbols.nop_i64_nonblocking(100); +}); + +Deno.bench("nop_usize_nonblocking()", async () => { + await dylib.symbols.nop_usize_nonblocking(100); +}); + +Deno.bench("nop_isize_nonblocking()", async () => { + await dylib.symbols.nop_isize_nonblocking(100); +}); + +Deno.bench("nop_f32_nonblocking()", async () => { + await dylib.symbols.nop_f32_nonblocking(100); +}); + +Deno.bench("nop_f64_nonblocking()", async () => { + await dylib.symbols.nop_f64_nonblocking(100); +}); + +Deno.bench("nop_buffer_nonblocking()", async () => { + await dylib.symbols.nop_buffer_nonblocking(buffer); +}); + +Deno.bench("return_u8_nonblocking()", async () => { + await dylib.symbols.return_u8_nonblocking(); +}); + +Deno.bench("return_i8_nonblocking()", async () => { + await dylib.symbols.return_i8_nonblocking(); +}); + +Deno.bench("return_u16_nonblocking()", async () => { + await dylib.symbols.return_u16_nonblocking(); +}); + +Deno.bench("return_i16_nonblocking()", async () => { + await dylib.symbols.return_i16_nonblocking(); +}); + +Deno.bench("return_u32_nonblocking()", async () => { + await dylib.symbols.return_u32_nonblocking(); +}); + +Deno.bench("return_i32_nonblocking()", async () => { + await dylib.symbols.return_i32_nonblocking(); +}); + +Deno.bench("return_u64_nonblocking()", async () => { + await dylib.symbols.return_u64_nonblocking(); +}); + +Deno.bench("return_i64_nonblocking()", async () => { + await dylib.symbols.return_i64_nonblocking(); +}); + +Deno.bench("return_usize_nonblocking()", async () => { + await dylib.symbols.return_usize_nonblocking(); +}); + +Deno.bench("return_isize_nonblocking()", async () => { + await dylib.symbols.return_isize_nonblocking(); +}); + +Deno.bench("return_f32_nonblocking()", async () => { + await dylib.symbols.return_f32_nonblocking(); +}); + +Deno.bench("return_f64_nonblocking()", async () => { + await dylib.symbols.return_f64_nonblocking(); +}); + +Deno.bench("return_buffer_nonblocking()", async () => { + await dylib.symbols.return_buffer_nonblocking(); +}); + +const buffer2 = new Uint8Array(8).fill(25); +Deno.bench("nop_many_parameters()", () => { + dylib.symbols.nop_many_parameters( + 135, + 47, + 356, + -236, + 7457, + -1356, + 16471468n, + -1334748136n, + 132658769535n, + -42745856824n, + 13567.26437, + 7.686234e-3, + buffer, + 64, + -42, + 83, + -136, + 3657, + -2376, + 3277918n, + -474628146n, + 344657895n, + -2436732n, + 135.26437e3, + 264.3576468623546834, + buffer2, + ); +}); + +Deno.bench("nop_many_parameters_nonblocking()", () => { + dylib.symbols.nop_many_parameters_nonblocking( + 135, + 47, + 356, + -236, + 7457, + -1356, + 16471468n, + -1334748136n, + 132658769535n, + -42745856824n, + 13567.26437, + 7.686234e-3, + buffer, + 64, + -42, + 83, + -136, + 3657, + -2376, + 3277918n, + -474628146n, + 344657895n, + -2436732n, + 135.26437e3, + 264.3576468623546834, + buffer2, + ); +}); diff --git a/test_ffi/tests/ffi_types.ts b/test_ffi/tests/ffi_types.ts index 9ad51e67c..92ac13892 100644 --- a/test_ffi/tests/ffi_types.ts +++ b/test_ffi/tests/ffi_types.ts @@ -24,6 +24,27 @@ const remote = Deno.dlopen( method17: { parameters: [], result: "usize", nonblocking: true }, method18: { parameters: [], result: "pointer" }, method19: { parameters: [], result: "pointer", nonblocking: true }, + method20: { + parameters: [{ + function: { parameters: ["u8", "u32", "pointer"], result: "void" }, + }], + result: "void", + }, + method21: { + parameters: [ + { function: { parameters: [], result: "u8" } }, + ], + result: "void", + }, + method22: { + parameters: [{ + function: { + parameters: [], + result: { function: { parameters: [], result: "u8" } }, + }, + }], + result: "void", + }, static1: { type: "usize" }, static2: { type: "pointer" }, static3: { type: "usize" }, @@ -41,6 +62,23 @@ const remote = Deno.dlopen( } as const, ); +Deno.dlopen( + "dummy_lib_2.so", + // @ts-expect-error: Returning a function pointer + // is declared using "pointer" + UnsafeFnPointer + { + wrong_method1: { + parameters: [], + result: { + function: { + parameters: [], + result: "void", + }, + }, + }, + } as const, +); + // @ts-expect-error: Invalid argument remote.symbols.method1(0); // @ts-expect-error: Invalid return type @@ -136,6 +174,100 @@ const fnptr = new Deno.UnsafeFnPointer( fnptr.call(null, null); fnptr.call(0, null); +const unsafe_callback_wrong1 = new Deno.UnsafeCallback( + { + parameters: ["i8"], + result: "void", + } as const, + // @ts-expect-error: i8 is not a pointer + (_: Deno.UnsafePointer) => {}, +); +const unsafe_callback_wrong2 = new Deno.UnsafeCallback( + { + parameters: ["pointer"], + result: "u64", + } as const, + // @ts-expect-error: must return a number or bigint + (_: Deno.UnsafePointer) => {}, +); +const unsafe_callback_wrong3 = new Deno.UnsafeCallback( + { + parameters: [], + result: "void", + } as const, + // @ts-expect-error: no parameters + (_: Deno.UnsafePointer) => {}, +); +const unsafe_callback_wrong4 = new Deno.UnsafeCallback( + { + parameters: ["u64"], + result: "void", + } as const, + // @ts-expect-error: Callback's 64bit parameters are always called as bigint + (_: number) => {}, +); +const unsafe_callback_right1 = new Deno.UnsafeCallback( + { + parameters: ["u8", "u32", "pointer"], + result: "void", + } as const, + (_1: number, _2: number, _3: Deno.UnsafePointer) => {}, +); +const unsafe_callback_right2 = new Deno.UnsafeCallback( + { + parameters: [], + result: "u8", + } as const, + () => 3, +); +const unsafe_callback_right3 = new Deno.UnsafeCallback( + { + parameters: [], + result: { + function: { + parameters: [], + result: "u8", + }, + }, + } as const, + // Callbacks can return other callbacks, if really wanted. + () => unsafe_callback_right2, +); +const unsafe_callback_right4 = new Deno.UnsafeCallback( + { + parameters: ["u8", "u32", "pointer"], + result: "u8", + } as const, + (_1: number, _2: number, _3: Deno.UnsafePointer) => 3, +); +const unsafe_callback_right5 = new Deno.UnsafeCallback( + { + parameters: ["u8", "i32", "pointer"], + result: "void", + } as const, + (_1: number, _2: number, _3: Deno.UnsafePointer) => {}, +); + +// @ts-expect-error: Must pass callback +remote.symbols.method20(); +// nullptr is okay +remote.symbols.method20(null); +// Foreign function ptr received as UnsafePointer is okay +remote.symbols.method20({} as Deno.UnsafePointer); +// @ts-expect-error: Callback does not match the parameter +remote.symbols.method20(unsafe_callback_right2); +remote.symbols.method20(unsafe_callback_right1); +// @ts-expect-error: Callback must match return value as well +remote.symbols.method20(unsafe_callback_right4); +// @ts-expect-error: Subtle differences in parameter types are not allowed (i32 vs u32) +remote.symbols.method20(unsafe_callback_right5); +remote.symbols.method21(unsafe_callback_right2); +remote.symbols.method22(unsafe_callback_right3); +// @ts-expect-error: Callback returns a callback with the wrong return value +remote.symbols.method21(unsafe_callback_right3); +// @ts-expect-error: Callback returns a callback with the wrong return value +remote.symbols.method22(unsafe_callback_right2); + // @ts-expect-error: Invalid member type const static1_wrong: null = remote.symbols.static1; const static1_right: bigint = remote.symbols.static1; diff --git a/test_ffi/tests/integration_tests.rs b/test_ffi/tests/integration_tests.rs index 5b9bb2fc2..93f368787 100644 --- a/test_ffi/tests/integration_tests.rs +++ b/test_ffi/tests/integration_tests.rs @@ -65,11 +65,27 @@ fn basic() { -8589934590n\n\ 579.9119873046875\n\ 579.912\n\ + 579\n\ + 8589934590n\n\ + -8589934590n\n\ + 8589934590n\n\ + -8589934590n\n\ + 579.9119873046875\n\ + 579.912\n\ After sleep_blocking\n\ true\n\ Before\n\ true\n\ + logCallback\n\ + 1 -1 2 -2 3 -3 4n -4n 0.5 -0.5 1 2 3 4 5 6 7 8\n\ + u8: 8\n\ + buf: [1, 2, 3, 4, 5, 6, 7, 8]\n\ + logCallback\n\ + 30\n\ + STORED_FUNCTION cleared\n\ + STORED_FUNCTION_2 cleared\n\ Static u32: 42\n\ + Static i64: -1242464576485n\n\ Static ptr: true\n\ Static ptr value: 42\n\ After\n\ diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js index b89dca648..1568abcbd 100644 --- a/test_ffi/tests/test.js +++ b/test_ffi/tests/test.js @@ -52,6 +52,54 @@ const dylib = Deno.dlopen(libPath, { "add_isize": { parameters: ["isize", "isize"], result: "isize" }, "add_f32": { parameters: ["f32", "f32"], result: "f32" }, "add_f64": { parameters: ["f64", "f64"], result: "f64" }, + "add_u32_nonblocking": { + name: "add_u32", + parameters: ["u32", "u32"], + result: "u32", + nonblocking: true, + }, + "add_i32_nonblocking": { + name: "add_i32", + parameters: ["i32", "i32"], + result: "i32", + nonblocking: true, + }, + "add_u64_nonblocking": { + name: "add_u64", + parameters: ["u64", "u64"], + result: "u64", + nonblocking: true, + }, + "add_i64_nonblocking": { + name: "add_i64", + parameters: ["i64", "i64"], + result: "i64", + nonblocking: true, + }, + "add_usize_nonblocking": { + name: "add_usize", + parameters: ["usize", "usize"], + result: "usize", + nonblocking: true, + }, + "add_isize_nonblocking": { + name: "add_isize", + parameters: ["isize", "isize"], + result: "isize", + nonblocking: true, + }, + "add_f32_nonblocking": { + name: "add_f32", + parameters: ["f32", "f32"], + result: "f32", + nonblocking: true, + }, + "add_f64_nonblocking": { + name: "add_f64", + parameters: ["f64", "f64"], + result: "f64", + nonblocking: true, + }, "fill_buffer": { parameters: ["u8", "pointer", "usize"], result: "void" }, "sleep_nonblocking": { name: "sleep_blocking", @@ -73,9 +121,63 @@ const dylib = Deno.dlopen(libPath, { parameters: [], result: "pointer", }, + // Callback function + call_fn_ptr: { + parameters: [{ function: { parameters: [], result: "void" } }], + result: "void", + }, + call_fn_ptr_many_parameters: { + parameters: [{ + function: { + parameters: [ + "u8", + "i8", + "u16", + "i16", + "u32", + "i32", + "u64", + "i64", + "f32", + "f64", + "pointer", + ], + result: "void", + }, + }], + result: "void", + }, + call_fn_ptr_return_u8: { + parameters: [{ function: { parameters: [], result: "u8" } }], + result: "void", + }, + call_fn_ptr_return_buffer: { + parameters: [{ function: { parameters: [], result: "pointer" } }], + result: "void", + }, + store_function: { + parameters: [{ function: { parameters: [], result: "void" } }], + result: "void", + }, + store_function_2: { + parameters: [{ function: { parameters: ["u8"], result: "u8" } }], + result: "void", + }, + call_stored_function: { + parameters: [], + result: "void", + }, + call_stored_function_2: { + parameters: ["u8"], + result: "void", + }, + // Statics "static_u32": { type: "u32", }, + "static_i64": { + type: "i64", + }, "static_ptr": { type: "pointer", }, @@ -135,14 +237,14 @@ assertThrows( dylib.symbols.add_u32(-1, 100); }, TypeError, - "Expected FFI argument to be an unsigned integer, but got Number(-1)", + "Expected FFI argument to be an unsigned integer, but got '-1'", ); assertThrows( () => { dylib.symbols.add_u32(null, 100); }, TypeError, - "Expected FFI argument to be an unsigned integer, but got Null", + "Expected FFI argument to be an unsigned integer, but got 'null'", ); console.log(dylib.symbols.add_i32(123, 456)); console.log(dylib.symbols.add_u64(0xffffffffn, 0xffffffffn)); @@ -152,6 +254,21 @@ console.log(dylib.symbols.add_isize(-0xffffffffn, -0xffffffffn)); console.log(dylib.symbols.add_f32(123.123, 456.789)); console.log(dylib.symbols.add_f64(123.123, 456.789)); +// Test adders as nonblocking calls +console.log(await dylib.symbols.add_i32_nonblocking(123, 456)); +console.log(await dylib.symbols.add_u64_nonblocking(0xffffffffn, 0xffffffffn)); +console.log( + await dylib.symbols.add_i64_nonblocking(-0xffffffffn, -0xffffffffn), +); +console.log( + await dylib.symbols.add_usize_nonblocking(0xffffffffn, 0xffffffffn), +); +console.log( + await dylib.symbols.add_isize_nonblocking(-0xffffffffn, -0xffffffffn), +); +console.log(await dylib.symbols.add_f32_nonblocking(123.123, 456.789)); +console.log(await dylib.symbols.add_f64_nonblocking(123.123, 456.789)); + // test mutating sync calls function test_fill_buffer(fillValue, arr) { @@ -207,7 +324,84 @@ dylib.symbols.sleep_nonblocking(100).then(() => { console.log("Before"); console.log(performance.now() - start < 100); +// Test calls with callback parameters +const logCallback = new Deno.UnsafeCallback( + { parameters: [], result: "void" }, + () => console.log("logCallback"), +); +const logManyParametersCallback = new Deno.UnsafeCallback({ + parameters: [ + "u8", + "i8", + "u16", + "i16", + "u32", + "i32", + "u64", + "i64", + "f32", + "f64", + "pointer", + ], + result: "void", +}, (u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, pointer) => { + const view = new Deno.UnsafePointerView(new Deno.UnsafePointer(pointer)); + const copy_buffer = new Uint8Array(8); + view.copyInto(copy_buffer); + console.log(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, ...copy_buffer); +}); +const returnU8Callback = new Deno.UnsafeCallback( + { parameters: [], result: "u8" }, + () => 8, +); +const returnBufferCallback = new Deno.UnsafeCallback({ + parameters: [], + result: "pointer", +}, () => { + return buffer; +}); +const add10Callback = new Deno.UnsafeCallback({ + parameters: ["u8"], + result: "u8", +}, (value) => value + 10); +const throwCallback = new Deno.UnsafeCallback({ + parameters: [], + result: "void", +}, () => { + throw new TypeError("hi"); +}); + +assertThrows( + () => { + dylib.symbols.call_fn_ptr(throwCallback); + }, + TypeError, + "hi", +); + +dylib.symbols.call_fn_ptr(logCallback); +dylib.symbols.call_fn_ptr_many_parameters(logManyParametersCallback); +dylib.symbols.call_fn_ptr_return_u8(returnU8Callback); +dylib.symbols.call_fn_ptr_return_buffer(returnBufferCallback); +dylib.symbols.store_function(logCallback); +dylib.symbols.call_stored_function(); +dylib.symbols.store_function_2(add10Callback); +dylib.symbols.call_stored_function_2(20); + +const nestedCallback = new Deno.UnsafeCallback( + { parameters: [], result: "void" }, + () => { + dylib.symbols.call_stored_function_2(10); + }, +); +dylib.symbols.store_function(nestedCallback); + +dylib.symbols.store_function(null); +dylib.symbols.store_function_2(null); + +// Test statics console.log("Static u32:", dylib.symbols.static_u32); +console.log("Static i64:", dylib.symbols.static_i64); console.log( "Static ptr:", dylib.symbols.static_ptr instanceof Deno.UnsafePointer, @@ -217,6 +411,13 @@ console.log("Static ptr value:", view.getUint32()); function cleanup() { dylib.close(); + throwCallback.close(); + logCallback.close(); + logManyParametersCallback.close(); + returnU8Callback.close(); + returnBufferCallback.close(); + add10Callback.close(); + nestedCallback.close(); const resourcesPost = Deno.resources(); |