From 16dbf4adc390c9fb7656372b42811c1929e755dd Mon Sep 17 00:00:00 2001 From: Aapo Alasuutari Date: Mon, 5 Sep 2022 06:26:52 +0300 Subject: [PATCH] feat(ext/ffi): Support bool FFI type (#15754) --- cli/dts/lib.deno.unstable.d.ts | 7 + ext/ffi/00_ffi.js | 6 + ext/ffi/jit_trampoline.rs | 2 + ext/ffi/lib.rs | 192 ++++++++++++++++++---------- ext/ffi/prelude.h | 11 ++ test_ffi/src/lib.rs | 13 ++ test_ffi/tests/bench.js | 33 +++++ test_ffi/tests/ffi_types.ts | 24 ++++ test_ffi/tests/integration_tests.rs | 2 + test_ffi/tests/test.js | 3 + 10 files changed, 227 insertions(+), 66 deletions(-) diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts index 09380387be..ae306d8195 100644 --- a/cli/dts/lib.deno.unstable.d.ts +++ b/cli/dts/lib.deno.unstable.d.ts @@ -393,6 +393,8 @@ declare namespace Deno { | "usize" | "isize"; + type NativeBooleanType = "bool"; + type NativePointerType = "pointer"; type NativeBufferType = "buffer"; @@ -408,6 +410,7 @@ declare namespace Deno { export type NativeType = | NativeNumberType | NativeBigIntType + | NativeBooleanType | NativePointerType | NativeBufferType | NativeFunctionType; @@ -419,6 +422,7 @@ declare namespace Deno { type ToNativeTypeMap = & Record & Record + & Record & Record & Record & Record; @@ -455,6 +459,7 @@ declare namespace Deno { type FromNativeTypeMap = & Record & Record + & Record & Record & Record & Record; @@ -610,6 +615,8 @@ declare namespace Deno { pointer: bigint; + /** Gets a boolean at the specified byte offset from the pointer. */ + getBool(offset?: number): boolean; /** Gets an unsigned 8-bit integer at the specified byte offset from the pointer. */ getUint8(offset?: number): number; /** Gets a signed 8-bit integer at the specified byte offset from the pointer. */ diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js index 6957b94188..c9d6d629cc 100644 --- a/ext/ffi/00_ffi.js +++ b/ext/ffi/00_ffi.js @@ -45,6 +45,12 @@ this.pointer = pointer; } + getBool(offset = 0) { + return ops.op_ffi_read_bool( + offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + ); + } + getUint8(offset = 0) { return ops.op_ffi_read_u8( offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, diff --git a/ext/ffi/jit_trampoline.rs b/ext/ffi/jit_trampoline.rs index 75cdae51de..6cb8ec74c2 100644 --- a/ext/ffi/jit_trampoline.rs +++ b/ext/ffi/jit_trampoline.rs @@ -23,6 +23,7 @@ macro_rules! cstr { fn native_arg_to_c(ty: &NativeType) -> &'static str { match ty { + NativeType::Bool => "bool", NativeType::U8 | NativeType::U16 | NativeType::U32 => "uint32_t", NativeType::I8 | NativeType::I16 | NativeType::I32 => "int32_t", NativeType::Void => "void", @@ -39,6 +40,7 @@ fn native_arg_to_c(ty: &NativeType) -> &'static str { fn native_to_c(ty: &NativeType) -> &'static str { match ty { + NativeType::Bool => "bool", NativeType::U8 => "uint8_t", NativeType::U16 => "uint16_t", NativeType::U32 => "uint32_t", diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs index 70591411a8..ead9be2839 100644 --- a/ext/ffi/lib.rs +++ b/ext/ffi/lib.rs @@ -23,7 +23,6 @@ use deno_core::ZeroCopyBuf; use dlopen::raw::Library; use libffi::middle::Arg; use libffi::middle::Cif; -use libffi::raw::*; use serde::Deserialize; use serde::Serialize; use std::borrow::Cow; @@ -186,6 +185,7 @@ pub fn init(unstable: bool) -> Extension { op_ffi_get_buf::decl::

(), op_ffi_buf_copy_into::decl::

(), op_ffi_cstr_read::decl::

(), + op_ffi_read_bool::decl::

(), op_ffi_read_u8::decl::

(), op_ffi_read_i8::decl::

(), op_ffi_read_u16::decl::

(), @@ -253,6 +253,7 @@ pub fn init(unstable: bool) -> Extension { #[serde(rename_all = "lowercase")] enum NativeType { Void, + Bool, U8, I8, U16, @@ -274,7 +275,7 @@ impl From for libffi::middle::Type { fn from(native_type: NativeType) -> Self { match native_type { NativeType::Void => libffi::middle::Type::void(), - NativeType::U8 => libffi::middle::Type::u8(), + NativeType::U8 | NativeType::Bool => libffi::middle::Type::u8(), NativeType::I8 => libffi::middle::Type::i8(), NativeType::U16 => libffi::middle::Type::u16(), NativeType::I16 => libffi::middle::Type::i16(), @@ -298,6 +299,7 @@ impl From for libffi::middle::Type { #[repr(C)] union NativeValue { void_value: (), + bool_value: bool, u8_value: u8, i8_value: i8, u16_value: u16, @@ -317,6 +319,7 @@ impl NativeValue { unsafe fn as_arg(&self, native_type: NativeType) -> Arg { match native_type { NativeType::Void => unreachable!(), + NativeType::Bool => Arg::new(&self.bool_value), NativeType::U8 => Arg::new(&self.u8_value), NativeType::I8 => Arg::new(&self.i8_value), NativeType::U16 => Arg::new(&self.u16_value), @@ -339,6 +342,7 @@ impl NativeValue { unsafe fn to_value(&self, native_type: NativeType) -> Value { match native_type { NativeType::Void => Value::Null, + NativeType::Bool => Value::from(self.bool_value), NativeType::U8 => Value::from(self.u8_value), NativeType::I8 => Value::from(self.i8_value), NativeType::U16 => Value::from(self.u16_value), @@ -402,6 +406,11 @@ impl NativeValue { let local_value: v8::Local = v8::undefined(scope).into(); local_value.into() } + NativeType::Bool => { + let local_value: v8::Local = + v8::Boolean::new(scope, self.bool_value).into(); + local_value.into() + } NativeType::U8 => { let local_value: v8::Local = v8::Integer::new_from_unsigned(scope, self.u8_value as u32).into(); @@ -743,6 +752,7 @@ impl fast_api::FastFunction for FfiFastCallTemplate { impl From<&NativeType> for fast_api::Type { fn from(native_type: &NativeType) -> Self { match native_type { + NativeType::Bool => fast_api::Type::Bool, NativeType::U8 | NativeType::U16 | NativeType::U32 => { fast_api::Type::Uint32 } @@ -907,6 +917,16 @@ fn make_sync_fn<'s>( weak.to_local(scope).unwrap() } +#[inline] +fn ffi_parse_bool_arg( + arg: v8::Local, +) -> Result { + let bool_value = v8::Local::::try_from(arg) + .map_err(|_| type_error("Invalid FFI u8 type, expected boolean"))? + .is_true(); + Ok(NativeValue { bool_value }) +} + #[inline] fn ffi_parse_u8_arg( arg: v8::Local, @@ -1163,6 +1183,9 @@ where for (index, native_type) in parameter_types.iter().enumerate() { let value = args.get_index(scope, index as u32).unwrap(); match native_type { + NativeType::Bool => { + ffi_args.push(ffi_parse_bool_arg(value)?); + } NativeType::U8 => { ffi_args.push(ffi_parse_u8_arg(value)?); } @@ -1239,6 +1262,9 @@ where for (index, native_type) in parameter_types.iter().enumerate() { let value = args.get(index as i32); match native_type { + NativeType::Bool => { + ffi_args.push(ffi_parse_bool_arg(value)?); + } NativeType::U8 => { ffi_args.push(ffi_parse_u8_arg(value)?); } @@ -1297,6 +1323,9 @@ where NativeType::Void => NativeValue { void_value: cif.call::<()>(*fun_ptr, &call_args), }, + NativeType::Bool => NativeValue { + bool_value: cif.call::(*fun_ptr, &call_args), + }, NativeType::U8 => NativeValue { u8_value: cif.call::(*fun_ptr, &call_args), }, @@ -1365,6 +1394,9 @@ fn ffi_call( NativeType::Void => NativeValue { void_value: cif.call::<()>(fun_ptr, &call_args), }, + NativeType::Bool => NativeValue { + bool_value: cif.call::(fun_ptr, &call_args), + }, NativeType::U8 => NativeValue { u8_value: cif.call::(fun_ptr, &call_args), }, @@ -1438,6 +1470,8 @@ impl Resource for UnsafeCallbackResource { } struct CallbackInfo { + pub parameters: Vec, + pub result: NativeType, pub async_work_sender: mpsc::UnboundedSender, pub callback: NonNull, pub context: NonNull, @@ -1445,7 +1479,7 @@ struct CallbackInfo { } unsafe extern "C" fn deno_ffi_callback( - cif: &libffi::low::ffi_cif, + _cif: &libffi::low::ffi_cif, result: &mut c_void, args: *const *const c_void, info: &CallbackInfo, @@ -1453,30 +1487,15 @@ unsafe extern "C" fn deno_ffi_callback( LOCAL_ISOLATE_POINTER.with(|s| { if ptr::eq(*s.borrow(), info.isolate) { // Own isolate thread, okay to call directly - do_ffi_callback( - cif, - result, - args, - info.callback, - info.context, - info.isolate, - ); + do_ffi_callback(info, result, args); } else { let async_work_sender = &info.async_work_sender; // SAFETY: Safe as this function blocks until `do_ffi_callback` completes and a response message is received. - let cif: &'static libffi::low::ffi_cif = std::mem::transmute(cif); let result: &'static mut c_void = std::mem::transmute(result); let info: &'static CallbackInfo = std::mem::transmute(info); let (response_sender, response_receiver) = sync_channel::<()>(0); let fut = Box::new(move || { - do_ffi_callback( - cif, - result, - args, - info.callback, - info.context, - info.isolate, - ); + do_ffi_callback(info, result, args); response_sender.send(()).unwrap(); }); async_work_sender.unbounded_send(fut).unwrap(); @@ -1486,13 +1505,13 @@ unsafe extern "C" fn deno_ffi_callback( } unsafe fn do_ffi_callback( - cif: &libffi::low::ffi_cif, + info: &CallbackInfo, result: &mut c_void, args: *const *const c_void, - callback: NonNull, - context: NonNull, - isolate: *mut v8::Isolate, ) { + let callback: NonNull = info.callback; + let context: NonNull = info.context; + let isolate: *mut v8::Isolate = info.isolate; let isolate = &mut *isolate; let callback = v8::Global::from_raw(isolate, callback); let context = std::mem::transmute::< @@ -1513,47 +1532,49 @@ unsafe fn do_ffi_callback( let scope = &mut v8::HandleScope::new(&mut cb_scope); let func = callback.open(scope); let result = result as *mut c_void; - let repr: &[*mut ffi_type] = - std::slice::from_raw_parts(cif.arg_types, cif.nargs as usize); let vals: &[*const c_void] = - std::slice::from_raw_parts(args, cif.nargs as usize); + std::slice::from_raw_parts(args, info.parameters.len() as usize); let mut params: Vec> = vec![]; - for (repr, val) in repr.iter().zip(vals) { - let value: v8::Local = match (*(*repr)).type_ as _ { - FFI_TYPE_FLOAT => { + for (native_type, val) in info.parameters.iter().zip(vals) { + let value: v8::Local = match native_type { + NativeType::Bool => { + let value = *((*val) as *const bool); + v8::Boolean::new(scope, value).into() + } + NativeType::F32 => { let value = *((*val) as *const f32); v8::Number::new(scope, value as f64).into() } - FFI_TYPE_DOUBLE => { + NativeType::F64 => { let value = *((*val) as *const f64); v8::Number::new(scope, value).into() } - FFI_TYPE_SINT8 => { + NativeType::I8 => { let value = *((*val) as *const i8); v8::Integer::new(scope, value as i32).into() } - FFI_TYPE_UINT8 => { + NativeType::U8 => { let value = *((*val) as *const u8); v8::Integer::new_from_unsigned(scope, value as u32).into() } - FFI_TYPE_SINT16 => { + NativeType::I16 => { let value = *((*val) as *const i16); v8::Integer::new(scope, value as i32).into() } - FFI_TYPE_UINT16 => { + NativeType::U16 => { let value = *((*val) as *const u16); v8::Integer::new_from_unsigned(scope, value as u32).into() } - FFI_TYPE_INT | FFI_TYPE_SINT32 => { + NativeType::I32 => { let value = *((*val) as *const i32); v8::Integer::new(scope, value).into() } - FFI_TYPE_UINT32 => { + NativeType::U32 => { let value = *((*val) as *const u32); v8::Integer::new_from_unsigned(scope, value).into() } - FFI_TYPE_SINT64 => { + NativeType::I64 => { let result = *((*val) as *const i64); if result > MAX_SAFE_INTEGER as i64 || result < MIN_SAFE_INTEGER as i64 { @@ -1562,7 +1583,7 @@ unsafe fn do_ffi_callback( v8::Number::new(scope, result as f64).into() } } - FFI_TYPE_UINT64 => { + NativeType::U64 => { let result = *((*val) as *const u64); if result > MAX_SAFE_INTEGER as u64 { v8::BigInt::new_from_u64(scope, result).into() @@ -1570,15 +1591,14 @@ unsafe fn do_ffi_callback( v8::Number::new(scope, result as f64).into() } } - FFI_TYPE_POINTER | FFI_TYPE_STRUCT => { - let result = *((*val) as *const u64); - if result > MAX_SAFE_INTEGER as u64 { - v8::BigInt::new_from_u64(scope, result).into() + NativeType::Pointer | NativeType::Buffer | NativeType::Function => { + let result = *((*val) as *const usize); + if result > MAX_SAFE_INTEGER as usize { + v8::BigInt::new_from_u64(scope, result as u64).into() } else { v8::Number::new(scope, result as f64).into() } } - FFI_TYPE_VOID => v8::undefined(scope).into(), _ => { unreachable!() } @@ -1594,30 +1614,36 @@ unsafe fn do_ffi_callback( // JS function threw an exception. Set the return value to zero and return. // The exception continue propagating up the call chain when the event loop // resumes. - match (*cif.rtype).type_ as _ { - FFI_TYPE_INT | FFI_TYPE_SINT32 | FFI_TYPE_UINT32 => { + match info.result { + NativeType::Bool => { + *(result as *mut bool) = false; + } + NativeType::U32 | NativeType::I32 => { // zero is equal for signed and unsigned alike *(result as *mut u32) = 0; } - FFI_TYPE_FLOAT => { + NativeType::F32 => { *(result as *mut f32) = 0.0; } - FFI_TYPE_DOUBLE => { + NativeType::F64 => { *(result as *mut f64) = 0.0; } - FFI_TYPE_SINT8 | FFI_TYPE_UINT8 => { + NativeType::U8 | NativeType::I8 => { // zero is equal for signed and unsigned alike *(result as *mut u8) = 0; } - FFI_TYPE_SINT16 | FFI_TYPE_UINT16 => { + NativeType::U16 | NativeType::I16 => { // zero is equal for signed and unsigned alike *(result as *mut u16) = 0; } - FFI_TYPE_POINTER | FFI_TYPE_STRUCT | FFI_TYPE_UINT64 - | FFI_TYPE_SINT64 => { + NativeType::Pointer + | NativeType::Buffer + | NativeType::Function + | NativeType::U64 + | NativeType::I64 => { *(result as *mut usize) = 0; } - FFI_TYPE_VOID => { + NativeType::Void => { // nop } _ => { @@ -1629,8 +1655,16 @@ unsafe fn do_ffi_callback( } let value = call_result.unwrap(); - match (*cif.rtype).type_ as _ { - FFI_TYPE_INT | FFI_TYPE_SINT32 => { + match info.result { + NativeType::Bool => { + let value = if let Ok(value) = v8::Local::::try_from(value) { + value.is_true() + } else { + value.boolean_value(scope) + }; + *(result as *mut bool) = value; + } + NativeType::I32 => { let value = if let Ok(value) = v8::Local::::try_from(value) { value.value() as i32 } else { @@ -1641,7 +1675,7 @@ unsafe fn do_ffi_callback( }; *(result as *mut i32) = value; } - FFI_TYPE_FLOAT => { + NativeType::F32 => { let value = if let Ok(value) = v8::Local::::try_from(value) { value.value() as f32 } else { @@ -1652,7 +1686,7 @@ unsafe fn do_ffi_callback( }; *(result as *mut f32) = value; } - FFI_TYPE_DOUBLE => { + NativeType::F64 => { let value = if let Ok(value) = v8::Local::::try_from(value) { value.value() } else { @@ -1663,7 +1697,7 @@ unsafe fn do_ffi_callback( }; *(result as *mut f64) = value; } - FFI_TYPE_POINTER | FFI_TYPE_STRUCT => { + NativeType::Pointer | NativeType::Buffer | NativeType::Function => { let pointer = if let Ok(value) = v8::Local::::try_from(value) { @@ -1692,7 +1726,7 @@ unsafe fn do_ffi_callback( }; *(result as *mut *const u8) = pointer; } - FFI_TYPE_SINT8 => { + NativeType::I8 => { let value = if let Ok(value) = v8::Local::::try_from(value) { value.value() as i8 } else { @@ -1703,7 +1737,7 @@ unsafe fn do_ffi_callback( }; *(result as *mut i8) = value; } - FFI_TYPE_UINT8 => { + NativeType::U8 => { let value = if let Ok(value) = v8::Local::::try_from(value) { value.value() as u8 } else { @@ -1714,7 +1748,7 @@ unsafe fn do_ffi_callback( }; *(result as *mut u8) = value; } - FFI_TYPE_SINT16 => { + NativeType::I16 => { let value = if let Ok(value) = v8::Local::::try_from(value) { value.value() as i16 } else { @@ -1725,7 +1759,7 @@ unsafe fn do_ffi_callback( }; *(result as *mut i16) = value; } - FFI_TYPE_UINT16 => { + NativeType::U16 => { let value = if let Ok(value) = v8::Local::::try_from(value) { value.value() as u16 } else { @@ -1736,7 +1770,7 @@ unsafe fn do_ffi_callback( }; *(result as *mut u16) = value; } - FFI_TYPE_UINT32 => { + NativeType::U32 => { let value = if let Ok(value) = v8::Local::::try_from(value) { value.value() as u32 } else { @@ -1747,7 +1781,7 @@ unsafe fn do_ffi_callback( }; *(result as *mut u32) = value; } - FFI_TYPE_SINT64 => { + NativeType::I64 => { if let Ok(value) = v8::Local::::try_from(value) { *(result as *mut i64) = value.i64_value().0; } else if let Ok(value) = v8::Local::::try_from(value) { @@ -1759,7 +1793,7 @@ unsafe fn do_ffi_callback( as i64; } } - FFI_TYPE_UINT64 => { + NativeType::U64 => { if let Ok(value) = v8::Local::::try_from(value) { *(result as *mut u64) = value.u64_value().0; } else if let Ok(value) = v8::Local::::try_from(value) { @@ -1771,7 +1805,7 @@ unsafe fn do_ffi_callback( as u64; } } - FFI_TYPE_VOID => { + NativeType::Void => { // nop } _ => { @@ -1817,6 +1851,8 @@ where let context = v8::Global::new(scope, current_context).into_raw(); let info = Box::leak(Box::new(CallbackInfo { + parameters: args.parameters.clone(), + result: args.result, async_work_sender, callback, context, @@ -1941,6 +1977,13 @@ fn op_ffi_get_static<'scope>( NativeType::Void => { return Err(type_error("Invalid FFI static type 'void'")); } + NativeType::Bool => { + // SAFETY: ptr is user provided + let result = unsafe { ptr::read_unaligned(data_ptr as *const bool) }; + let boolean: v8::Local = + v8::Boolean::new(scope, result).into(); + boolean.into() + } NativeType::U8 => { // SAFETY: ptr is user provided let result = unsafe { ptr::read_unaligned(data_ptr as *const u8) }; @@ -2239,6 +2282,23 @@ where Ok(value.into()) } +#[op] +fn op_ffi_read_bool( + state: &mut deno_core::OpState, + ptr: usize, +) -> Result +where + FP: FfiPermissions + 'static, +{ + check_unstable(state, "Deno.UnsafePointerView#getBool"); + + let permissions = state.borrow_mut::(); + permissions.check(None)?; + + // SAFETY: ptr is user provided. + Ok(unsafe { ptr::read_unaligned(ptr as *const bool) }) +} + #[op] fn op_ffi_read_u8( state: &mut deno_core::OpState, diff --git a/ext/ffi/prelude.h b/ext/ffi/prelude.h index 89ae162c1d..2da1e65238 100644 --- a/ext/ffi/prelude.h +++ b/ext/ffi/prelude.h @@ -1,5 +1,16 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +/* Boolean type */ + +#ifndef _STDBOOL_H +#define _STDBOOL_H + +#define bool _Bool +#define true 1 +#define false 0 + +#endif + /* Exact integral types. */ /* Signed. */ diff --git a/test_ffi/src/lib.rs b/test_ffi/src/lib.rs index 08ef7cb7f1..812b563ef7 100644 --- a/test_ffi/src/lib.rs +++ b/test_ffi/src/lib.rs @@ -94,6 +94,11 @@ pub extern "C" fn add_f64(a: f64, b: f64) -> f64 { a + b } +#[no_mangle] +pub extern "C" fn and(a: bool, b: bool) -> bool { + a && b +} + #[no_mangle] unsafe extern "C" fn hash(ptr: *const u8, length: u32) -> u32 { let buf = std::slice::from_raw_parts(ptr, length as usize); @@ -257,6 +262,9 @@ pub extern "C" fn call_stored_function_thread_safe_and_log() { #[no_mangle] pub extern "C" fn nop() {} +#[no_mangle] +pub extern "C" fn nop_bool(_a: bool) {} + #[no_mangle] pub extern "C" fn nop_u8(_a: u8) {} @@ -296,6 +304,11 @@ pub extern "C" fn nop_f64(_a: f64) {} #[no_mangle] pub extern "C" fn nop_buffer(_buffer: *mut [u8; 8]) {} +#[no_mangle] +pub extern "C" fn return_bool() -> bool { + true +} + #[no_mangle] pub extern "C" fn return_u8() -> u8 { 255 diff --git a/test_ffi/tests/bench.js b/test_ffi/tests/bench.js index c1a3d630fa..b590970829 100644 --- a/test_ffi/tests/bench.js +++ b/test_ffi/tests/bench.js @@ -15,6 +15,7 @@ const dylib = Deno.dlopen(libPath, { "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" }, @@ -28,6 +29,7 @@ const dylib = Deno.dlopen(libPath, { "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" }, @@ -43,6 +45,11 @@ const dylib = Deno.dlopen(libPath, { "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": { @@ -100,6 +107,11 @@ const dylib = Deno.dlopen(libPath, { 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": { @@ -267,6 +279,11 @@ 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); @@ -343,6 +360,11 @@ 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(); @@ -400,6 +422,11 @@ 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); @@ -465,6 +492,12 @@ 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(); diff --git a/test_ffi/tests/ffi_types.ts b/test_ffi/tests/ffi_types.ts index be8a3f7707..76c013a8f3 100644 --- a/test_ffi/tests/ffi_types.ts +++ b/test_ffi/tests/ffi_types.ts @@ -42,6 +42,10 @@ const remote = Deno.dlopen( parameters: ["buffer"], result: "void", }, + method24: { + parameters: ["bool"], + result: "bool", + }, static1: { type: "usize" }, static2: { type: "pointer" }, static3: { type: "usize" }, @@ -56,6 +60,7 @@ const remote = Deno.dlopen( static12: { type: "i64" }, static13: { type: "f32" }, static14: { type: "f64" }, + static15: { type: "bool" }, } as const, ); @@ -258,6 +263,22 @@ remote.symbols.method23(0); remote.symbols.method23(0n); 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. + 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); + remote.symbols.method24(Math.random() > 0.5); + // @ts-expect-error: Invalid member type const static1_wrong: null = remote.symbols.static1; const static1_right: Deno.PointerValue = remote.symbols.static1; @@ -300,6 +321,9 @@ 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; // Adapted from https://stackoverflow.com/a/53808212/10873797 type Equal = (() => G extends T ? 1 : 2) extends diff --git a/test_ffi/tests/integration_tests.rs b/test_ffi/tests/integration_tests.rs index 0792935509..88da8a0b99 100644 --- a/test_ffi/tests/integration_tests.rs +++ b/test_ffi/tests/integration_tests.rs @@ -78,6 +78,8 @@ fn basic() { -9007199254740992n\n\ 579.9119873046875\n\ 579.912\n\ + true\n\ + false\n\ 579\n\ 8589934590\n\ -8589934590\n\ diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js index 7e8c41cfeb..f71f23adc8 100644 --- a/test_ffi/tests/test.js +++ b/test_ffi/tests/test.js @@ -59,6 +59,7 @@ const dylib = Deno.dlopen(libPath, { "add_isize": { parameters: ["isize", "isize"], result: "isize" }, "add_f32": { parameters: ["f32", "f32"], result: "f32" }, "add_f64": { parameters: ["f64", "f64"], result: "f64" }, + "and": { parameters: ["bool", "bool"], result: "bool" }, "add_u32_nonblocking": { name: "add_u32", parameters: ["u32", "u32"], @@ -290,6 +291,8 @@ 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)); // Test adders as nonblocking calls console.log(await dylib.symbols.add_i32_nonblocking(123, 456));