diff options
author | Aapo Alasuutari <aapo.alasuutari@gmail.com> | 2022-09-05 06:26:52 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-05 08:56:52 +0530 |
commit | 16dbf4adc390c9fb7656372b42811c1929e755dd (patch) | |
tree | bff7c876c97e5eb56d2d08de0198fe7640ddb031 /ext | |
parent | 08a6af398fd92517193e20117f9971c272b1bb5f (diff) |
feat(ext/ffi): Support bool FFI type (#15754)
Diffstat (limited to 'ext')
-rw-r--r-- | ext/ffi/00_ffi.js | 6 | ||||
-rw-r--r-- | ext/ffi/jit_trampoline.rs | 2 | ||||
-rw-r--r-- | ext/ffi/lib.rs | 192 | ||||
-rw-r--r-- | ext/ffi/prelude.h | 11 |
4 files changed, 145 insertions, 66 deletions
diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js index 6957b9418..c9d6d629c 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 75cdae51d..6cb8ec74c 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 70591411a..ead9be283 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<P: FfiPermissions + 'static>(unstable: bool) -> Extension { op_ffi_get_buf::decl::<P>(), op_ffi_buf_copy_into::decl::<P>(), op_ffi_cstr_read::decl::<P>(), + op_ffi_read_bool::decl::<P>(), op_ffi_read_u8::decl::<P>(), op_ffi_read_i8::decl::<P>(), op_ffi_read_u16::decl::<P>(), @@ -253,6 +253,7 @@ pub fn init<P: FfiPermissions + 'static>(unstable: bool) -> Extension { #[serde(rename_all = "lowercase")] enum NativeType { Void, + Bool, U8, I8, U16, @@ -274,7 +275,7 @@ impl From<NativeType> 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<NativeType> 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::Value> = v8::undefined(scope).into(); local_value.into() } + NativeType::Bool => { + let local_value: v8::Local<v8::Value> = + v8::Boolean::new(scope, self.bool_value).into(); + local_value.into() + } NativeType::U8 => { let local_value: v8::Local<v8::Value> = 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 } @@ -908,6 +918,16 @@ fn make_sync_fn<'s>( } #[inline] +fn ffi_parse_bool_arg( + arg: v8::Local<v8::Value>, +) -> Result<NativeValue, AnyError> { + let bool_value = v8::Local::<v8::Boolean>::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<v8::Value>, ) -> Result<NativeValue, AnyError> { @@ -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::<bool>(*fun_ptr, &call_args), + }, NativeType::U8 => NativeValue { u8_value: cif.call::<u8>(*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::<bool>(fun_ptr, &call_args), + }, NativeType::U8 => NativeValue { u8_value: cif.call::<u8>(fun_ptr, &call_args), }, @@ -1438,6 +1470,8 @@ impl Resource for UnsafeCallbackResource { } struct CallbackInfo { + pub parameters: Vec<NativeType>, + pub result: NativeType, pub async_work_sender: mpsc::UnboundedSender<PendingFfiAsyncWork>, pub callback: NonNull<v8::Function>, pub context: NonNull<v8::Context>, @@ -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<v8::Function>, - context: NonNull<v8::Context>, - isolate: *mut v8::Isolate, ) { + let callback: NonNull<v8::Function> = info.callback; + let context: NonNull<v8::Context> = 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<v8::Local<v8::Value>> = vec![]; - for (repr, val) in repr.iter().zip(vals) { - let value: v8::Local<v8::Value> = match (*(*repr)).type_ as _ { - FFI_TYPE_FLOAT => { + for (native_type, val) in info.parameters.iter().zip(vals) { + let value: v8::Local<v8::Value> = 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::<v8::Boolean>::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::<v8::Integer>::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::<v8::Number>::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::<v8::Number>::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::<v8::ArrayBufferView>::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::<v8::Integer>::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::<v8::Integer>::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::<v8::Integer>::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::<v8::Integer>::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::<v8::Integer>::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::<v8::BigInt>::try_from(value) { *(result as *mut i64) = value.i64_value().0; } else if let Ok(value) = v8::Local::<v8::Integer>::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::<v8::BigInt>::try_from(value) { *(result as *mut u64) = value.u64_value().0; } else if let Ok(value) = v8::Local::<v8::Integer>::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::Value> = + 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) }; @@ -2240,6 +2283,23 @@ where } #[op] +fn op_ffi_read_bool<FP>( + state: &mut deno_core::OpState, + ptr: usize, +) -> Result<bool, AnyError> +where + FP: FfiPermissions + 'static, +{ + check_unstable(state, "Deno.UnsafePointerView#getBool"); + + let permissions = state.borrow_mut::<FP>(); + permissions.check(None)?; + + // SAFETY: ptr is user provided. + Ok(unsafe { ptr::read_unaligned(ptr as *const bool) }) +} + +#[op] fn op_ffi_read_u8<FP>( state: &mut deno_core::OpState, ptr: usize, diff --git a/ext/ffi/prelude.h b/ext/ffi/prelude.h index 89ae162c1..2da1e6523 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. */ |