summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorAapo Alasuutari <aapo.alasuutari@gmail.com>2022-09-05 06:26:52 +0300
committerGitHub <noreply@github.com>2022-09-05 08:56:52 +0530
commit16dbf4adc390c9fb7656372b42811c1929e755dd (patch)
treebff7c876c97e5eb56d2d08de0198fe7640ddb031 /ext
parent08a6af398fd92517193e20117f9971c272b1bb5f (diff)
feat(ext/ffi): Support bool FFI type (#15754)
Diffstat (limited to 'ext')
-rw-r--r--ext/ffi/00_ffi.js6
-rw-r--r--ext/ffi/jit_trampoline.rs2
-rw-r--r--ext/ffi/lib.rs192
-rw-r--r--ext/ffi/prelude.h11
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. */