summaryrefslogtreecommitdiff
path: root/test_ffi/tests
diff options
context:
space:
mode:
Diffstat (limited to 'test_ffi/tests')
-rw-r--r--test_ffi/tests/bench.js687
-rw-r--r--test_ffi/tests/event_loop_integration.ts78
-rw-r--r--test_ffi/tests/ffi_callback_errors.ts141
-rw-r--r--test_ffi/tests/ffi_types.ts529
-rw-r--r--test_ffi/tests/integration_tests.rs280
-rw-r--r--test_ffi/tests/test.js802
-rw-r--r--test_ffi/tests/thread_safe_test.js105
-rw-r--r--test_ffi/tests/thread_safe_test_worker.js41
8 files changed, 0 insertions, 2663 deletions
diff --git a/test_ffi/tests/bench.js b/test_ffi/tests/bench.js
deleted file mode 100644
index 49884d32e..000000000
--- a/test_ffi/tests/bench.js
+++ /dev/null
@@ -1,687 +0,0 @@
-// Copyright 2018-2024 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" },
- "add_u32": { parameters: ["u32", "u32"], result: "u32" },
- "add_u64": { parameters: ["u64", "u64"], result: "u64" },
- "ffi_string": { parameters: [], result: "pointer" },
- "hash": { parameters: ["buffer", "u32"], result: "u32" },
- "nop_bool": { parameters: ["bool"], 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: ["buffer"], result: "void" },
- "return_bool": { parameters: [], result: "bool" },
- "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: "buffer" },
- // Nonblocking calls
- "nop_nonblocking": { name: "nop", parameters: [], result: "void" },
- "nop_bool_nonblocking": {
- name: "nop_bool",
- parameters: ["bool"],
- 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: ["buffer"],
- result: "void",
- },
- "return_bool_nonblocking": {
- name: "return_bool",
- parameters: [],
- result: "bool",
- },
- "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: "buffer",
- },
- // Parameter checking
- "nop_many_parameters": {
- parameters: [
- "u8",
- "i8",
- "u16",
- "i16",
- "u32",
- "i32",
- "u64",
- "i64",
- "usize",
- "isize",
- "f32",
- "f64",
- "buffer",
- "u8",
- "i8",
- "u16",
- "i16",
- "u32",
- "i32",
- "u64",
- "i64",
- "usize",
- "isize",
- "f32",
- "f64",
- "buffer",
- ],
- 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,
- },
-});
-
-const { nop } = dylib.symbols;
-Deno.bench("nop()", () => {
- nop();
-});
-
-const bytes = new Uint8Array(64);
-
-const { hash } = dylib.symbols;
-Deno.bench("hash()", () => {
- hash(bytes, bytes.byteLength);
-});
-
-const { ffi_string } = dylib.symbols;
-Deno.bench(
- "c string",
- () => Deno.UnsafePointerView.getCString(ffi_string()),
-);
-
-const { add_u32 } = dylib.symbols;
-Deno.bench("add_u32()", () => {
- add_u32(1, 2);
-});
-
-const { return_buffer } = dylib.symbols;
-Deno.bench("return_buffer()", () => {
- return_buffer();
-});
-
-const { add_u64 } = dylib.symbols;
-Deno.bench("add_u64()", () => {
- add_u64(1, 2);
-});
-
-const { return_u64 } = dylib.symbols;
-Deno.bench("return_u64()", () => {
- return_u64();
-});
-
-const { return_i64 } = dylib.symbols;
-Deno.bench("return_i64()", () => {
- return_i64();
-});
-
-const { nop_bool } = dylib.symbols;
-Deno.bench("nop_bool()", () => {
- nop_bool(true);
-});
-
-const { nop_u8 } = dylib.symbols;
-Deno.bench("nop_u8()", () => {
- nop_u8(100);
-});
-
-const { nop_i8 } = dylib.symbols;
-Deno.bench("nop_i8()", () => {
- nop_i8(100);
-});
-
-const { nop_u16 } = dylib.symbols;
-Deno.bench("nop_u16()", () => {
- nop_u16(100);
-});
-
-const { nop_i16 } = dylib.symbols;
-Deno.bench("nop_i16()", () => {
- nop_i16(100);
-});
-
-const { nop_u32 } = dylib.symbols;
-Deno.bench("nop_u32()", () => {
- nop_u32(100);
-});
-
-const { nop_i32 } = dylib.symbols;
-Deno.bench("nop_i32()", () => {
- nop_i32(100);
-});
-
-const { nop_u64 } = dylib.symbols;
-Deno.bench("nop_u64()", () => {
- nop_u64(100);
-});
-
-const { nop_i64 } = dylib.symbols;
-Deno.bench("nop_i64()", () => {
- nop_i64(100);
-});
-
-const { nop_usize } = dylib.symbols;
-Deno.bench("nop_usize() number", () => {
- nop_usize(100);
-});
-
-Deno.bench("nop_usize() bigint", () => {
- nop_usize(100n);
-});
-
-const { nop_isize } = dylib.symbols;
-Deno.bench("nop_isize() number", () => {
- nop_isize(100);
-});
-
-Deno.bench("nop_isize() bigint", () => {
- nop_isize(100n);
-});
-
-const { nop_f32 } = dylib.symbols;
-Deno.bench("nop_f32()", () => {
- nop_f32(100.1);
-});
-
-const { nop_f64 } = dylib.symbols;
-Deno.bench("nop_f64()", () => {
- nop_f64(100.1);
-});
-
-const { nop_buffer } = dylib.symbols;
-const buffer = new Uint8Array(8).fill(5);
-Deno.bench("nop_buffer()", () => {
- nop_buffer(buffer);
-});
-
-const { return_bool } = dylib.symbols;
-Deno.bench("return_bool()", () => {
- return_bool();
-});
-
-const { return_u8 } = dylib.symbols;
-Deno.bench("return_u8()", () => {
- return_u8();
-});
-
-const { return_i8 } = dylib.symbols;
-Deno.bench("return_i8()", () => {
- return_i8();
-});
-
-const { return_u16 } = dylib.symbols;
-Deno.bench("return_u16()", () => {
- return_u16();
-});
-
-const { return_i16 } = dylib.symbols;
-Deno.bench("return_i16()", () => {
- return_i16();
-});
-
-const { return_u32 } = dylib.symbols;
-Deno.bench("return_u32()", () => {
- return_u32();
-});
-
-const { return_i32 } = dylib.symbols;
-Deno.bench("return_i32()", () => {
- return_i32();
-});
-
-const { return_usize } = dylib.symbols;
-Deno.bench("return_usize()", () => {
- return_usize();
-});
-
-const { return_isize } = dylib.symbols;
-Deno.bench("return_isize()", () => {
- return_isize();
-});
-
-const { return_f32 } = dylib.symbols;
-Deno.bench("return_f32()", () => {
- return_f32();
-});
-
-const { return_f64 } = dylib.symbols;
-Deno.bench("return_f64()", () => {
- return_f64();
-});
-
-// Nonblocking calls
-
-const { nop_nonblocking } = dylib.symbols;
-Deno.bench("nop_nonblocking()", async () => {
- await nop_nonblocking();
-});
-
-const { nop_bool_nonblocking } = dylib.symbols;
-Deno.bench("nop_bool_nonblocking()", async () => {
- await nop_bool_nonblocking(true);
-});
-
-const { nop_u8_nonblocking } = dylib.symbols;
-Deno.bench("nop_u8_nonblocking()", async () => {
- await nop_u8_nonblocking(100);
-});
-
-const { nop_i8_nonblocking } = dylib.symbols;
-Deno.bench("nop_i8_nonblocking()", async () => {
- await nop_i8_nonblocking(100);
-});
-
-const { nop_u16_nonblocking } = dylib.symbols;
-Deno.bench("nop_u16_nonblocking()", async () => {
- await nop_u16_nonblocking(100);
-});
-
-const { nop_i16_nonblocking } = dylib.symbols;
-Deno.bench("nop_i16_nonblocking()", async () => {
- await nop_i16_nonblocking(100);
-});
-
-const { nop_u32_nonblocking } = dylib.symbols;
-Deno.bench("nop_u32_nonblocking()", async () => {
- await nop_u32_nonblocking(100);
-});
-
-const { nop_i32_nonblocking } = dylib.symbols;
-
-Deno.bench("nop_i32_nonblocking()", async () => {
- await nop_i32_nonblocking(100);
-});
-
-const { nop_u64_nonblocking } = dylib.symbols;
-Deno.bench("nop_u64_nonblocking()", async () => {
- await nop_u64_nonblocking(100);
-});
-
-const { nop_i64_nonblocking } = dylib.symbols;
-Deno.bench("nop_i64_nonblocking()", async () => {
- await nop_i64_nonblocking(100);
-});
-
-const { nop_usize_nonblocking } = dylib.symbols;
-Deno.bench("nop_usize_nonblocking()", async () => {
- await nop_usize_nonblocking(100);
-});
-
-const { nop_isize_nonblocking } = dylib.symbols;
-Deno.bench("nop_isize_nonblocking()", async () => {
- await nop_isize_nonblocking(100);
-});
-
-const { nop_f32_nonblocking } = dylib.symbols;
-Deno.bench("nop_f32_nonblocking()", async () => {
- await nop_f32_nonblocking(100);
-});
-
-const { nop_f64_nonblocking } = dylib.symbols;
-Deno.bench("nop_f64_nonblocking()", async () => {
- await nop_f64_nonblocking(100);
-});
-
-const { nop_buffer_nonblocking } = dylib.symbols;
-Deno.bench("nop_buffer_nonblocking()", async () => {
- await nop_buffer_nonblocking(buffer);
-});
-
-const { return_bool_nonblocking } = dylib.symbols;
-Deno.bench("return_bool_nonblocking()", async () => {
- await return_bool_nonblocking();
-});
-
-const { return_u8_nonblocking } = dylib.symbols;
-Deno.bench("return_u8_nonblocking()", async () => {
- await return_u8_nonblocking();
-});
-
-const { return_i8_nonblocking } = dylib.symbols;
-Deno.bench("return_i8_nonblocking()", async () => {
- await return_i8_nonblocking();
-});
-
-const { return_u16_nonblocking } = dylib.symbols;
-Deno.bench("return_u16_nonblocking()", async () => {
- await return_u16_nonblocking();
-});
-
-const { return_i16_nonblocking } = dylib.symbols;
-Deno.bench("return_i16_nonblocking()", async () => {
- await return_i16_nonblocking();
-});
-
-const { return_u32_nonblocking } = dylib.symbols;
-Deno.bench("return_u32_nonblocking()", async () => {
- await return_u32_nonblocking();
-});
-
-const { return_i32_nonblocking } = dylib.symbols;
-Deno.bench("return_i32_nonblocking()", async () => {
- await return_i32_nonblocking();
-});
-
-const { return_u64_nonblocking } = dylib.symbols;
-Deno.bench("return_u64_nonblocking()", async () => {
- await return_u64_nonblocking();
-});
-
-const { return_i64_nonblocking } = dylib.symbols;
-Deno.bench("return_i64_nonblocking()", async () => {
- await return_i64_nonblocking();
-});
-
-const { return_usize_nonblocking } = dylib.symbols;
-Deno.bench("return_usize_nonblocking()", async () => {
- await return_usize_nonblocking();
-});
-
-const { return_isize_nonblocking } = dylib.symbols;
-Deno.bench("return_isize_nonblocking()", async () => {
- await return_isize_nonblocking();
-});
-
-const { return_f32_nonblocking } = dylib.symbols;
-Deno.bench("return_f32_nonblocking()", async () => {
- await return_f32_nonblocking();
-});
-
-const { return_f64_nonblocking } = dylib.symbols;
-Deno.bench("return_f64_nonblocking()", async () => {
- await return_f64_nonblocking();
-});
-
-const { return_buffer_nonblocking } = dylib.symbols;
-Deno.bench("return_buffer_nonblocking()", async () => {
- await return_buffer_nonblocking();
-});
-
-const { nop_many_parameters } = dylib.symbols;
-const buffer2 = new Uint8Array(8).fill(25);
-Deno.bench("nop_many_parameters()", () => {
- 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,
- );
-});
-
-const { nop_many_parameters_nonblocking } = dylib.symbols;
-Deno.bench("nop_many_parameters_nonblocking()", () => {
- 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,
- );
-});
-
-Deno.bench("Deno.UnsafePointer.of", () => {
- Deno.UnsafePointer.of(buffer);
-});
-
-const cstringBuffer = new TextEncoder().encode("Best believe it!\0");
-const cstringPointerView = new Deno.UnsafePointerView(
- Deno.UnsafePointer.of(cstringBuffer),
-);
-Deno.bench("Deno.UnsafePointerView#getCString", () => {
- cstringPointerView.getCString();
-});
-
-const bufferPointerView = new Deno.UnsafePointerView(
- Deno.UnsafePointer.of(buffer),
-);
-
-Deno.bench("Deno.UnsafePointerView#getBool", () => {
- bufferPointerView.getBool();
-});
-
-Deno.bench("Deno.UnsafePointerView#getUint8", () => {
- bufferPointerView.getUint8();
-});
-
-Deno.bench("Deno.UnsafePointerView#getInt8", () => {
- bufferPointerView.getInt8();
-});
-
-Deno.bench("Deno.UnsafePointerView#getUint16", () => {
- bufferPointerView.getUint16();
-});
-
-Deno.bench("Deno.UnsafePointerView#getInt16", () => {
- bufferPointerView.getInt16();
-});
-
-Deno.bench("Deno.UnsafePointerView#getUint32", () => {
- bufferPointerView.getUint32();
-});
-
-Deno.bench("Deno.UnsafePointerView#getInt32", () => {
- bufferPointerView.getInt32();
-});
-
-Deno.bench("Deno.UnsafePointerView#getBigUint64", () => {
- bufferPointerView.getBigUint64();
-});
-
-Deno.bench("Deno.UnsafePointerView#getBigInt64", () => {
- bufferPointerView.getBigInt64();
-});
-
-Deno.bench("Deno.UnsafePointerView#getFloat32", () => {
- bufferPointerView.getFloat32();
-});
-
-Deno.bench("Deno.UnsafePointerView#getFloat64", () => {
- bufferPointerView.getFloat64();
-});
diff --git a/test_ffi/tests/event_loop_integration.ts b/test_ffi/tests/event_loop_integration.ts
deleted file mode 100644
index d9ada6027..000000000
--- a/test_ffi/tests/event_loop_integration.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-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,
- {
- store_function: {
- parameters: ["function"],
- result: "void",
- },
- call_stored_function: {
- parameters: [],
- result: "void",
- },
- call_stored_function_thread_safe_and_log: {
- parameters: [],
- result: "void",
- },
- } as const,
-);
-
-let retry = false;
-const tripleLogCallback = () => {
- console.log("Sync");
- queueMicrotask(() => {
- console.log("Async");
- callback.unref();
- });
- setTimeout(() => {
- console.log("Timeout");
- callback.unref();
-
- if (retry) {
- // Re-ref and retry the call to make sure re-refing works.
- console.log("RETRY THREAD SAFE");
- retry = false;
- callback.ref();
- dylib.symbols.call_stored_function_thread_safe_and_log();
- }
- }, 100);
-};
-
-const callback = Deno.UnsafeCallback.threadSafe(
- {
- parameters: [],
- result: "void",
- } as const,
- tripleLogCallback,
-);
-
-// Store function
-dylib.symbols.store_function(callback.pointer);
-
-// Synchronous callback logging
-console.log("SYNCHRONOUS");
-// This function only calls the callback, and does not log.
-dylib.symbols.call_stored_function();
-console.log("STORED_FUNCTION called");
-
-// Wait to make sure synch logging and async logging
-await new Promise((res) => setTimeout(res, 200));
-
-// Ref once to make sure both `queueMicrotask()` and `setTimeout()`
-// must resolve and unref before isolate exists.
-// One ref'ing has been done by `threadSafe` constructor.
-callback.ref();
-
-console.log("THREAD SAFE");
-retry = true;
-// This function calls the callback and logs 'STORED_FUNCTION called'
-dylib.symbols.call_stored_function_thread_safe_and_log();
diff --git a/test_ffi/tests/ffi_callback_errors.ts b/test_ffi/tests/ffi_callback_errors.ts
deleted file mode 100644
index dbd60636c..000000000
--- a/test_ffi/tests/ffi_callback_errors.ts
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-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,
- {
- store_function_2: {
- parameters: ["function"],
- result: "void",
- },
- call_stored_function_2: {
- parameters: ["u8"],
- result: "void",
- },
- call_stored_function_2_from_other_thread: {
- name: "call_stored_function_2",
- parameters: ["u8"],
- result: "void",
- nonblocking: true,
- },
- call_stored_function_2_thread_safe: {
- parameters: ["u8"],
- result: "void",
- },
- } as const,
-);
-
-globalThis.addEventListener("error", (data) => {
- console.log("Unhandled error");
- data.preventDefault();
-});
-globalThis.onerror = (data) => {
- console.log("Unhandled error");
- if (typeof data !== "string") {
- data.preventDefault();
- }
-};
-
-globalThis.addEventListener("unhandledrejection", (data) => {
- console.log("Unhandled rejection");
- data.preventDefault();
-});
-
-const timer = setTimeout(() => {
- console.error(
- "Test failed, final callback did not get picked up by Deno event loop",
- );
- Deno.exit(-1);
-}, 5_000);
-
-Deno.unrefTimer(timer);
-
-enum CallCase {
- SyncSelf,
- SyncFfi,
- AsyncSelf,
- AsyncSyncFfi,
- AsyncFfi,
-}
-type U8CallCase = Deno.NativeU8Enum<CallCase>;
-
-const throwCb = (c: CallCase): number => {
- console.log("CallCase:", CallCase[c]);
- if (c === CallCase.AsyncFfi) {
- cb.unref();
- }
- throw new Error("Error");
-};
-
-const THROW_CB_DEFINITION = {
- parameters: ["u8" as U8CallCase],
- result: "u8",
-} as const;
-
-const cb = new Deno.UnsafeCallback(THROW_CB_DEFINITION, throwCb);
-
-try {
- const fnPointer = new Deno.UnsafeFnPointer(cb.pointer, THROW_CB_DEFINITION);
-
- fnPointer.call(CallCase.SyncSelf);
-} catch (_err) {
- console.log(
- "Throwing errors from an UnsafeCallback called from a synchronous UnsafeFnPointer works. Terribly excellent.",
- );
-}
-
-dylib.symbols.store_function_2(cb.pointer);
-try {
- dylib.symbols.call_stored_function_2(CallCase.SyncFfi);
-} catch (_err) {
- console.log(
- "Throwing errors from an UnsafeCallback called from a synchronous FFI symbol works. Terribly excellent.",
- );
-}
-
-try {
- const fnPointer = new Deno.UnsafeFnPointer(cb.pointer, {
- ...THROW_CB_DEFINITION,
- nonblocking: true,
- });
- await fnPointer.call(CallCase.AsyncSelf);
-} catch (err) {
- throw new Error(
- "Nonblocking UnsafeFnPointer should not be threading through a JS error thrown on the other side of the call",
- {
- cause: err,
- },
- );
-}
-
-try {
- await dylib.symbols.call_stored_function_2_from_other_thread(
- CallCase.AsyncSyncFfi,
- );
-} catch (err) {
- throw new Error(
- "Nonblocking symbol call should not be threading through a JS error thrown on the other side of the call",
- {
- cause: err,
- },
- );
-}
-try {
- // Ref the callback to make sure we do not exit before the call is done.
- cb.ref();
- dylib.symbols.call_stored_function_2_thread_safe(CallCase.AsyncFfi);
-} catch (err) {
- throw new Error(
- "Blocking symbol call should not be travelling 1.5 seconds forward in time to figure out that it call will trigger a JS error to be thrown",
- {
- cause: err,
- },
- );
-}
diff --git a/test_ffi/tests/ffi_types.ts b/test_ffi/tests/ffi_types.ts
deleted file mode 100644
index 596662873..000000000
--- a/test_ffi/tests/ffi_types.ts
+++ /dev/null
@@ -1,529 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-// deno-lint-ignore-file
-// Only for testing types. Invoke with `deno cache`
-
-const remote = Deno.dlopen(
- "dummy_lib.so",
- {
- method1: { parameters: ["usize", "bool"], result: "void", callback: true },
- method2: { parameters: [], result: "void" },
- method3: { parameters: ["usize"], result: "void" },
- method4: { parameters: ["isize"], result: "void" },
- method5: { parameters: ["u8"], result: "void" },
- method6: { parameters: ["u16"], result: "void" },
- method7: { parameters: ["u32"], result: "void" },
- method8: { parameters: ["u64"], result: "void" },
- method9: { parameters: ["i8"], result: "void" },
- method10: { parameters: ["i16"], result: "void" },
- method11: { parameters: ["i32"], result: "void" },
- method12: { parameters: ["i64"], result: "void" },
- method13: { parameters: ["f32"], result: "void" },
- method14: { parameters: ["f64"], result: "void" },
- method15: { parameters: ["pointer"], result: "void" },
- method16: { parameters: [], result: "usize" },
- method17: { parameters: [], result: "usize", nonblocking: true },
- method18: { parameters: [], result: "pointer" },
- method19: { parameters: [], result: "pointer", nonblocking: true },
- method20: {
- parameters: ["pointer"],
- result: "void",
- },
- method21: {
- parameters: [
- "pointer",
- ],
- result: "void",
- },
- method22: {
- parameters: ["pointer"],
- result: "void",
- },
- method23: {
- parameters: ["buffer"],
- result: "void",
- },
- method24: {
- parameters: ["bool"],
- result: "bool",
- },
- method25: {
- parameters: [],
- result: "void",
- optional: true,
- },
- static1: { type: "usize" },
- static2: { type: "pointer" },
- static3: { type: "usize" },
- static4: { type: "isize" },
- static5: { type: "u8" },
- static6: { type: "u16" },
- static7: { type: "u32" },
- static8: { type: "u64" },
- static9: { type: "i8" },
- static10: { type: "i16" },
- static11: { type: "i32" },
- static12: { type: "i64" },
- static13: { type: "f32" },
- static14: { type: "f64" },
- static15: { type: "bool" },
- static16: {
- type: "bool",
- optional: true,
- },
- },
-);
-
-Deno.dlopen(
- "dummy_lib_2.so",
- {
- wrong_method1: {
- parameters: [],
- result: "function",
- },
- },
-);
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method1(0);
-// @ts-expect-error: Invalid argument
-remote.symbols.method1(0, 0);
-// @ts-expect-error: Invalid argument
-remote.symbols.method1(true, true);
-// @ts-expect-error: Invalid return type
-<number> remote.symbols.method1(0, true);
-<void> remote.symbols.method1(0n, true);
-
-// @ts-expect-error: Expected 0 arguments, but got 1.
-remote.symbols.method2(null);
-remote.symbols.method2();
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method3(null);
-remote.symbols.method3(0n);
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method4(null);
-remote.symbols.method4(0n);
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method5(null);
-remote.symbols.method5(0);
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method6(null);
-remote.symbols.method6(0);
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method7(null);
-remote.symbols.method7(0);
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method8(null);
-remote.symbols.method8(0n);
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method9(null);
-remote.symbols.method9(0);
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method10(null);
-remote.symbols.method10(0);
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method11(null);
-remote.symbols.method11(0);
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method12(null);
-remote.symbols.method12(0n);
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method13(null);
-remote.symbols.method13(0);
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method14(null);
-remote.symbols.method14(0);
-
-// @ts-expect-error: Invalid argument
-remote.symbols.method15("foo");
-// @ts-expect-error: Invalid argument
-remote.symbols.method15(new Uint16Array(1));
-remote.symbols.method15(null);
-remote.symbols.method15({} as Deno.PointerValue);
-
-const result = remote.symbols.method16();
-// @ts-expect-error: Invalid argument
-let r_0: string = result;
-let r_1: number | bigint = result;
-
-const result2 = remote.symbols.method17();
-// @ts-expect-error: Invalid argument
-result2.then((_0: string) => {});
-result2.then((_1: number | bigint) => {});
-
-const result3 = remote.symbols.method18();
-// @ts-expect-error: Invalid argument
-let r3_0: Deno.BufferSource = result3;
-let r3_1: null | Deno.UnsafePointer = result3;
-
-const result4 = remote.symbols.method19();
-// @ts-expect-error: Invalid argument
-result4.then((_0: Deno.BufferSource) => {});
-result4.then((_1: null | Deno.UnsafePointer) => {});
-
-const fnptr = new Deno.UnsafeFnPointer(
- {} as Deno.PointerObject,
- {
- parameters: ["u32", "pointer"],
- result: "void",
- },
-);
-// @ts-expect-error: Invalid argument
-fnptr.call(null, null);
-fnptr.call(0, null);
-
-const unsafe_callback_wrong1 = new Deno.UnsafeCallback(
- {
- parameters: ["i8"],
- result: "void",
- },
- // @ts-expect-error: i8 is not a pointer
- (_: bigint) => {},
-);
-const unsafe_callback_wrong2 = new Deno.UnsafeCallback(
- {
- parameters: ["pointer"],
- result: "u64",
- },
- // @ts-expect-error: must return a number or bigint
- (_: Deno.UnsafePointer) => {},
-);
-const unsafe_callback_wrong3 = new Deno.UnsafeCallback(
- {
- parameters: [],
- result: "void",
- },
- // @ts-expect-error: no parameters
- (_: Deno.UnsafePointer) => {},
-);
-const unsafe_callback_wrong4 = new Deno.UnsafeCallback(
- {
- parameters: ["u64"],
- result: "void",
- },
- // @ts-expect-error: Callback's 64bit parameters are either number or bigint
- (_: number) => {},
-);
-const unsafe_callback_right1 = new Deno.UnsafeCallback(
- {
- parameters: ["u8", "u32", "pointer"],
- result: "void",
- },
- (_1: number, _2: number, _3: null | Deno.PointerValue) => {},
-);
-const unsafe_callback_right2 = new Deno.UnsafeCallback(
- {
- parameters: [],
- result: "u8",
- },
- () => 3,
-);
-const unsafe_callback_right3 = new Deno.UnsafeCallback(
- {
- parameters: [],
- result: "function",
- },
- // Callbacks can return other callbacks' pointers, if really wanted.
- () => unsafe_callback_right2.pointer,
-);
-const unsafe_callback_right4 = new Deno.UnsafeCallback(
- {
- parameters: ["u8", "u32", "pointer"],
- result: "u8",
- },
- (_1: number, _2: number, _3: null | Deno.PointerValue) => 3,
-);
-const unsafe_callback_right5 = new Deno.UnsafeCallback(
- {
- parameters: ["u8", "i32", "pointer"],
- result: "void",
- },
- (_1: number, _2: number, _3: null | Deno.PointerValue) => {},
-);
-
-// @ts-expect-error: Must pass callback
-remote.symbols.method20();
-// nullptr is okay
-remote.symbols.method20(null);
-// @ts-expect-error: Callback cannot be passed directly
-remote.symbols.method20(unsafe_callback_right2);
-remote.symbols.method20(unsafe_callback_right1.pointer);
-
-remote.symbols.method23(new Uint8Array(1));
-remote.symbols.method23(new Uint32Array(1));
-remote.symbols.method23(new Uint8Array(1));
-
-// @ts-expect-error: Cannot pass pointer values as buffer.
-remote.symbols.method23({});
-// @ts-expect-error: Cannot pass pointer values as buffer.
-remote.symbols.method23({});
-remote.symbols.method23(null);
-
-// @ts-expect-error: Cannot pass number as bool.
-remote.symbols.method24(0);
-// @ts-expect-error: Cannot pass number as bool.
-remote.symbols.method24(1);
-// @ts-expect-error: Cannot pass null as bool.
-remote.symbols.method24(null);
-remote.symbols.method24(true);
-remote.symbols.method24(false);
-// @ts-expect-error: Cannot assert return type as a number.
-<number> remote.symbols.method24(true);
-// @ts-expect-error: Cannot assert return type truthiness.
-let r24_0: true = remote.symbols.method24(true);
-// @ts-expect-error: Cannot assert return type as a number.
-let r42_1: number = remote.symbols.method24(true);
-<boolean> remote.symbols.method24(Math.random() > 0.5);
-
-// @ts-expect-error: Optional symbol; can be null.
-remote.symbols.method25();
-
-// @ts-expect-error: Invalid member type
-const static1_wrong: null = remote.symbols.static1;
-const static1_right: number | bigint = remote.symbols.static1;
-// @ts-expect-error: Invalid member type
-const static2_wrong: null = remote.symbols.static2;
-const static2_right: null | Deno.UnsafePointer = remote.symbols.static2;
-// @ts-expect-error: Invalid member type
-const static3_wrong: null = remote.symbols.static3;
-const static3_right: number | bigint = remote.symbols.static3;
-// @ts-expect-error: Invalid member type
-const static4_wrong: null = remote.symbols.static4;
-const static4_right: number | bigint = remote.symbols.static4;
-// @ts-expect-error: Invalid member type
-const static5_wrong: null = remote.symbols.static5;
-const static5_right: number = remote.symbols.static5;
-// @ts-expect-error: Invalid member type
-const static6_wrong: null = remote.symbols.static6;
-const static6_right: number = remote.symbols.static6;
-// @ts-expect-error: Invalid member type
-const static7_wrong: null = remote.symbols.static7;
-const static7_right: number = remote.symbols.static7;
-// @ts-expect-error: Invalid member type
-const static8_wrong: null = remote.symbols.static8;
-const static8_right: number | bigint = remote.symbols.static8;
-// @ts-expect-error: Invalid member type
-const static9_wrong: null = remote.symbols.static9;
-const static9_right: number = remote.symbols.static9;
-// @ts-expect-error: Invalid member type
-const static10_wrong: null = remote.symbols.static10;
-const static10_right: number = remote.symbols.static10;
-// @ts-expect-error: Invalid member type
-const static11_wrong: null = remote.symbols.static11;
-const static11_right: number = remote.symbols.static11;
-// @ts-expect-error: Invalid member type
-const static12_wrong: null = remote.symbols.static12;
-const static12_right: number | bigint = remote.symbols.static12;
-// @ts-expect-error: Invalid member type
-const static13_wrong: null = remote.symbols.static13;
-const static13_right: number = remote.symbols.static13;
-// @ts-expect-error: Invalid member type
-const static14_wrong: null = remote.symbols.static14;
-const static14_right: number = remote.symbols.static14;
-// @ts-expect-error: Invalid member type
-const static15_wrong: number = remote.symbols.static15;
-const static15_right: boolean = remote.symbols.static15;
-// @ts-expect-error: Invalid member type
-const static16_wrong: boolean = remote.symbols.static16;
-const static16_right: boolean | null = remote.symbols.static16;
-
-// Adapted from https://stackoverflow.com/a/53808212/10873797
-type Equal<T, U> = (<G>() => G extends T ? 1 : 2) extends
- (<G>() => G extends U ? 1 : 2) ? true
- : false;
-
-type AssertEqual<
- Expected extends $,
- Got extends $$,
- $ = [Equal<Got, Expected>] extends [true] ? Expected
- : ([Expected] extends [Got] ? never : Got),
- $$ = [Equal<Expected, Got>] extends [true] ? Got
- : ([Got] extends [Expected] ? never : Got),
-> = never;
-
-type AssertNotEqual<
- Expected extends $,
- Got,
- $ = [Equal<Expected, Got>] extends [true] ? never : Expected,
-> = never;
-
-const enum FooEnum {
- Foo,
- Bar,
-}
-const foo = "u8" as Deno.NativeU8Enum<FooEnum>;
-
-declare const brand: unique symbol;
-class MyPointerClass {}
-type MyPointer = Deno.PointerObject & { [brand]: MyPointerClass };
-const myPointer = "pointer" as Deno.NativeTypedPointer<MyPointer>;
-type MyFunctionDefinition = Deno.UnsafeCallbackDefinition<
- [typeof foo, "u32"],
- typeof myPointer
->;
-const myFunction = "function" as Deno.NativeTypedFunction<
- MyFunctionDefinition
->;
-
-type __Tests__ = [
- empty: AssertEqual<
- { symbols: Record<never, never>; close(): void },
- Deno.DynamicLibrary<Record<never, never>>
- >,
- basic: AssertEqual<
- { symbols: { add: (n1: number, n2: number) => number }; close(): void },
- Deno.DynamicLibrary<{ add: { parameters: ["i32", "u8"]; result: "i32" } }>
- >,
- higher_order_params: AssertEqual<
- {
- symbols: {
- pushBuf: (
- buf: BufferSource | null,
- ptr: Deno.PointerValue | null,
- func: Deno.PointerValue | null,
- ) => void;
- };
- close(): void;
- },
- Deno.DynamicLibrary<
- {
- pushBuf: {
- parameters: ["buffer", "pointer", "function"];
- result: "void";
- };
- }
- >
- >,
- higher_order_returns: AssertEqual<
- {
- symbols: {
- pushBuf: (
- buf: BufferSource | null,
- ptr: Deno.PointerValue,
- func: Deno.PointerValue,
- ) => Deno.PointerValue;
- };
- close(): void;
- },
- Deno.DynamicLibrary<
- {
- pushBuf: {
- parameters: ["buffer", "pointer", "function"];
- result: "pointer";
- };
- }
- >
- >,
- non_exact_params: AssertEqual<
- {
- symbols: {
- foo: (
- ...args: (number | Deno.PointerValue | null)[]
- ) => number | bigint;
- };
- close(): void;
- },
- Deno.DynamicLibrary<
- { foo: { parameters: ("i32" | "pointer")[]; result: "u64" } }
- >
- >,
- non_exact_params_empty: AssertEqual<
- {
- symbols: {
- foo: () => number;
- };
- close(): void;
- },
- Deno.DynamicLibrary<
- { foo: { parameters: []; result: "i32" } }
- >
- >,
- non_exact_params_empty: AssertNotEqual<
- {
- symbols: {
- foo: (a: number) => number;
- };
- close(): void;
- },
- Deno.DynamicLibrary<
- { foo: { parameters: []; result: "i32" } }
- >
- >,
- enum_param: AssertEqual<
- {
- symbols: {
- foo: (arg: FooEnum) => void;
- };
- close(): void;
- },
- Deno.DynamicLibrary<
- { foo: { parameters: [typeof foo]; result: "void" } }
- >
- >,
- enum_return: AssertEqual<
- {
- symbols: {
- foo: () => FooEnum;
- };
- close(): void;
- },
- Deno.DynamicLibrary<
- { foo: { parameters: []; result: typeof foo } }
- >
- >,
- typed_pointer_param: AssertEqual<
- {
- symbols: {
- foo: (arg: MyPointer | null) => void;
- };
- close(): void;
- },
- Deno.DynamicLibrary<
- { foo: { parameters: [typeof myPointer]; result: "void" } }
- >
- >,
- typed_pointer_return: AssertEqual<
- {
- symbols: {
- foo: () => MyPointer | null;
- };
- close(): void;
- },
- Deno.DynamicLibrary<
- { foo: { parameters: []; result: typeof myPointer } }
- >
- >,
- typed_function_param: AssertEqual<
- {
- symbols: {
- foo: (arg: Deno.PointerObject<MyFunctionDefinition> | null) => void;
- };
- close(): void;
- },
- Deno.DynamicLibrary<
- { foo: { parameters: [typeof myFunction]; result: "void" } }
- >
- >,
- typed_function_return: AssertEqual<
- {
- symbols: {
- foo: () => Deno.PointerObject<MyFunctionDefinition> | null;
- };
- close(): void;
- },
- Deno.DynamicLibrary<
- { foo: { parameters: []; result: typeof myFunction } }
- >
- >,
-];
diff --git a/test_ffi/tests/integration_tests.rs b/test_ffi/tests/integration_tests.rs
deleted file mode 100644
index 642fbed03..000000000
--- a/test_ffi/tests/integration_tests.rs
+++ /dev/null
@@ -1,280 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-use pretty_assertions::assert_eq;
-use std::process::Command;
-use test_util::deno_cmd;
-
-#[cfg(debug_assertions)]
-const BUILD_VARIANT: &str = "debug";
-
-#[cfg(not(debug_assertions))]
-const BUILD_VARIANT: &str = "release";
-
-fn build() {
- let mut build_plugin_base = Command::new("cargo");
- let mut build_plugin =
- build_plugin_base.arg("build").arg("-p").arg("test_ffi");
- if BUILD_VARIANT == "release" {
- build_plugin = build_plugin.arg("--release");
- }
- let build_plugin_output = build_plugin.output().unwrap();
- assert!(build_plugin_output.status.success());
-}
-
-#[test]
-fn basic() {
- build();
-
- let output = deno_cmd()
- .arg("run")
- .arg("--allow-ffi")
- .arg("--allow-read")
- .arg("--unstable-ffi")
- .arg("--quiet")
- .arg(r#"--v8-flags=--allow-natives-syntax"#)
- .arg("tests/test.js")
- .env("NO_COLOR", "1")
- .output()
- .unwrap();
- let stdout = std::str::from_utf8(&output.stdout).unwrap();
- let stderr = std::str::from_utf8(&output.stderr).unwrap();
- if !output.status.success() {
- println!("stdout {stdout}");
- println!("stderr {stderr}");
- }
- println!("{:?}", output.status);
- assert!(output.status.success());
- let expected = "\
- something\n\
- [1, 2, 3, 4, 5, 6, 7, 8]\n\
- [4, 5, 6]\n\
- [1, 2, 3, 4, 5, 6, 7, 8] [9, 10]\n\
- [1, 2, 3, 4, 5, 6, 7, 8]\n\
- [ 1, 2, 3, 4, 5, 6 ]\n\
- [ 4, 5, 6 ]\n\
- [ 4, 5, 6 ]\n\
- Hello from pointer!\n\
- pointer!\n\
- false false\n\
- true true\n\
- false false\n\
- true true\n\
- false false\n\
- 579\n\
- true\n\
- 579\n\
- 579\n\
- 5\n\
- 5\n\
- 579\n\
- 8589934590\n\
- -8589934590\n\
- 8589934590\n\
- -8589934590\n\
- 9007199254740992n\n\
- 9007199254740992n\n\
- -9007199254740992n\n\
- 9007199254740992n\n\
- 9007199254740992n\n\
- -9007199254740992n\n\
- 579.9119873046875\n\
- 579.912\n\
- true\n\
- false\n\
- 579.9119873046875\n\
- 579.9119873046875\n\
- 579.912\n\
- 579.912\n\
- 579\n\
- 8589934590\n\
- -8589934590\n\
- 8589934590\n\
- -8589934590\n\
- 9007199254740992n\n\
- 9007199254740992n\n\
- -9007199254740992n\n\
- 9007199254740992n\n\
- 9007199254740992n\n\
- -9007199254740992n\n\
- 579.9119873046875\n\
- 579.912\n\
- Before\n\
- After\n\
- logCallback\n\
- 1 -1 2 -2 3 -3 4 -4 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\
- 255 65535 4294967295 4294967296 123.456 789.876 -1 -2 -3 -4 -1000 1000 12345.67891 12345.679 12345.67891 12345.679 12345.67891 12345.679 12345.67891\n\
- 255 65535 4294967295 4294967296 123.456 789.876 -1 -2 -3 -4 -1000 1000 12345.67891 12345.679 12345.67891 12345.679 12345.67891 12345.679 12345.67891\n\
- 0\n\
- 0\n\
- 0\n\
- 0\n\
- 78\n\
- 78\n\
- STORED_FUNCTION cleared\n\
- STORED_FUNCTION_2 cleared\n\
- logCallback\n\
- u8: 8\n\
- Rect { x: 10.0, y: 20.0, w: 100.0, h: 200.0 }\n\
- Rect { x: 10.0, y: 20.0, w: 100.0, h: 200.0 }\n\
- Rect { x: 20.0, y: 20.0, w: 100.0, h: 200.0 }\n\
- Mixed { u8: 3, f32: 12.515, rect: Rect { x: 10.0, y: 20.0, w: 100.0, h: 200.0 }, usize: 12456789, array: [8, 32] }\n\
- 2264956937\n\
- 2264956937\n\
- Correct number of resources\n";
- assert_eq!(stdout, expected);
- assert_eq!(stderr, "");
-}
-
-#[test]
-fn symbol_types() {
- build();
-
- let output = deno_cmd()
- .arg("check")
- .arg("--unstable-ffi")
- .arg("--quiet")
- .arg("tests/ffi_types.ts")
- .env("NO_COLOR", "1")
- .output()
- .unwrap();
- let stdout = std::str::from_utf8(&output.stdout).unwrap();
- let stderr = std::str::from_utf8(&output.stderr).unwrap();
- if !output.status.success() {
- println!("stdout {stdout}");
- println!("stderr {stderr}");
- }
- println!("{:?}", output.status);
- assert!(output.status.success());
- assert_eq!(stderr, "");
-}
-
-#[test]
-fn thread_safe_callback() {
- build();
-
- let output = deno_cmd()
- .arg("run")
- .arg("--allow-ffi")
- .arg("--allow-read")
- .arg("--unstable-ffi")
- .arg("--quiet")
- .arg("tests/thread_safe_test.js")
- .env("NO_COLOR", "1")
- .output()
- .unwrap();
- let stdout = std::str::from_utf8(&output.stdout).unwrap();
- let stderr = std::str::from_utf8(&output.stderr).unwrap();
- if !output.status.success() {
- println!("stdout {stdout}");
- println!("stderr {stderr}");
- }
- println!("{:?}", output.status);
- assert!(output.status.success());
- let expected = "\
- Callback on main thread\n\
- Callback on worker thread\n\
- STORED_FUNCTION cleared\n\
- Calling callback, isolate should stay asleep until callback is called\n\
- Callback being called\n\
- STORED_FUNCTION cleared\n\
- Isolate should now exit\n";
- assert_eq!(stdout, expected);
- assert_eq!(stderr, "");
-}
-
-#[test]
-fn event_loop_integration() {
- build();
-
- let output = deno_cmd()
- .arg("run")
- .arg("--allow-ffi")
- .arg("--allow-read")
- .arg("--unstable-ffi")
- .arg("--quiet")
- .arg("tests/event_loop_integration.ts")
- .env("NO_COLOR", "1")
- .output()
- .unwrap();
- let stdout = std::str::from_utf8(&output.stdout).unwrap();
- let stderr = std::str::from_utf8(&output.stderr).unwrap();
- if !output.status.success() {
- println!("stdout {stdout}");
- println!("stderr {stderr}");
- }
- println!("{:?}", output.status);
- assert!(output.status.success());
- // TODO(aapoalas): The order of logging in thread safe callbacks is
- // unexpected: The callback logs synchronously and creates an asynchronous
- // logging task, which then gets called synchronously before the callback
- // actually yields to the calling thread. This is in contrast to what the
- // logging would look like if the call was coming from within Deno itself,
- // and may lead users to unknowingly run heavy asynchronous tasks from thread
- // safe callbacks synchronously.
- // The fix would be to make sure microtasks are only run after the event loop
- // middleware that polls them has completed its work. This just does not seem
- // to work properly with Linux release builds.
- let expected = "\
- SYNCHRONOUS\n\
- Sync\n\
- STORED_FUNCTION called\n\
- Async\n\
- Timeout\n\
- THREAD SAFE\n\
- Sync\n\
- Async\n\
- STORED_FUNCTION called\n\
- Timeout\n\
- RETRY THREAD SAFE\n\
- Sync\n\
- Async\n\
- STORED_FUNCTION called\n\
- Timeout\n";
- assert_eq!(stdout, expected);
- assert_eq!(stderr, "");
-}
-
-#[test]
-fn ffi_callback_errors_test() {
- build();
-
- let output = deno_cmd()
- .arg("run")
- .arg("--allow-ffi")
- .arg("--allow-read")
- .arg("--unstable-ffi")
- .arg("--quiet")
- .arg("tests/ffi_callback_errors.ts")
- .env("NO_COLOR", "1")
- .output()
- .unwrap();
- let stdout = std::str::from_utf8(&output.stdout).unwrap();
- let stderr = std::str::from_utf8(&output.stderr).unwrap();
- if !output.status.success() {
- println!("stdout {stdout}");
- println!("stderr {stderr}");
- }
- println!("{:?}", output.status);
- assert!(output.status.success());
-
- let expected = "\
- CallCase: SyncSelf\n\
- Throwing errors from an UnsafeCallback called from a synchronous UnsafeFnPointer works. Terribly excellent.\n\
- CallCase: SyncFfi\n\
- 0\n\
- Throwing errors from an UnsafeCallback called from a synchronous FFI symbol works. Terribly excellent.\n\
- CallCase: AsyncSelf\n\
- CallCase: AsyncSyncFfi\n\
- 0\n\
- Calling\n\
- CallCase: AsyncFfi\n";
- assert_eq!(stdout, expected);
- assert_eq!(
- stderr,
- "Illegal unhandled exception in nonblocking callback.\n".repeat(3)
- );
-}
diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js
deleted file mode 100644
index 8e57cd34b..000000000
--- a/test_ffi/tests/test.js
+++ /dev/null
@@ -1,802 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-// deno-lint-ignore-file
-
-// Run using cargo test or `--v8-flags=--allow-natives-syntax`
-
-import {
- assertThrows,
- assert,
- assertNotEquals,
- assertInstanceOf,
- assertEquals,
- assertFalse,
-} from "../../test_util/std/assert/mod.ts";
-
-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 resourcesPre = Deno[Deno.internal].core.resources();
-
-// dlopen shouldn't panic
-assertThrows(() => {
- Deno.dlopen("cli/src/main.rs", {});
-});
-
-assertThrows(
- () => {
- Deno.dlopen(libPath, {
- non_existent_symbol: {
- parameters: [],
- result: "void",
- },
- });
- },
- Error,
- "Failed to register symbol non_existent_symbol",
-);
-
-assertThrows(() => {
- Deno.dlopen(libPath, {
- print_something: {
- parameters: [],
- result: { struct: [] }
- },
- }),
- TypeError,
- "Struct must have at least one field"
-});
-
-assertThrows(() => {
- Deno.dlopen(libPath, {
- print_something: {
- parameters: [ { struct: [] } ],
- result: "void",
- },
- }),
- TypeError,
- "Struct must have at least one field"
-});
-
-const Empty = { struct: [] }
-assertThrows(() => {
- Deno.dlopen(libPath, {
- print_something: {
- parameters: [ { struct: [Empty] } ],
- result: "void",
- },
- }),
- TypeError,
- "Struct must have at least one field"
-});
-
-const Point = ["f64", "f64"];
-const Size = ["f64", "f64"];
-const Rect = ["f64", "f64", "f64", "f64"];
-const RectNested = [{ struct: Point }, { struct: Size }];
-const RectNestedCached = [{ struct: Size }, { struct: Size }];
-const Mixed = ["u8", "f32", { struct: Rect }, "usize", { struct: ["u32", "u32"] }];
-
-const dylib = Deno.dlopen(libPath, {
- "printSomething": {
- name: "print_something",
- parameters: [],
- result: "void",
- },
- "print_buffer": { parameters: ["buffer", "usize"], result: "void" },
- "print_pointer": { name: "print_buffer", parameters: ["pointer", "usize"], result: "void" },
- "print_buffer2": {
- parameters: ["buffer", "usize", "buffer", "usize"],
- result: "void",
- },
- "return_buffer": { parameters: [], result: "buffer" },
- "is_null_ptr": { parameters: ["pointer"], result: "bool" },
- "is_null_buf": { name: "is_null_ptr", parameters: ["buffer"], result: "bool" },
- "add_u32": { parameters: ["u32", "u32"], result: "u32" },
- "add_i32": { parameters: ["i32", "i32"], result: "i32" },
- "add_u64": { parameters: ["u64", "u64"], result: "u64" },
- "add_i64": { parameters: ["i64", "i64"], result: "i64" },
- "add_usize": { parameters: ["usize", "usize"], result: "usize" },
- "add_usize_fast": { parameters: ["usize", "usize"], result: "u32" },
- "add_isize": { parameters: ["isize", "isize"], result: "isize" },
- "add_f32": { parameters: ["f32", "f32"], result: "f32" },
- "add_f64": { parameters: ["f64", "f64"], result: "f64" },
- "and": { parameters: ["bool", "bool"], result: "bool" },
- "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", "buffer", "usize"], result: "void" },
- "sleep_nonblocking": {
- name: "sleep_blocking",
- parameters: ["u64"],
- result: "void",
- nonblocking: true,
- },
- "sleep_blocking": { parameters: ["u64"], result: "void" },
- "nonblocking_buffer": {
- parameters: ["buffer", "usize"],
- result: "void",
- nonblocking: true,
- },
- "get_add_u32_ptr": {
- parameters: [],
- result: "pointer",
- },
- "get_sleep_blocking_ptr": {
- parameters: [],
- result: "pointer",
- },
- // Callback function
- call_fn_ptr: {
- parameters: ["function"],
- result: "void",
- },
- call_fn_ptr_thread_safe: {
- name: "call_fn_ptr",
- parameters: ["function"],
- result: "void",
- nonblocking: true,
- },
- call_fn_ptr_many_parameters: {
- parameters: ["function"],
- result: "void",
- },
- call_fn_ptr_return_u8: {
- parameters: ["function"],
- result: "void",
- },
- call_fn_ptr_return_u8_thread_safe: {
- name: "call_fn_ptr_return_u8",
- parameters: ["function"],
- result: "void",
- },
- call_fn_ptr_return_buffer: {
- parameters: ["function"],
- result: "void",
- },
- store_function: {
- parameters: ["function"],
- result: "void",
- },
- store_function_2: {
- parameters: ["function"],
- result: "void",
- },
- call_stored_function: {
- parameters: [],
- result: "void",
- callback: true,
- },
- call_stored_function_2: {
- parameters: ["u8"],
- result: "void",
- callback: true,
- },
- log_many_parameters: {
- parameters: ["u8", "u16", "u32", "u64", "f64", "f32", "i64", "i32", "i16", "i8", "isize", "usize", "f64", "f32", "f64", "f32", "f64", "f32", "f64"],
- result: "void",
- },
- cast_u8_u32: {
- parameters: ["u8"],
- result: "u32",
- },
- cast_u32_u8: {
- parameters: ["u32"],
- result: "u8",
- },
- add_many_u16: {
- parameters: ["u16", "u16", "u16", "u16", "u16", "u16", "u16", "u16", "u16", "u16", "u16", "u16", "u16"],
- result: "u16",
- },
- // Statics
- "static_u32": {
- type: "u32",
- },
- "static_i64": {
- type: "i64",
- },
- "static_ptr": {
- type: "pointer",
- },
- /**
- * Invalid UTF-8 characters, buffer of length 14
- */
- "static_char": {
- type: "pointer",
- optional: true,
- },
- "hash": { parameters: ["buffer", "u32"], result: "u32" },
- make_rect: {
- parameters: ["f64", "f64", "f64", "f64"],
- result: { struct: Rect },
- },
- make_rect_async: {
- name: "make_rect",
- nonblocking: true,
- parameters: ["f64", "f64", "f64", "f64"],
- result: { struct: RectNested },
- },
- print_rect: {
- parameters: [{ struct: RectNestedCached }],
- result: "void",
- },
- print_rect_async: {
- name: "print_rect",
- nonblocking: true,
- parameters: [{ struct: Rect }],
- result: "void",
- },
- create_mixed: {
- parameters: ["u8", "f32", { struct: Rect }, "pointer", "buffer"],
- result: { struct: Mixed }
- },
- print_mixed: {
- parameters: [{ struct: Mixed }],
- result: "void",
- optional: true,
- },
- non_existent_symbol: {
- parameters: [],
- result: "void",
- optional: true,
- },
- non_existent_nonblocking_symbol: {
- parameters: [],
- result: "void",
- nonblocking: true,
- optional: true,
- },
- non_existent_static: {
- type: "u32",
- optional: true,
- },
-});
-const { symbols } = dylib;
-
-symbols.printSomething();
-const buffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
-const buffer2 = new Uint8Array([9, 10]);
-dylib.symbols.print_buffer(buffer, buffer.length);
-// Test subarrays
-const subarray = buffer.subarray(3);
-dylib.symbols.print_buffer(subarray, subarray.length - 2);
-dylib.symbols.print_buffer2(buffer, buffer.length, buffer2, buffer2.length);
-
-const { return_buffer } = symbols;
-function returnBuffer() { return return_buffer(); };
-
-%PrepareFunctionForOptimization(returnBuffer);
-returnBuffer();
-%OptimizeFunctionOnNextCall(returnBuffer);
-const ptr0 = returnBuffer();
-assertIsOptimized(returnBuffer);
-
-dylib.symbols.print_pointer(ptr0, 8);
-const ptrView = new Deno.UnsafePointerView(ptr0);
-const into = new Uint8Array(6);
-const into2 = new Uint8Array(3);
-const into2ptr = Deno.UnsafePointer.of(into2);
-const into2ptrView = new Deno.UnsafePointerView(into2ptr);
-const into3 = new Uint8Array(3);
-const into4 = new Uint16Array(3);
-ptrView.copyInto(into4);
-ptrView.copyInto(into);
-console.log([...into]);
-ptrView.copyInto(into2, 3);
-console.log([...into2]);
-into2ptrView.copyInto(into3);
-console.log([...into3]);
-const string = new Uint8Array([
- ...new TextEncoder().encode("Hello from pointer!"),
- 0,
-]);
-const stringPtr = Deno.UnsafePointer.of(string);
-const stringPtrview = new Deno.UnsafePointerView(stringPtr);
-console.log(stringPtrview.getCString());
-console.log(stringPtrview.getCString(11));
-console.log("false", dylib.symbols.is_null_ptr(ptr0));
-console.log("true", dylib.symbols.is_null_ptr(null));
-console.log("false", dylib.symbols.is_null_ptr(Deno.UnsafePointer.of(into)));
-const emptyBuffer = new Uint8Array(0);
-console.log("true", dylib.symbols.is_null_ptr(Deno.UnsafePointer.of(emptyBuffer)));
-const emptySlice = into.subarray(6);
-console.log("false", dylib.symbols.is_null_ptr(Deno.UnsafePointer.of(emptySlice)));
-
-const { is_null_buf } = symbols;
-function isNullBuffer(buffer) { return is_null_buf(buffer); };
-function isNullBufferDeopt(buffer) { return is_null_buf(buffer); };
-%PrepareFunctionForOptimization(isNullBuffer);
-isNullBuffer(emptyBuffer);
-%NeverOptimizeFunction(isNullBufferDeopt);
-%OptimizeFunctionOnNextCall(isNullBuffer);
-isNullBuffer(emptyBuffer);
-assertIsOptimized(isNullBuffer);
-
-// ==== ZERO LENGTH BUFFER TESTS ====
-assertEquals(isNullBuffer(emptyBuffer), true, "isNullBuffer(emptyBuffer) !== true");
-assertEquals(isNullBufferDeopt(emptyBuffer), true, "isNullBufferDeopt(emptyBuffer) !== true");
-assertEquals(isNullBuffer(emptySlice), false, "isNullBuffer(emptySlice) !== false");
-assertEquals(isNullBufferDeopt(emptySlice), false, "isNullBufferDeopt(emptySlice) !== false");
-assertEquals(isNullBufferDeopt(new Uint8Array()), true, "isNullBufferDeopt(new Uint8Array()) !== true");
-
-// ==== V8 ZERO LENGTH BUFFER ANOMALIES ====
-
-// V8 bug: inline Uint8Array creation to fast call sees non-null pointer
-// https://bugs.chromium.org/p/v8/issues/detail?id=13489
-if (Deno.build.os != "linux" || Deno.build.arch != "aarch64") {
- assertEquals(isNullBuffer(new Uint8Array()), false, "isNullBuffer(new Uint8Array()) !== false");
-}
-
-// Externally backed ArrayBuffer has a non-null data pointer, even though its length is zero.
-const externalZeroBuffer = new Uint8Array(Deno.UnsafePointerView.getArrayBuffer(ptr0, 0));
-// V8 Fast calls used to get null pointers for all zero-sized buffers no matter their external backing.
-assertEquals(isNullBuffer(externalZeroBuffer), false, "isNullBuffer(externalZeroBuffer) !== false");
-// V8's `Local<ArrayBuffer>->Data()` method also used to similarly return null pointers for all
-// zero-sized buffers which would not match what `Local<ArrayBuffer>->GetBackingStore()->Data()`
-// API returned. These issues have been fixed in https://bugs.chromium.org/p/v8/issues/detail?id=13488.
-assertEquals(isNullBufferDeopt(externalZeroBuffer), false, "isNullBufferDeopt(externalZeroBuffer) !== false");
-
-// The same pointer with a non-zero byte length for the buffer will return non-null pointers in
-// both Fast call and V8 API calls.
-const externalOneBuffer = new Uint8Array(Deno.UnsafePointerView.getArrayBuffer(ptr0, 1));
-assertEquals(isNullBuffer(externalOneBuffer), false, "isNullBuffer(externalOneBuffer) !== false");
-assertEquals(isNullBufferDeopt(externalOneBuffer), false, "isNullBufferDeopt(externalOneBuffer) !== false");
-
-// UnsafePointer.of uses an exact-pointer fallback for zero-length buffers and slices to ensure that it always gets
-// the underlying pointer right.
-assertNotEquals(Deno.UnsafePointer.of(externalZeroBuffer), null, "Deno.UnsafePointer.of(externalZeroBuffer) === null");
-assertNotEquals(Deno.UnsafePointer.of(externalOneBuffer), null, "Deno.UnsafePointer.of(externalOneBuffer) === null");
-
-const addU32Ptr = dylib.symbols.get_add_u32_ptr();
-const addU32 = new Deno.UnsafeFnPointer(addU32Ptr, {
- parameters: ["u32", "u32"],
- result: "u32",
-});
-console.log(addU32.call(123, 456));
-
-const sleepBlockingPtr = dylib.symbols.get_sleep_blocking_ptr();
-const sleepNonBlocking = new Deno.UnsafeFnPointer(sleepBlockingPtr, {
- nonblocking: true,
- parameters: ["u64"],
- result: "void",
-});
-const before = performance.now();
-await sleepNonBlocking.call(100);
-console.log(performance.now() - before >= 100);
-
-const { add_u32, add_usize_fast } = symbols;
-function addU32Fast(a, b) {
- return add_u32(a, b);
-};
-testOptimized(addU32Fast, () => addU32Fast(123, 456));
-
-function addU64Fast(a, b) { return add_usize_fast(a, b); };
-testOptimized(addU64Fast, () => addU64Fast(2, 3));
-
-console.log(dylib.symbols.add_i32(123, 456));
-console.log(dylib.symbols.add_u64(0xffffffffn, 0xffffffffn));
-console.log(dylib.symbols.add_i64(-0xffffffffn, -0xffffffffn));
-console.log(dylib.symbols.add_usize(0xffffffffn, 0xffffffffn));
-console.log(dylib.symbols.add_isize(-0xffffffffn, -0xffffffffn));
-console.log(dylib.symbols.add_u64(Number.MAX_SAFE_INTEGER, 1));
-console.log(dylib.symbols.add_i64(Number.MAX_SAFE_INTEGER, 1));
-console.log(dylib.symbols.add_i64(Number.MIN_SAFE_INTEGER, -1));
-console.log(dylib.symbols.add_usize(Number.MAX_SAFE_INTEGER, 1));
-console.log(dylib.symbols.add_isize(Number.MAX_SAFE_INTEGER, 1));
-console.log(dylib.symbols.add_isize(Number.MIN_SAFE_INTEGER, -1));
-console.log(dylib.symbols.add_f32(123.123, 456.789));
-console.log(dylib.symbols.add_f64(123.123, 456.789));
-console.log(dylib.symbols.and(true, true));
-console.log(dylib.symbols.and(true, false));
-
-function addF32Fast(a, b) {
- return dylib.symbols.add_f32(a, b);
-};
-testOptimized(addF32Fast, () => addF32Fast(123.123, 456.789));
-
-function addF64Fast(a, b) {
- return dylib.symbols.add_f64(a, b);
-};
-testOptimized(addF64Fast, () => addF64Fast(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_u64_nonblocking(Number.MAX_SAFE_INTEGER, 1));
-console.log(await dylib.symbols.add_i64_nonblocking(Number.MAX_SAFE_INTEGER, 1));
-console.log(await dylib.symbols.add_i64_nonblocking(Number.MIN_SAFE_INTEGER, -1));
-console.log(await dylib.symbols.add_usize_nonblocking(Number.MAX_SAFE_INTEGER, 1));
-console.log(await dylib.symbols.add_isize_nonblocking(Number.MAX_SAFE_INTEGER, 1));
-console.log(await dylib.symbols.add_isize_nonblocking(Number.MIN_SAFE_INTEGER, -1));
-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) {
- let buf = new Uint8Array(arr);
- dylib.symbols.fill_buffer(fillValue, buf, buf.length);
- for (let i = 0; i < buf.length; i++) {
- if (buf[i] !== fillValue) {
- throw new Error(`Found '${buf[i]}' in buffer, expected '${fillValue}'.`);
- }
- }
-}
-
-test_fill_buffer(0, [2, 3, 4]);
-test_fill_buffer(5, [2, 7, 3, 2, 1]);
-
-const deferred = Promise.withResolvers();
-const buffer3 = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
-dylib.symbols.nonblocking_buffer(buffer3, buffer3.length).then(() => {
- deferred.resolve();
-});
-await deferred.promise;
-
-let start = performance.now();
-dylib.symbols.sleep_blocking(100);
-assert(performance.now() - start >= 100);
-
-start = performance.now();
-const promise_2 = dylib.symbols.sleep_nonblocking(100).then(() => {
- console.log("After");
- assert(performance.now() - start >= 100);
-});
-console.log("Before");
-assert(performance.now() - start < 100);
-
-// Await to make sure `sleep_nonblocking` calls and logs before we proceed
-await promise_2;
-
-// 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(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: "buffer",
-}, () => {
- 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.pointer);
- },
- TypeError,
- "hi",
-);
-
-const { call_stored_function } = dylib.symbols;
-
-dylib.symbols.call_fn_ptr(logCallback.pointer);
-dylib.symbols.call_fn_ptr_many_parameters(logManyParametersCallback.pointer);
-dylib.symbols.call_fn_ptr_return_u8(returnU8Callback.pointer);
-dylib.symbols.call_fn_ptr_return_buffer(returnBufferCallback.pointer);
-dylib.symbols.store_function(logCallback.pointer);
-call_stored_function();
-dylib.symbols.store_function_2(add10Callback.pointer);
-dylib.symbols.call_stored_function_2(20);
-
-function logManyParametersFast(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s) {
- return symbols.log_many_parameters(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s);
-};
-testOptimized(
- logManyParametersFast,
- () => logManyParametersFast(
- 255, 65535, 4294967295, 4294967296, 123.456, 789.876, -1, -2, -3, -4, -1000, 1000,
- 12345.678910, 12345.678910, 12345.678910, 12345.678910, 12345.678910, 12345.678910, 12345.678910
- )
-);
-
-// Some ABIs rely on the convention to zero/sign-extend arguments by the caller to optimize the callee function.
-// If the trampoline did not zero/sign-extend arguments, this would return 256 instead of the expected 0 (in optimized builds)
-function castU8U32Fast(x) { return symbols.cast_u8_u32(x); };
-testOptimized(castU8U32Fast, () => castU8U32Fast(256));
-
-// Some ABIs rely on the convention to expect garbage in the bits beyond the size of the return value to optimize the callee function.
-// If the trampoline did not zero/sign-extend the return value, this would return 256 instead of the expected 0 (in optimized builds)
-function castU32U8Fast(x) { return symbols.cast_u32_u8(x); };
-testOptimized(castU32U8Fast, () => castU32U8Fast(256));
-
-// Generally the trampoline tail-calls into the FFI function, but in certain cases (e.g. when returning 8 or 16 bit integers)
-// the tail call is not possible and a new stack frame must be created. We need enough parameters to have some on the stack
-function addManyU16Fast(a, b, c, d, e, f, g, h, i, j, k, l, m) {
- return symbols.add_many_u16(a, b, c, d, e, f, g, h, i, j, k, l, m);
-};
-// N.B. V8 does not currently follow Aarch64 Apple's calling convention.
-// The current implementation of the JIT trampoline follows the V8 incorrect calling convention. This test covers the use-case
-// and is expected to fail once Deno uses a V8 version with the bug fixed.
-// The V8 bug is being tracked in https://bugs.chromium.org/p/v8/issues/detail?id=13171
-testOptimized(addManyU16Fast, () => addManyU16Fast(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12));
-
-
-const nestedCallback = new Deno.UnsafeCallback(
- { parameters: [], result: "void" },
- () => {
- dylib.symbols.call_stored_function_2(10);
- },
-);
-dylib.symbols.store_function(nestedCallback.pointer);
-
-dylib.symbols.store_function(null);
-dylib.symbols.store_function_2(null);
-
-let counter = 0;
-const addToFooCallback = new Deno.UnsafeCallback({
- parameters: [],
- result: "void",
-}, () => counter++);
-
-// Test thread safe callbacks
-assertEquals(counter, 0);
-addToFooCallback.ref();
-await dylib.symbols.call_fn_ptr_thread_safe(addToFooCallback.pointer);
-addToFooCallback.unref();
-logCallback.ref();
-await dylib.symbols.call_fn_ptr_thread_safe(logCallback.pointer);
-logCallback.unref();
-assertEquals(counter, 1);
-returnU8Callback.ref();
-await dylib.symbols.call_fn_ptr_return_u8_thread_safe(returnU8Callback.pointer);
-// Purposefully do not unref returnU8Callback: Instead use it to test close() unrefing.
-
-// Test statics
-assertEquals(dylib.symbols.static_u32, 42);
-assertEquals(dylib.symbols.static_i64, -1242464576485);
-assert(
- typeof dylib.symbols.static_ptr === "object"
-);
-assertEquals(
- Object.keys(dylib.symbols.static_ptr).length, 0
-);
-const view = new Deno.UnsafePointerView(dylib.symbols.static_ptr);
-assertEquals(view.getUint32(), 42);
-
-// Test struct returning
-const rect_sync = dylib.symbols.make_rect(10, 20, 100, 200);
-assertInstanceOf(rect_sync, Uint8Array);
-assertEquals(rect_sync.length, 4 * 8);
-assertEquals(Array.from(new Float64Array(rect_sync.buffer)), [10, 20, 100, 200]);
-// Test struct passing
-dylib.symbols.print_rect(rect_sync);
-// Test struct passing asynchronously
-await dylib.symbols.print_rect_async(rect_sync);
-dylib.symbols.print_rect(new Float64Array([20, 20, 100, 200]));
-// Test struct returning asynchronously
-const rect_async = await dylib.symbols.make_rect_async(10, 20, 100, 200);
-assertInstanceOf(rect_async, Uint8Array);
-assertEquals(rect_async.length, 4 * 8);
-assertEquals(Array.from(new Float64Array(rect_async.buffer)), [10, 20, 100, 200]);
-
-// Test complex, mixed struct returning and passing
-const mixedStruct = dylib.symbols.create_mixed(3, 12.515000343322754, rect_async, Deno.UnsafePointer.create(12456789), new Uint32Array([8, 32]));
-assertEquals(mixedStruct.length, 56);
-assertEquals(Array.from(mixedStruct.subarray(0, 4)), [3, 0, 0, 0]);
-assertEquals(new Float32Array(mixedStruct.buffer, 4, 1)[0], 12.515000343322754);
-assertEquals(new Float64Array(mixedStruct.buffer, 8, 4), new Float64Array(rect_async.buffer));
-assertEquals(new BigUint64Array(mixedStruct.buffer, 40, 1)[0], 12456789n);
-assertEquals(new Uint32Array(mixedStruct.buffer, 48, 2), new Uint32Array([8, 32]));
-dylib.symbols.print_mixed(mixedStruct);
-
-const cb = new Deno.UnsafeCallback({
- parameters: [{ struct: Rect }],
- result: { struct: Rect },
-}, (innerRect) => {
- innerRect = new Float64Array(innerRect.buffer);
- return new Float64Array([innerRect[0] + 10, innerRect[1] + 10, innerRect[2] + 10, innerRect[3] + 10]);
-});
-
-const cbFfi = new Deno.UnsafeFnPointer(cb.pointer, cb.definition);
-const cbResult = new Float64Array(cbFfi.call(rect_async).buffer);
-assertEquals(Array.from(cbResult), [20, 30, 110, 210]);
-
-cb.close();
-
-const arrayBuffer = view.getArrayBuffer(4);
-const uint32Array = new Uint32Array(arrayBuffer);
-assertEquals(arrayBuffer.byteLength, 4);
-assertEquals(uint32Array.length, 1);
-assertEquals(uint32Array[0], 42);
-uint32Array[0] = 55; // MUTATES!
-assertEquals(uint32Array[0], 55);
-assertEquals(view.getUint32(), 55);
-
-
-{
- // Test UnsafePointer APIs
- assertEquals(Deno.UnsafePointer.create(0), null);
- const createdPointer = Deno.UnsafePointer.create(1);
- assertNotEquals(createdPointer, null);
- assertEquals(typeof createdPointer, "object");
- assertEquals(Deno.UnsafePointer.value(null), 0);
- assertEquals(Deno.UnsafePointer.value(createdPointer), 1);
- assert(Deno.UnsafePointer.equals(null, null));
- assertFalse(Deno.UnsafePointer.equals(null, createdPointer));
- assertFalse(Deno.UnsafePointer.equals(Deno.UnsafePointer.create(2), createdPointer));
- // Do not allow offsetting from null, `create` function should be used instead.
- assertThrows(() => Deno.UnsafePointer.offset(null, 5));
- const offsetPointer = Deno.UnsafePointer.offset(createdPointer, 5);
- assertEquals(Deno.UnsafePointer.value(offsetPointer), 6);
- const zeroPointer = Deno.UnsafePointer.offset(offsetPointer, -6);
- assertEquals(Deno.UnsafePointer.value(zeroPointer), 0);
- assertEquals(zeroPointer, null);
-}
-
-// Test non-UTF-8 characters
-
-const charView = new Deno.UnsafePointerView(dylib.symbols.static_char);
-
-const charArrayBuffer = charView.getArrayBuffer(14);
-const uint8Array = new Uint8Array(charArrayBuffer);
-assertEquals([...uint8Array], [
- 0xC0, 0xC1, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
- 0x00
-]);
-
-// Check that `getCString` works equally to `TextDecoder`
-assertEquals(charView.getCString(), new TextDecoder().decode(uint8Array.subarray(0, uint8Array.length - 1)));
-
-// Check a selection of various invalid UTF-8 sequences in C strings and verify
-// that the `getCString` API does not cause unexpected behaviour.
-for (const charBuffer of [
- Uint8Array.from([0xA0, 0xA1, 0x00]),
- Uint8Array.from([0xE2, 0x28, 0xA1, 0x00]),
- Uint8Array.from([0xE2, 0x82, 0x28, 0x00]),
- Uint8Array.from([0xF0, 0x28, 0x8C, 0xBC, 0x00]),
- Uint8Array.from([0xF0, 0x90, 0x28, 0xBC, 0x00]),
- Uint8Array.from([0xF0, 0x28, 0x8C, 0x28, 0x00]),
- Uint8Array.from([0xF8, 0xA1, 0xA1, 0xA1, 0xA1, 0x00]),
- Uint8Array.from([0xFC, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0x00]),
-]) {
- const charBufferPointer = Deno.UnsafePointer.of(charBuffer);
- const charString = Deno.UnsafePointerView.getCString(charBufferPointer);
- const charBufferPointerArrayBuffer = new Uint8Array(Deno.UnsafePointerView.getArrayBuffer(charBufferPointer, charBuffer.length - 1));
- assertEquals(charString, new TextDecoder().decode(charBufferPointerArrayBuffer));
- assertEquals([...charBuffer.subarray(0, charBuffer.length - 1)], [...charBufferPointerArrayBuffer]);
-}
-
-
-const bytes = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
-function hash() { return dylib.symbols.hash(bytes, bytes.byteLength); };
-
-testOptimized(hash, () => hash());
-
-(function cleanup() {
- dylib.close();
- throwCallback.close();
- logCallback.close();
- logManyParametersCallback.close();
- returnU8Callback.close();
- returnBufferCallback.close();
- add10Callback.close();
- nestedCallback.close();
- addToFooCallback.close();
-
- const resourcesPost = Deno[Deno.internal].core.resources();
-
- const preStr = JSON.stringify(resourcesPre, null, 2);
- const postStr = JSON.stringify(resourcesPost, null, 2);
- if (preStr !== postStr) {
- throw new Error(
- `Difference in open resources before dlopen and after closing:
-Before: ${preStr}
-After: ${postStr}`,
- );
- }
-
- console.log("Correct number of resources");
-})();
-
-function assertIsOptimized(fn) {
- const status = %GetOptimizationStatus(fn);
- assert(status & (1 << 4), `expected ${fn.name} to be optimized, but wasn't`);
-}
-
-function testOptimized(fn, callback) {
- %PrepareFunctionForOptimization(fn);
- const r1 = callback();
- if (r1 !== undefined) {
- console.log(r1);
- }
- %OptimizeFunctionOnNextCall(fn);
- const r2 = callback();
- if (r2 !== undefined) {
- console.log(r2);
- }
- assertIsOptimized(fn);
-}
diff --git a/test_ffi/tests/thread_safe_test.js b/test_ffi/tests/thread_safe_test.js
deleted file mode 100644
index fffa61a04..000000000
--- a/test_ffi/tests/thread_safe_test.js
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2018-2024 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, {
- store_function: {
- parameters: ["function"],
- result: "void",
- },
- call_stored_function: {
- parameters: [],
- result: "void",
- },
- call_stored_function_thread_safe: {
- parameters: [],
- result: "void",
- },
-});
-
-let resolveWorker;
-let workerResponsePromise;
-
-const worker = new Worker(
- new URL("./thread_safe_test_worker.js", import.meta.url).href,
- { type: "module" },
-);
-
-worker.addEventListener("message", () => {
- if (resolveWorker) {
- resolveWorker();
- }
-});
-
-const sendWorkerMessage = async (data) => {
- workerResponsePromise = new Promise((res) => {
- resolveWorker = res;
- });
- worker.postMessage(data);
- await workerResponsePromise;
-};
-
-// Test step 1: Register main thread callback, trigger on worker thread
-
-const mainThreadCallback = new Deno.UnsafeCallback(
- { parameters: [], result: "void" },
- () => {
- console.log("Callback on main thread");
- },
-);
-
-mainThreadCallback.ref();
-
-dylib.symbols.store_function(mainThreadCallback.pointer);
-
-await sendWorkerMessage("call");
-
-// Test step 2: Register on worker thread, trigger on main thread
-
-await sendWorkerMessage("register");
-
-dylib.symbols.call_stored_function();
-
-// Unref both main and worker thread callbacks and terminate the worker: Note, the stored function pointer in lib is now dangling.
-
-dylib.symbols.store_function(null);
-
-mainThreadCallback.unref();
-await sendWorkerMessage("unref");
-worker.terminate();
-
-// Test step 3: Register a callback that will be the only thing left keeping the isolate from exiting.
-// Rely on it to keep Deno running until the callback comes in and unrefs the callback, after which Deno should exit.
-
-const cleanupCallback = new Deno.UnsafeCallback(
- { parameters: [], result: "void" },
- () => {
- console.log("Callback being called");
- // Defer the cleanup to give the spawned thread all the time it needs to properly shut down
- setTimeout(() => cleanup(), 100);
- },
-);
-
-cleanupCallback.ref();
-
-function cleanup() {
- cleanupCallback.unref();
- dylib.symbols.store_function(null);
- mainThreadCallback.close();
- cleanupCallback.close();
- console.log("Isolate should now exit");
-}
-
-dylib.symbols.store_function(cleanupCallback.pointer);
-
-console.log(
- "Calling callback, isolate should stay asleep until callback is called",
-);
-dylib.symbols.call_stored_function_thread_safe();
diff --git a/test_ffi/tests/thread_safe_test_worker.js b/test_ffi/tests/thread_safe_test_worker.js
deleted file mode 100644
index fc4854436..000000000
--- a/test_ffi/tests/thread_safe_test_worker.js
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2018-2024 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, {
- store_function: {
- parameters: ["function"],
- result: "void",
- },
- call_stored_function: {
- parameters: [],
- result: "void",
- },
-});
-
-const callback = new Deno.UnsafeCallback(
- { parameters: [], result: "void" },
- () => {
- console.log("Callback on worker thread");
- },
-);
-
-callback.ref();
-
-self.addEventListener("message", ({ data }) => {
- if (data === "register") {
- dylib.symbols.store_function(callback.pointer);
- } else if (data === "call") {
- dylib.symbols.call_stored_function();
- } else if (data === "unref") {
- callback.close();
- }
- self.postMessage("done");
-});