From 5d71bc8734c663138b791e3ad9345ff5a0b4722f Mon Sep 17 00:00:00 2001 From: eliassjogreen Date: Wed, 11 Aug 2021 15:21:23 +0200 Subject: [PATCH 01/18] feat: ffi string and buffer support --- extensions/ffi/00_ffi.js | 25 +++- extensions/ffi/lib.rs | 181 ++++++++++++++++------------ test_ffi/src/lib.rs | 53 +++++++- test_ffi/tests/integration_tests.rs | 9 ++ test_ffi/tests/test.js | 23 +++- 5 files changed, 210 insertions(+), 81 deletions(-) diff --git a/extensions/ffi/00_ffi.js b/extensions/ffi/00_ffi.js index 3c4112a47333bb..dd621d2abd4eb1 100644 --- a/extensions/ffi/00_ffi.js +++ b/extensions/ffi/00_ffi.js @@ -12,8 +12,29 @@ this.#rid = core.opSync("op_ffi_load", { path, symbols }); for (const symbol in symbols) { - this.symbols[symbol] = (...parameters) => - core.opSync("op_ffi_call", { rid: this.#rid, symbol, parameters }); + this.symbols[symbol] = (...args) => { + const parameters = []; + const buffers = []; + + for (const arg of args) { + if ( + arg && arg.buffer instanceof ArrayBuffer && + arg.byteLength !== undefined + ) { + parameters.push(buffers.length); + buffers.push(arg); + } else { + parameters.push(arg); + } + } + + return core.opSync("op_ffi_call", { + rid: this.#rid, + symbol, + parameters, + buffers, + }); + }; } } diff --git a/extensions/ffi/lib.rs b/extensions/ffi/lib.rs index 125e6da9945223..438054de6e57b5 100644 --- a/extensions/ffi/lib.rs +++ b/extensions/ffi/lib.rs @@ -10,6 +10,7 @@ use deno_core::Extension; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; +use deno_core::ZeroCopyBuf; use dlopen::raw::Library; use libffi::middle::Arg; use serde::Deserialize; @@ -17,6 +18,9 @@ use std::borrow::Cow; use std::collections::HashMap; use std::convert::TryFrom; use std::ffi::c_void; +use std::ffi::CStr; +use std::ffi::CString; +use std::os::raw::c_char; use std::rc::Rc; pub struct Unstable(pub bool); @@ -50,6 +54,7 @@ struct Symbol { ptr: libffi::middle::CodePtr, parameter_types: Vec, result_type: NativeType, + result_length: Option, } struct DynamicLibraryResource { @@ -90,6 +95,7 @@ impl DynamicLibraryResource { ptr, parameter_types: parameter_types.collect(), result_type, + result_length: foreign_fn.result_length, }, ); @@ -131,6 +137,8 @@ enum NativeType { ISize, F32, F64, + String, + Buffer, } impl From for libffi::middle::Type { @@ -149,6 +157,8 @@ impl From for libffi::middle::Type { NativeType::ISize => libffi::middle::Type::isize(), NativeType::F32 => libffi::middle::Type::f32(), NativeType::F64 => libffi::middle::Type::f64(), + NativeType::String => libffi::middle::Type::pointer(), + NativeType::Buffer => libffi::middle::Type::pointer(), } } } @@ -169,86 +179,77 @@ impl From for NativeType { "isize" => NativeType::ISize, "f32" => NativeType::F32, "f64" => NativeType::F64, + "string" => NativeType::String, + "buffer" => NativeType::Buffer, _ => unimplemented!(), } } } -#[repr(C)] -union NativeValue { - void_value: (), - u8_value: u8, - i8_value: i8, - u16_value: u16, - i16_value: i16, - u32_value: u32, - i32_value: i32, - u64_value: u64, - i64_value: i64, - usize_value: usize, - isize_value: isize, - f32_value: f32, - f64_value: f64, +enum NativeValue { + Void, + U8(u8), + I8(i8), + U16(u16), + I16(i16), + U32(u32), + I32(i32), + U64(u64), + I64(i64), + USize(usize), + ISize(isize), + F32(f32), + F64(f64), + String(*const i8), + Buffer(*const u8), } impl NativeValue { - fn new(native_type: NativeType, value: Value) -> Self { + fn from_value(native_type: NativeType, value: Value) -> Self { match native_type { - NativeType::Void => Self { void_value: () }, - NativeType::U8 => Self { - u8_value: value_as_uint::(value), - }, - NativeType::I8 => Self { - i8_value: value_as_int::(value), - }, - NativeType::U16 => Self { - u16_value: value_as_uint::(value), - }, - NativeType::I16 => Self { - i16_value: value_as_int::(value), - }, - NativeType::U32 => Self { - u32_value: value_as_uint::(value), - }, - NativeType::I32 => Self { - i32_value: value_as_int::(value), - }, - NativeType::U64 => Self { - u64_value: value_as_uint::(value), - }, - NativeType::I64 => Self { - i64_value: value_as_int::(value), - }, - NativeType::USize => Self { - usize_value: value_as_uint::(value), - }, - NativeType::ISize => Self { - isize_value: value_as_int::(value), - }, - NativeType::F32 => Self { - f32_value: value_as_f32(value), - }, - NativeType::F64 => Self { - f64_value: value_as_f64(value), - }, + NativeType::Void => Self::Void, + NativeType::U8 => Self::U8(value_as_uint::(value)), + NativeType::I8 => Self::I8(value_as_int::(value)), + NativeType::U16 => Self::U16(value_as_uint::(value)), + NativeType::I16 => Self::I16(value_as_int::(value)), + NativeType::U32 => Self::U32(value_as_uint::(value)), + NativeType::I32 => Self::I32(value_as_int::(value)), + NativeType::U64 => Self::U64(value_as_uint::(value)), + NativeType::I64 => Self::I64(value_as_int::(value)), + NativeType::USize => Self::USize(value_as_uint::(value)), + NativeType::ISize => Self::ISize(value_as_int::(value)), + NativeType::F32 => Self::F32(value_as_f32(value)), + NativeType::F64 => Self::F64(value_as_f64(value)), + NativeType::String => Self::String( + CString::new( + value + .as_str() + .expect("Expected ffi arg value to be a string"), + ) + .unwrap() + .into_raw(), + ), + NativeType::Buffer => unreachable!(), } } - unsafe fn as_arg(&self, native_type: NativeType) -> Arg { - match native_type { - NativeType::Void => Arg::new(&self.void_value), - NativeType::U8 => Arg::new(&self.u8_value), - NativeType::I8 => Arg::new(&self.i8_value), - NativeType::U16 => Arg::new(&self.u16_value), - NativeType::I16 => Arg::new(&self.i16_value), - NativeType::U32 => Arg::new(&self.u32_value), - NativeType::I32 => Arg::new(&self.i32_value), - NativeType::U64 => Arg::new(&self.u64_value), - NativeType::I64 => Arg::new(&self.i64_value), - NativeType::USize => Arg::new(&self.usize_value), - NativeType::ISize => Arg::new(&self.isize_value), - NativeType::F32 => Arg::new(&self.f32_value), - NativeType::F64 => Arg::new(&self.f64_value), + fn as_arg(&self) -> Arg { + match self { + Self::Void => Arg::new(&()), + Self::U8(value) => Arg::new(value), + Self::I8(value) => Arg::new(value), + Self::U16(value) => Arg::new(value), + Self::I16(value) => Arg::new(value), + Self::U32(value) => Arg::new(value), + Self::I32(value) => Arg::new(value), + Self::U64(value) => Arg::new(value), + Self::I64(value) => Arg::new(value), + Self::USize(value) => Arg::new(value), + Self::ISize(value) => Arg::new(value), + Self::F32(value) => Arg::new(value), + Self::F64(value) => Arg::new(value), + Self::String(value) => Arg::new(value), + Self::Buffer(value) => Arg::new(value), } } } @@ -281,6 +282,7 @@ fn value_as_f64(value: Value) -> f64 { struct ForeignFunction { parameters: Vec, result: String, + result_length: Option, } #[derive(Deserialize, Debug)] @@ -314,12 +316,13 @@ where Ok(state.resource_table.add(resource)) } -#[derive(Deserialize, Debug)] +#[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct FfiCallArgs { rid: ResourceId, symbol: String, parameters: Vec, + buffers: Vec, } fn op_ffi_call( @@ -337,20 +340,30 @@ fn op_ffi_call( .get(&args.symbol) .ok_or_else(bad_resource_id)?; + let buffers: Vec<&[u8]> = args + .buffers + .iter() + .map(|buffer| &buffer[..]) + .collect(); + let native_values = symbol .parameter_types .iter() .zip(args.parameters.into_iter()) - .map(|(&native_type, value)| NativeValue::new(native_type, value)) + .map(|(&native_type, value)| { + if let NativeType::Buffer = native_type { + let idx: usize = value_as_uint(value); + let ptr = buffers[idx].as_ptr(); + NativeValue::Buffer(ptr) + } else { + NativeValue::from_value(native_type, value) + } + }) .collect::>(); - let call_args = symbol - .parameter_types + let call_args = native_values .iter() - .zip(native_values.iter()) - .map(|(&native_type, native_value)| unsafe { - native_value.as_arg(native_type) - }) + .map(|native_value| native_value.as_arg()) .collect::>(); Ok(match symbol.result_type { @@ -393,5 +406,21 @@ fn op_ffi_call( NativeType::F64 => { json!(unsafe { symbol.cif.call::(symbol.ptr, &call_args) }) } + NativeType::String => { + json!(unsafe { + let ptr = symbol.cif.call::<*const c_char>(symbol.ptr, &call_args); + let cstr = CStr::from_ptr(ptr); + cstr.to_str().unwrap() + }) + } + NativeType::Buffer => { + let ptr = unsafe { symbol.cif.call::<*const u8>(symbol.ptr, &call_args) }; + if let Some(len) = symbol.result_length { + let slice = unsafe { std::slice::from_raw_parts(ptr, len) }; + json!(slice) + } else { + json!(ptr as usize) + } + } }) } diff --git a/test_ffi/src/lib.rs b/test_ffi/src/lib.rs index d9e950d4f664ea..87abfd5943b7b2 100644 --- a/test_ffi/src/lib.rs +++ b/test_ffi/src/lib.rs @@ -1,9 +1,60 @@ +use std::ffi::CStr; +use std::os::raw::c_char; + #[no_mangle] pub extern "C" fn print_something() { println!("something"); } #[no_mangle] -pub extern "C" fn add(a: u32, b: u32) -> u32 { +pub unsafe extern "C" fn print_string(ptr: *const c_char) { + let cstr = CStr::from_ptr(ptr); + let name = cstr.to_str().unwrap(); + println!("{}", name); +} + +#[no_mangle] +pub unsafe extern "C" fn print_buffer(ptr: *const u8, len: usize) { + let buf = std::slice::from_raw_parts(ptr, len); + println!("{:?}", buf); +} + +#[no_mangle] +pub extern "C" fn add_u32(a: u32, b: u32) -> u32 { + a + b +} + +#[no_mangle] +pub extern "C" fn add_i32(a: i32, b: i32) -> i32 { + a + b +} + +#[no_mangle] +pub extern "C" fn add_u64(a: u64, b: u64) -> u64 { + a + b +} + +#[no_mangle] +pub extern "C" fn add_i64(a: i64, b: i64) -> i64 { + a + b +} + +#[no_mangle] +pub extern "C" fn add_usize(a: usize, b: usize) -> usize { + a + b +} + +#[no_mangle] +pub extern "C" fn add_isize(a: isize, b: isize) -> isize { + a + b +} + +#[no_mangle] +pub extern "C" fn add_f32(a: f32, b: f32) -> f32 { + a + b +} + +#[no_mangle] +pub extern "C" fn add_f64(a: f64, b: f64) -> f64 { a + b } diff --git a/test_ffi/tests/integration_tests.rs b/test_ffi/tests/integration_tests.rs index 7aa8a061142151..8d030917d23a8b 100644 --- a/test_ffi/tests/integration_tests.rs +++ b/test_ffi/tests/integration_tests.rs @@ -38,7 +38,16 @@ fn basic() { assert!(output.status.success()); let expected = "\ something\n\ + hello from deno!\n\ + [1, 2, 3, 4, 5, 6, 7, 8]\n\ 579\n\ + 579\n\ + 579\n\ + 579\n\ + 579\n\ + 579\n\ + 579.9119873046875\n\ + 579.912\n\ Correct number of resources\n"; assert_eq!(stdout, expected); assert_eq!(stderr, ""); diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js index a7b0aba6db6752..01c1607884e7ff 100644 --- a/test_ffi/tests/test.js +++ b/test_ffi/tests/test.js @@ -12,11 +12,30 @@ const libPath = `${targetDir}/${libPrefix}test_ffi.${libSuffix}`; const resourcesPre = Deno.resources(); const dylib = Deno.dlopen(libPath, { "print_something": { parameters: [], result: "void" }, - "add": { parameters: ["u32", "u32"], result: "u32" }, + "print_string": { parameters: ["string"], result: "void" }, + "print_buffer": { parameters: ["buffer", "usize"], result: "void" }, + "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_isize": { parameters: ["isize", "isize"], result: "isize" }, + "add_f32": { parameters: ["f32", "f32"], result: "f32" }, + "add_f64": { parameters: ["f64", "f64"], result: "f64" }, }); dylib.symbols.print_something(); -console.log(dylib.symbols.add(123, 456)); +dylib.symbols.print_string("hello from deno!"); +const buffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); +dylib.symbols.print_buffer(buffer, buffer.length); +console.log(dylib.symbols.add_u32(123, 456)); +console.log(dylib.symbols.add_i32(123, 456)); +console.log(dylib.symbols.add_u64(123, 456)); +console.log(dylib.symbols.add_i64(123, 456)); +console.log(dylib.symbols.add_usize(123, 456)); +console.log(dylib.symbols.add_isize(123, 456)); +console.log(dylib.symbols.add_f32(123.123, 456.789)); +console.log(dylib.symbols.add_f64(123.123, 456.789)); dylib.close(); const resourcesPost = Deno.resources(); From 24a13d43db447df13f9d41cc5e24ed98923319be Mon Sep 17 00:00:00 2001 From: eliassjogreen Date: Wed, 11 Aug 2021 17:39:00 +0200 Subject: [PATCH 02/18] feat: update typings --- cli/dts/lib.deno.unstable.d.ts | 12 +++++++++--- extensions/ffi/lib.rs | 7 ++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts index b83309bc9ddbd8..6b64a448150ef4 100644 --- a/cli/dts/lib.deno.unstable.d.ts +++ b/cli/dts/lib.deno.unstable.d.ts @@ -121,13 +121,19 @@ declare namespace Deno { | "usize" | "isize" | "f32" - | "f64"; + | "f64" + | "string" + | "buffer"; /** A foreign function as defined by its parameter and result types */ - export interface ForeignFunction { + export type ForeignFunction = { parameters: NativeType[]; result: NativeType; - } + } | { + parameters: NativeType[]; + result: "buffer"; + resultLength?: number; + }; /** A dynamic library resource */ export interface DynamicLibrary> { diff --git a/extensions/ffi/lib.rs b/extensions/ffi/lib.rs index 438054de6e57b5..94a30d0b5fb246 100644 --- a/extensions/ffi/lib.rs +++ b/extensions/ffi/lib.rs @@ -340,11 +340,8 @@ fn op_ffi_call( .get(&args.symbol) .ok_or_else(bad_resource_id)?; - let buffers: Vec<&[u8]> = args - .buffers - .iter() - .map(|buffer| &buffer[..]) - .collect(); + let buffers: Vec<&[u8]> = + args.buffers.iter().map(|buffer| &buffer[..]).collect(); let native_values = symbol .parameter_types From 746f8be90de131803674847d4941e3ce047d724e Mon Sep 17 00:00:00 2001 From: eliassjogreen Date: Thu, 12 Aug 2021 12:40:13 +0200 Subject: [PATCH 03/18] fix: rename ForeignFunction params to camelCase --- extensions/ffi/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/ffi/lib.rs b/extensions/ffi/lib.rs index 94a30d0b5fb246..e8d0489c00162f 100644 --- a/extensions/ffi/lib.rs +++ b/extensions/ffi/lib.rs @@ -279,6 +279,7 @@ fn value_as_f64(value: Value) -> f64 { } #[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] struct ForeignFunction { parameters: Vec, result: String, From b73e4b68eee0ccfe773e12b671c5b2243380461a Mon Sep 17 00:00:00 2001 From: eliassjogreen Date: Mon, 6 Sep 2021 16:29:42 +0200 Subject: [PATCH 04/18] fix: merge --- ext/ffi/lib.rs | 11 +++++------ test_util/wpt | 2 +- third_party | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs index d242d7ebee81e4..f29dabdc987fd5 100644 --- a/ext/ffi/lib.rs +++ b/ext/ffi/lib.rs @@ -80,13 +80,12 @@ impl DynamicLibraryResource { ) -> Result<(), AnyError> { let fn_ptr = unsafe { self.lib.symbol::<*const c_void>(&symbol) }?; let ptr = libffi::middle::CodePtr::from_ptr(fn_ptr as _); + let parameter_types = + foreign_fn.parameters.into_iter().map(NativeType::from); + let result_type = NativeType::from(foreign_fn.result); let cif = libffi::middle::Cif::new( - foreign_fn - .parameters - .clone() - .into_iter() - .map(libffi::middle::Type::from), - foreign_fn.result.into(), + parameter_types.clone().map(libffi::middle::Type::from), + result_type.into(), ); self.symbols.insert( diff --git a/test_util/wpt b/test_util/wpt index 230bbebcbc16f0..f55cfdca640b7e 160000 --- a/test_util/wpt +++ b/test_util/wpt @@ -1 +1 @@ -Subproject commit 230bbebcbc16f08e72ea65218a4d49b48084c205 +Subproject commit f55cfdca640b7e178c8fba26161b17a37bdcae59 diff --git a/third_party b/third_party index 084660078bfd4b..6c449eaecb0783 160000 --- a/third_party +++ b/third_party @@ -1 +1 @@ -Subproject commit 084660078bfd4b16993e5ef6ea7d099ad6d0cf55 +Subproject commit 6c449eaecb0783b06003b5eecd2893bd2617d66e From e08015880e1ecefcc5f1f4974efede7e6de3ec66 Mon Sep 17 00:00:00 2001 From: eliassjogreen Date: Mon, 6 Sep 2021 16:48:39 +0200 Subject: [PATCH 05/18] feat: test_ffi return string & buffer --- test_ffi/src/lib.rs | 13 ++++++++++++- test_ffi/tests/integration_tests.rs | 2 ++ test_ffi/tests/test.js | 6 +++++- test_util/std | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/test_ffi/src/lib.rs b/test_ffi/src/lib.rs index 87abfd5943b7b2..6848f0c062c8ec 100644 --- a/test_ffi/src/lib.rs +++ b/test_ffi/src/lib.rs @@ -1,4 +1,4 @@ -use std::ffi::CStr; +use std::ffi::{CStr, CString}; use std::os::raw::c_char; #[no_mangle] @@ -19,6 +19,17 @@ pub unsafe extern "C" fn print_buffer(ptr: *const u8, len: usize) { println!("{:?}", buf); } +#[no_mangle] +pub extern "C" fn return_string() -> *const c_char { + let cstring = CString::new("Hello from test ffi!").unwrap(); + cstring.into_raw() +} + +#[no_mangle] +pub extern "C" fn return_buffer() -> *const u8 { + [1, 2, 3, 4, 5, 6, 7, 8].as_ptr() +} + #[no_mangle] pub extern "C" fn add_u32(a: u32, b: u32) -> u32 { a + b diff --git a/test_ffi/tests/integration_tests.rs b/test_ffi/tests/integration_tests.rs index 8d030917d23a8b..8d70d0de4d9a49 100644 --- a/test_ffi/tests/integration_tests.rs +++ b/test_ffi/tests/integration_tests.rs @@ -40,6 +40,8 @@ fn basic() { something\n\ hello from deno!\n\ [1, 2, 3, 4, 5, 6, 7, 8]\n\ + Hello from test ffi!\n\ + [1, 2, 3, 4, 5, 6, 7, 8]\n\ 579\n\ 579\n\ 579\n\ diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js index 01c1607884e7ff..3ef5da1aec6a4d 100644 --- a/test_ffi/tests/test.js +++ b/test_ffi/tests/test.js @@ -14,6 +14,8 @@ const dylib = Deno.dlopen(libPath, { "print_something": { parameters: [], result: "void" }, "print_string": { parameters: ["string"], result: "void" }, "print_buffer": { parameters: ["buffer", "usize"], result: "void" }, + "return_string": { parameters: [], result: "string" }, + "return_buffer": { parameters: [], result: "buffer", resultLength: 8 }, "add_u32": { parameters: ["u32", "u32"], result: "u32" }, "add_i32": { parameters: ["i32", "i32"], result: "i32" }, "add_u64": { parameters: ["u64", "u64"], result: "u64" }, @@ -27,7 +29,9 @@ const dylib = Deno.dlopen(libPath, { dylib.symbols.print_something(); dylib.symbols.print_string("hello from deno!"); const buffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); -dylib.symbols.print_buffer(buffer, buffer.length); +dylib.symbols.print_buffer(buffer, buffer.length);; +console.log(dylib.symbols.return_string()); +console.log("[" + dylib.symbols.return_buffer().join(", ") + "]"); console.log(dylib.symbols.add_u32(123, 456)); console.log(dylib.symbols.add_i32(123, 456)); console.log(dylib.symbols.add_u64(123, 456)); diff --git a/test_util/std b/test_util/std index ca23a1e6035ebf..81314bcab8b5dc 160000 --- a/test_util/std +++ b/test_util/std @@ -1 +1 @@ -Subproject commit ca23a1e6035ebf34152ab1f20b46f1c3c9a11a5b +Subproject commit 81314bcab8b5dc2fef85ec65f8588cab17063378 From e71653933b586ab0741b553a3b6c149687b35080 Mon Sep 17 00:00:00 2001 From: eliassjogreen Date: Mon, 6 Sep 2021 17:09:15 +0200 Subject: [PATCH 06/18] fmt & lint --- test_ffi/src/lib.rs | 8 ++++---- test_ffi/tests/test.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test_ffi/src/lib.rs b/test_ffi/src/lib.rs index 6848f0c062c8ec..3250bf3315593b 100644 --- a/test_ffi/src/lib.rs +++ b/test_ffi/src/lib.rs @@ -7,15 +7,15 @@ pub extern "C" fn print_something() { } #[no_mangle] -pub unsafe extern "C" fn print_string(ptr: *const c_char) { - let cstr = CStr::from_ptr(ptr); +pub extern "C" fn print_string(ptr: *const c_char) { + let cstr = unsafe { CStr::from_ptr(ptr) }; let name = cstr.to_str().unwrap(); println!("{}", name); } #[no_mangle] -pub unsafe extern "C" fn print_buffer(ptr: *const u8, len: usize) { - let buf = std::slice::from_raw_parts(ptr, len); +pub extern "C" fn print_buffer(ptr: *const u8, len: usize) { + let buf = unsafe { std::slice::from_raw_parts(ptr, len) }; println!("{:?}", buf); } diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js index 3ef5da1aec6a4d..ac9394c0c815cf 100644 --- a/test_ffi/tests/test.js +++ b/test_ffi/tests/test.js @@ -29,7 +29,7 @@ const dylib = Deno.dlopen(libPath, { dylib.symbols.print_something(); dylib.symbols.print_string("hello from deno!"); const buffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); -dylib.symbols.print_buffer(buffer, buffer.length);; +dylib.symbols.print_buffer(buffer, buffer.length); console.log(dylib.symbols.return_string()); console.log("[" + dylib.symbols.return_buffer().join(", ") + "]"); console.log(dylib.symbols.add_u32(123, 456)); From 39e5e37aa1e5027d6349c053516893c1f5f5e0f8 Mon Sep 17 00:00:00 2001 From: eliassjogreen Date: Tue, 7 Sep 2021 15:38:55 +0200 Subject: [PATCH 07/18] adfsasfasfsadfsadf --- ext/ffi/00_ffi.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js index 4ea8740152559e..46126c278c6698 100644 --- a/ext/ffi/00_ffi.js +++ b/ext/ffi/00_ffi.js @@ -19,7 +19,7 @@ for (const arg of args) { if ( - arg && arg.buffer instanceof ArrayBuffer && + arg?.buffer instanceof ArrayBuffer && arg.byteLength !== undefined ) { parameters.push(buffers.length); From 4d132faa6f6719001ca42d59701be3a66182d762 Mon Sep 17 00:00:00 2001 From: eliassjogreen Date: Tue, 7 Sep 2021 15:40:05 +0200 Subject: [PATCH 08/18] update 3rd party --- third_party | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party b/third_party index 6c449eaecb0783..bc48d4631492b5 160000 --- a/third_party +++ b/third_party @@ -1 +1 @@ -Subproject commit 6c449eaecb0783b06003b5eecd2893bd2617d66e +Subproject commit bc48d4631492b5998795c41b192dee40e6047d95 From 5f4d9d4b6e02229dfe84ee5cd71bee0f3d359c35 Mon Sep 17 00:00:00 2001 From: eliassjogreen Date: Wed, 8 Sep 2021 08:49:17 +0200 Subject: [PATCH 09/18] update wpt --- test_util/wpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_util/wpt b/test_util/wpt index f55cfdca640b7e..8a2b0f1086adf1 160000 --- a/test_util/wpt +++ b/test_util/wpt @@ -1 +1 @@ -Subproject commit f55cfdca640b7e178c8fba26161b17a37bdcae59 +Subproject commit 8a2b0f1086adf122d91c36c222b26362ba4059f2 From 9bb4271d448f478c77e694084454f15191c9315b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 9 Sep 2021 17:01:57 +0200 Subject: [PATCH 10/18] sync std --- test_util/std | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_util/std b/test_util/std index 81314bcab8b5dc..ca23a1e6035ebf 160000 --- a/test_util/std +++ b/test_util/std @@ -1 +1 @@ -Subproject commit 81314bcab8b5dc2fef85ec65f8588cab17063378 +Subproject commit ca23a1e6035ebf34152ab1f20b46f1c3c9a11a5b From 32cc8179b8de0134eb20103515852cb6fcb9b779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 9 Sep 2021 17:06:00 +0200 Subject: [PATCH 11/18] lint --- ext/ffi/00_ffi.js | 8 +++++--- test_ffi/src/lib.rs | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js index 46126c278c6698..d76c1a53fb753e 100644 --- a/ext/ffi/00_ffi.js +++ b/ext/ffi/00_ffi.js @@ -3,8 +3,10 @@ ((window) => { const core = window.Deno.core; - const __bootstrap = window.__bootstrap; - + const util = window.__bootstrap.util; + const { + ArrayBuffer, + } = window.__bootstrap.primordials; class DynamicLibrary { #rid; symbols = {}; @@ -46,7 +48,7 @@ function dlopen(path, symbols) { // URL support is progressively enhanced by util in `runtime/js`. - const pathFromURL = __bootstrap.util.pathFromURL ?? ((p) => p); + const pathFromURL = util.pathFromURL ?? ((p) => p); return new DynamicLibrary(pathFromURL(path), symbols); } diff --git a/test_ffi/src/lib.rs b/test_ffi/src/lib.rs index 3250bf3315593b..6e50079cb1a305 100644 --- a/test_ffi/src/lib.rs +++ b/test_ffi/src/lib.rs @@ -6,6 +6,7 @@ pub extern "C" fn print_something() { println!("something"); } +#[allow(clippy::not_unsafe_ptr_arg_deref)] #[no_mangle] pub extern "C" fn print_string(ptr: *const c_char) { let cstr = unsafe { CStr::from_ptr(ptr) }; @@ -13,6 +14,7 @@ pub extern "C" fn print_string(ptr: *const c_char) { println!("{}", name); } +#[allow(clippy::not_unsafe_ptr_arg_deref)] #[no_mangle] pub extern "C" fn print_buffer(ptr: *const u8, len: usize) { let buf = unsafe { std::slice::from_raw_parts(ptr, len) }; From b2c622f0aaf50067d52194edca273441833ad189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 9 Sep 2021 17:17:53 +0200 Subject: [PATCH 12/18] try fix destructure --- ext/ffi/00_ffi.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js index d76c1a53fb753e..50103cb4ab2b4b 100644 --- a/ext/ffi/00_ffi.js +++ b/ext/ffi/00_ffi.js @@ -3,7 +3,7 @@ ((window) => { const core = window.Deno.core; - const util = window.__bootstrap.util; + const __bootstrap = window.__bootstrap; const { ArrayBuffer, } = window.__bootstrap.primordials; @@ -48,7 +48,7 @@ function dlopen(path, symbols) { // URL support is progressively enhanced by util in `runtime/js`. - const pathFromURL = util.pathFromURL ?? ((p) => p); + const pathFromURL = __bootstrap.util.pathFromURL ?? ((p) => p); return new DynamicLibrary(pathFromURL(path), symbols); } From f7bdcd3bece0383f8245e76df315f59ad46dce99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 9 Sep 2021 17:39:37 +0200 Subject: [PATCH 13/18] try fix unit test error --- cli/tests/unit/ffi_test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/tests/unit/ffi_test.ts b/cli/tests/unit/ffi_test.ts index ab25df699e55ae..07ec4003f9d932 100644 --- a/cli/tests/unit/ffi_test.ts +++ b/cli/tests/unit/ffi_test.ts @@ -2,7 +2,7 @@ import { assertThrows, unitTest } from "./test_util.ts"; -unitTest(function dlopenInvalidArguments() { +unitTest({ perms: { ffi: true } }, function dlopenInvalidArguments() { const filename = "/usr/lib/libc.so.6"; assertThrows(() => { // @ts-expect-error: ForeignFunction cannot be null From efd5e8c0a314985e38ad19b054a48e8c6f34ee8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 5 Oct 2021 22:58:49 +0200 Subject: [PATCH 14/18] drop support for strings --- cli/dts/lib.deno.unstable.d.ts | 9 +++------ ext/ffi/lib.rs | 24 ------------------------ test_ffi/src/lib.rs | 17 +---------------- test_ffi/tests/integration_tests.rs | 2 -- test_ffi/tests/test.js | 4 ---- 5 files changed, 4 insertions(+), 52 deletions(-) diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts index 24d8376dc503ae..9e3bee3d9336e5 100644 --- a/cli/dts/lib.deno.unstable.d.ts +++ b/cli/dts/lib.deno.unstable.d.ts @@ -118,18 +118,15 @@ declare namespace Deno { | "isize" | "f32" | "f64" - | "string" | "buffer"; /** A foreign function as defined by its parameter and result types */ - export type ForeignFunction = { + export interface ForeignFunction { parameters: NativeType[]; result: NativeType; - } | { - parameters: NativeType[]; - result: "buffer"; + /** Only present if `result` is of type "buffer". */ resultLength?: number; - }; + } /** A dynamic library resource */ export interface DynamicLibrary> { diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs index f29dabdc987fd5..a8cba7d48397ad 100644 --- a/ext/ffi/lib.rs +++ b/ext/ffi/lib.rs @@ -18,9 +18,6 @@ use std::borrow::Cow; use std::collections::HashMap; use std::convert::TryFrom; use std::ffi::c_void; -use std::ffi::CStr; -use std::ffi::CString; -use std::os::raw::c_char; use std::rc::Rc; pub struct Unstable(pub bool); @@ -137,7 +134,6 @@ enum NativeType { ISize, F32, F64, - String, Buffer, } @@ -157,7 +153,6 @@ impl From for libffi::middle::Type { NativeType::ISize => libffi::middle::Type::isize(), NativeType::F32 => libffi::middle::Type::f32(), NativeType::F64 => libffi::middle::Type::f64(), - NativeType::String => libffi::middle::Type::pointer(), NativeType::Buffer => libffi::middle::Type::pointer(), } } @@ -179,7 +174,6 @@ impl From for NativeType { "isize" => NativeType::ISize, "f32" => NativeType::F32, "f64" => NativeType::F64, - "string" => NativeType::String, "buffer" => NativeType::Buffer, _ => unimplemented!(), } @@ -200,7 +194,6 @@ enum NativeValue { ISize(isize), F32(f32), F64(f64), - String(*const i8), Buffer(*const u8), } @@ -220,15 +213,6 @@ impl NativeValue { NativeType::ISize => Self::ISize(value_as_int::(value)), NativeType::F32 => Self::F32(value_as_f32(value)), NativeType::F64 => Self::F64(value_as_f64(value)), - NativeType::String => Self::String( - CString::new( - value - .as_str() - .expect("Expected ffi arg value to be a string"), - ) - .unwrap() - .into_raw(), - ), NativeType::Buffer => unreachable!(), } } @@ -248,7 +232,6 @@ impl NativeValue { Self::ISize(value) => Arg::new(value), Self::F32(value) => Arg::new(value), Self::F64(value) => Arg::new(value), - Self::String(value) => Arg::new(value), Self::Buffer(value) => Arg::new(value), } } @@ -403,13 +386,6 @@ fn op_ffi_call( NativeType::F64 => { json!(unsafe { symbol.cif.call::(symbol.ptr, &call_args) }) } - NativeType::String => { - json!(unsafe { - let ptr = symbol.cif.call::<*const c_char>(symbol.ptr, &call_args); - let cstr = CStr::from_ptr(ptr); - cstr.to_str().unwrap() - }) - } NativeType::Buffer => { let ptr = unsafe { symbol.cif.call::<*const u8>(symbol.ptr, &call_args) }; if let Some(len) = symbol.result_length { diff --git a/test_ffi/src/lib.rs b/test_ffi/src/lib.rs index 6e50079cb1a305..d3bdff7255fa12 100644 --- a/test_ffi/src/lib.rs +++ b/test_ffi/src/lib.rs @@ -1,19 +1,10 @@ -use std::ffi::{CStr, CString}; -use std::os::raw::c_char; +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. #[no_mangle] pub extern "C" fn print_something() { println!("something"); } -#[allow(clippy::not_unsafe_ptr_arg_deref)] -#[no_mangle] -pub extern "C" fn print_string(ptr: *const c_char) { - let cstr = unsafe { CStr::from_ptr(ptr) }; - let name = cstr.to_str().unwrap(); - println!("{}", name); -} - #[allow(clippy::not_unsafe_ptr_arg_deref)] #[no_mangle] pub extern "C" fn print_buffer(ptr: *const u8, len: usize) { @@ -21,12 +12,6 @@ pub extern "C" fn print_buffer(ptr: *const u8, len: usize) { println!("{:?}", buf); } -#[no_mangle] -pub extern "C" fn return_string() -> *const c_char { - let cstring = CString::new("Hello from test ffi!").unwrap(); - cstring.into_raw() -} - #[no_mangle] pub extern "C" fn return_buffer() -> *const u8 { [1, 2, 3, 4, 5, 6, 7, 8].as_ptr() diff --git a/test_ffi/tests/integration_tests.rs b/test_ffi/tests/integration_tests.rs index 8d70d0de4d9a49..b34f7e561cfd93 100644 --- a/test_ffi/tests/integration_tests.rs +++ b/test_ffi/tests/integration_tests.rs @@ -38,9 +38,7 @@ fn basic() { assert!(output.status.success()); let expected = "\ something\n\ - hello from deno!\n\ [1, 2, 3, 4, 5, 6, 7, 8]\n\ - Hello from test ffi!\n\ [1, 2, 3, 4, 5, 6, 7, 8]\n\ 579\n\ 579\n\ diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js index ac9394c0c815cf..95a14b56dec780 100644 --- a/test_ffi/tests/test.js +++ b/test_ffi/tests/test.js @@ -12,9 +12,7 @@ const libPath = `${targetDir}/${libPrefix}test_ffi.${libSuffix}`; const resourcesPre = Deno.resources(); const dylib = Deno.dlopen(libPath, { "print_something": { parameters: [], result: "void" }, - "print_string": { parameters: ["string"], result: "void" }, "print_buffer": { parameters: ["buffer", "usize"], result: "void" }, - "return_string": { parameters: [], result: "string" }, "return_buffer": { parameters: [], result: "buffer", resultLength: 8 }, "add_u32": { parameters: ["u32", "u32"], result: "u32" }, "add_i32": { parameters: ["i32", "i32"], result: "i32" }, @@ -27,10 +25,8 @@ const dylib = Deno.dlopen(libPath, { }); dylib.symbols.print_something(); -dylib.symbols.print_string("hello from deno!"); const buffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); dylib.symbols.print_buffer(buffer, buffer.length); -console.log(dylib.symbols.return_string()); console.log("[" + dylib.symbols.return_buffer().join(", ") + "]"); console.log(dylib.symbols.add_u32(123, 456)); console.log(dylib.symbols.add_i32(123, 456)); From 6e5d98805c6d10ea1016c20a1d580d0b3e874e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 5 Oct 2021 23:33:45 +0200 Subject: [PATCH 15/18] drop support for return buffer, bring back NativeValue union --- cli/dts/lib.deno.unstable.d.ts | 5 +- ext/ffi/lib.rs | 185 +++++++++++++++++---------------- test_ffi/src/lib.rs | 5 - test_ffi/tests/test.js | 2 - 4 files changed, 94 insertions(+), 103 deletions(-) diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts index 9e3bee3d9336e5..db59980ec0b871 100644 --- a/cli/dts/lib.deno.unstable.d.ts +++ b/cli/dts/lib.deno.unstable.d.ts @@ -117,15 +117,12 @@ declare namespace Deno { | "usize" | "isize" | "f32" - | "f64" - | "buffer"; + | "f64"; /** A foreign function as defined by its parameter and result types */ export interface ForeignFunction { parameters: NativeType[]; result: NativeType; - /** Only present if `result` is of type "buffer". */ - resultLength?: number; } /** A dynamic library resource */ diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs index 6fb571146bf0fc..ebf5572a714cc2 100644 --- a/ext/ffi/lib.rs +++ b/ext/ffi/lib.rs @@ -46,7 +46,6 @@ struct Symbol { ptr: libffi::middle::CodePtr, parameter_types: Vec, result_type: NativeType, - result_length: Option, } unsafe impl Send for Symbol {} @@ -75,12 +74,13 @@ impl DynamicLibraryResource { ) -> Result<(), AnyError> { let fn_ptr = unsafe { self.lib.symbol::<*const c_void>(&symbol) }?; let ptr = libffi::middle::CodePtr::from_ptr(fn_ptr as _); - let parameter_types = - foreign_fn.parameters.into_iter().map(NativeType::from); - let result_type = NativeType::from(foreign_fn.result); let cif = libffi::middle::Cif::new( - parameter_types.clone().map(libffi::middle::Type::from), - result_type.into(), + foreign_fn + .parameters + .clone() + .into_iter() + .map(libffi::middle::Type::from), + foreign_fn.result.into(), ); self.symbols.insert( @@ -88,9 +88,8 @@ impl DynamicLibraryResource { Symbol { cif, ptr, - parameter_types: parameter_types.collect(), - result_type, - result_length: foreign_fn.result_length, + parameter_types: foreign_fn.parameters, + result_type: foreign_fn.result, }, ); @@ -157,81 +156,88 @@ impl From for libffi::middle::Type { } } -impl From for NativeType { - fn from(string: String) -> Self { - match string.as_str() { - "void" => NativeType::Void, - "u8" => NativeType::U8, - "i8" => NativeType::I8, - "u16" => NativeType::U16, - "i16" => NativeType::I16, - "u32" => NativeType::U32, - "i32" => NativeType::I32, - "u64" => NativeType::U64, - "i64" => NativeType::I64, - "usize" => NativeType::USize, - "isize" => NativeType::ISize, - "f32" => NativeType::F32, - "f64" => NativeType::F64, - "buffer" => NativeType::Buffer, - _ => unimplemented!(), - } - } -} - -enum NativeValue { - Void, - U8(u8), - I8(i8), - U16(u16), - I16(i16), - U32(u32), - I32(i32), - U64(u64), - I64(i64), - USize(usize), - ISize(isize), - F32(f32), - F64(f64), - Buffer(*const u8), +#[repr(C)] +union NativeValue { + void_value: (), + u8_value: u8, + i8_value: i8, + u16_value: u16, + i16_value: i16, + u32_value: u32, + i32_value: i32, + u64_value: u64, + i64_value: i64, + usize_value: usize, + isize_value: isize, + f32_value: f32, + f64_value: f64, + buffer: *const u8, } impl NativeValue { - fn from_value(native_type: NativeType, value: Value) -> Self { + fn new(native_type: NativeType, value: Value) -> Self { match native_type { - NativeType::Void => Self::Void, - NativeType::U8 => Self::U8(value_as_uint::(value)), - NativeType::I8 => Self::I8(value_as_int::(value)), - NativeType::U16 => Self::U16(value_as_uint::(value)), - NativeType::I16 => Self::I16(value_as_int::(value)), - NativeType::U32 => Self::U32(value_as_uint::(value)), - NativeType::I32 => Self::I32(value_as_int::(value)), - NativeType::U64 => Self::U64(value_as_uint::(value)), - NativeType::I64 => Self::I64(value_as_int::(value)), - NativeType::USize => Self::USize(value_as_uint::(value)), - NativeType::ISize => Self::ISize(value_as_int::(value)), - NativeType::F32 => Self::F32(value_as_f32(value)), - NativeType::F64 => Self::F64(value_as_f64(value)), + NativeType::Void => Self { void_value: () }, + NativeType::U8 => Self { + u8_value: value_as_uint::(value), + }, + NativeType::I8 => Self { + i8_value: value_as_int::(value), + }, + NativeType::U16 => Self { + u16_value: value_as_uint::(value), + }, + NativeType::I16 => Self { + i16_value: value_as_int::(value), + }, + NativeType::U32 => Self { + u32_value: value_as_uint::(value), + }, + NativeType::I32 => Self { + i32_value: value_as_int::(value), + }, + NativeType::U64 => Self { + u64_value: value_as_uint::(value), + }, + NativeType::I64 => Self { + i64_value: value_as_int::(value), + }, + NativeType::USize => Self { + usize_value: value_as_uint::(value), + }, + NativeType::ISize => Self { + isize_value: value_as_int::(value), + }, + NativeType::F32 => Self { + f32_value: value_as_f32(value), + }, + NativeType::F64 => Self { + f64_value: value_as_f64(value), + }, NativeType::Buffer => unreachable!(), } } - fn as_arg(&self) -> Arg { - match self { - Self::Void => Arg::new(&()), - Self::U8(value) => Arg::new(value), - Self::I8(value) => Arg::new(value), - Self::U16(value) => Arg::new(value), - Self::I16(value) => Arg::new(value), - Self::U32(value) => Arg::new(value), - Self::I32(value) => Arg::new(value), - Self::U64(value) => Arg::new(value), - Self::I64(value) => Arg::new(value), - Self::USize(value) => Arg::new(value), - Self::ISize(value) => Arg::new(value), - Self::F32(value) => Arg::new(value), - Self::F64(value) => Arg::new(value), - Self::Buffer(value) => Arg::new(value), + fn buffer(ptr: *const u8) -> Self { + Self { buffer: ptr } + } + + unsafe fn as_arg(&self, native_type: NativeType) -> Arg { + match native_type { + NativeType::Void => Arg::new(&self.void_value), + NativeType::U8 => Arg::new(&self.u8_value), + NativeType::I8 => Arg::new(&self.i8_value), + NativeType::U16 => Arg::new(&self.u16_value), + NativeType::I16 => Arg::new(&self.i16_value), + NativeType::U32 => Arg::new(&self.u32_value), + NativeType::I32 => Arg::new(&self.i32_value), + NativeType::U64 => Arg::new(&self.u64_value), + NativeType::I64 => Arg::new(&self.i64_value), + NativeType::USize => Arg::new(&self.usize_value), + NativeType::ISize => Arg::new(&self.isize_value), + NativeType::F32 => Arg::new(&self.f32_value), + NativeType::F64 => Arg::new(&self.f64_value), + NativeType::Buffer => Arg::new(&self.buffer), } } } @@ -263,9 +269,8 @@ fn value_as_f64(value: Value) -> f64 { #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] struct ForeignFunction { - parameters: Vec, - result: String, - result_length: Option, + parameters: Vec, + result: NativeType, } #[derive(Deserialize, Debug)] @@ -320,16 +325,20 @@ fn ffi_call(args: FfiCallArgs, symbol: &Symbol) -> Result { if let NativeType::Buffer = native_type { let idx: usize = value_as_uint(value); let ptr = buffers[idx].as_ptr(); - NativeValue::Buffer(ptr) + NativeValue::buffer(ptr) } else { - NativeValue::from_value(native_type, value) + NativeValue::new(native_type, value) } }) .collect::>(); - let call_args = native_values + let call_args = symbol + .parameter_types .iter() - .map(|native_value| native_value.as_arg()) + .zip(native_values.iter()) + .map(|(&native_type, native_value)| unsafe { + native_value.as_arg(native_type) + }) .collect::>(); Ok(match symbol.result_type { @@ -372,15 +381,7 @@ fn ffi_call(args: FfiCallArgs, symbol: &Symbol) -> Result { NativeType::F64 => { json!(unsafe { symbol.cif.call::(symbol.ptr, &call_args) }) } - NativeType::Buffer => { - let ptr = unsafe { symbol.cif.call::<*const u8>(symbol.ptr, &call_args) }; - if let Some(len) = symbol.result_length { - let slice = unsafe { std::slice::from_raw_parts(ptr, len) }; - json!(slice) - } else { - json!(ptr as usize) - } - } + NativeType::Buffer => unreachable!(), }) } diff --git a/test_ffi/src/lib.rs b/test_ffi/src/lib.rs index 0d10c969e1c221..fb340ae099f63e 100644 --- a/test_ffi/src/lib.rs +++ b/test_ffi/src/lib.rs @@ -15,11 +15,6 @@ pub extern "C" fn print_buffer(ptr: *const u8, len: usize) { println!("{:?}", buf); } -#[no_mangle] -pub extern "C" fn return_buffer() -> *const u8 { - [1, 2, 3, 4, 5, 6, 7, 8].as_ptr() -} - #[no_mangle] pub extern "C" fn add_u32(a: u32, b: u32) -> u32 { a + b diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js index 3850dee7c49e16..5515f1e782a325 100644 --- a/test_ffi/tests/test.js +++ b/test_ffi/tests/test.js @@ -13,7 +13,6 @@ const resourcesPre = Deno.resources(); const dylib = Deno.dlopen(libPath, { "print_something": { parameters: [], result: "void" }, "print_buffer": { parameters: ["buffer", "usize"], result: "void" }, - "return_buffer": { parameters: [], result: "buffer", resultLength: 8 }, "add_u32": { parameters: ["u32", "u32"], result: "u32" }, "add_i32": { parameters: ["i32", "i32"], result: "i32" }, "add_u64": { parameters: ["u64", "u64"], result: "u64" }, @@ -28,7 +27,6 @@ const dylib = Deno.dlopen(libPath, { dylib.symbols.print_something(); const buffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); dylib.symbols.print_buffer(buffer, buffer.length); -console.log("[" + dylib.symbols.return_buffer().join(", ") + "]"); console.log(dylib.symbols.add_u32(123, 456)); console.log(dylib.symbols.add_i32(123, 456)); console.log(dylib.symbols.add_u64(123, 456)); From 3f339a30949f5b62b51fc7dd0efaf4d6c69e4c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 5 Oct 2021 23:35:51 +0200 Subject: [PATCH 16/18] fix test --- test_ffi/tests/integration_tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/test_ffi/tests/integration_tests.rs b/test_ffi/tests/integration_tests.rs index 633727abce4e8e..0ae395da86972a 100644 --- a/test_ffi/tests/integration_tests.rs +++ b/test_ffi/tests/integration_tests.rs @@ -39,7 +39,6 @@ fn basic() { let expected = "\ something\n\ [1, 2, 3, 4, 5, 6, 7, 8]\n\ - [1, 2, 3, 4, 5, 6, 7, 8]\n\ 579\n\ 579\n\ 579\n\ From 84ac1a5914131f7b9418fb8f62ee0087e45b86f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 5 Oct 2021 23:45:45 +0200 Subject: [PATCH 17/18] add missing arguments and fix tests --- ext/ffi/00_ffi.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js index 7edcc542d370d1..25eba02336adfd 100644 --- a/ext/ffi/00_ffi.js +++ b/ext/ffi/00_ffi.js @@ -34,13 +34,19 @@ } if (isNonBlocking) { - core.opAsync("op_ffi_call_nonblocking", { + return core.opAsync("op_ffi_call_nonblocking", { rid: this.#rid, symbol, parameters, + buffers, }); } else { - core.opSync("op_ffi_call", { rid: this.#rid, symbol, parameters }); + return core.opSync("op_ffi_call", { + rid: this.#rid, + symbol, + parameters, + buffers, + }); } }; } From 067b136bc0123082184947bf43503cb54a6570f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 5 Oct 2021 23:57:11 +0200 Subject: [PATCH 18/18] add test for nonblocking buffer --- test_ffi/src/lib.rs | 7 +++++++ test_ffi/tests/test.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/test_ffi/src/lib.rs b/test_ffi/src/lib.rs index fb340ae099f63e..cc6063ca3442a5 100644 --- a/test_ffi/src/lib.rs +++ b/test_ffi/src/lib.rs @@ -60,3 +60,10 @@ pub extern "C" fn sleep_blocking(ms: u64) { let duration = Duration::from_millis(ms); sleep(duration); } + +#[allow(clippy::not_unsafe_ptr_arg_deref)] +#[no_mangle] +pub extern "C" fn nonblocking_buffer(ptr: *const u8, len: usize) { + let buf = unsafe { std::slice::from_raw_parts(ptr, len) }; + assert_eq!(buf, vec![1, 2, 3, 4, 5, 6, 7, 8]); +} diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js index 5515f1e782a325..fc354139daeddc 100644 --- a/test_ffi/tests/test.js +++ b/test_ffi/tests/test.js @@ -22,6 +22,11 @@ const dylib = Deno.dlopen(libPath, { "add_f32": { parameters: ["f32", "f32"], result: "f32" }, "add_f64": { parameters: ["f64", "f64"], result: "f64" }, "sleep_blocking": { parameters: ["u64"], result: "void", nonblocking: true }, + "nonblocking_buffer": { + parameters: ["buffer", "usize"], + result: "void", + nonblocking: true, + }, }); dylib.symbols.print_something(); @@ -37,6 +42,30 @@ console.log(dylib.symbols.add_f32(123.123, 456.789)); console.log(dylib.symbols.add_f64(123.123, 456.789)); // Test non blocking calls + +function deferred() { + let methods; + const promise = new Promise((resolve, reject) => { + methods = { + async resolve(value) { + await value; + resolve(value); + }, + reject(reason) { + reject(reason); + }, + }; + }); + return Object.assign(promise, methods); +} + +const promise = deferred(); +const buffer2 = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); +dylib.symbols.nonblocking_buffer(buffer2, buffer2.length).then(() => { + promise.resolve(); +}); +await promise; + const start = performance.now(); dylib.symbols.sleep_blocking(100).then(() => { console.log("After");