summaryrefslogtreecommitdiff
path: root/ops
diff options
context:
space:
mode:
Diffstat (limited to 'ops')
-rw-r--r--ops/fast_call.rs6
-rw-r--r--ops/lib.rs38
-rw-r--r--ops/optimizer.rs92
-rw-r--r--ops/optimizer_tests/op_ffi_ptr_value.expected11
-rw-r--r--ops/optimizer_tests/op_ffi_ptr_value.out127
-rw-r--r--ops/optimizer_tests/op_ffi_ptr_value.rs3
6 files changed, 273 insertions, 4 deletions
diff --git a/ops/fast_call.rs b/ops/fast_call.rs
index fe6455f37..a7ca51d4f 100644
--- a/ops/fast_call.rs
+++ b/ops/fast_call.rs
@@ -418,13 +418,14 @@ pub(crate) fn generate(
fn q_fast_ty(v: &FastValue) -> Quote {
match v {
FastValue::Void => q!({ () }),
+ FastValue::Bool => q!({ bool }),
FastValue::U32 => q!({ u32 }),
FastValue::I32 => q!({ i32 }),
FastValue::U64 => q!({ u64 }),
FastValue::I64 => q!({ i64 }),
FastValue::F32 => q!({ f32 }),
FastValue::F64 => q!({ f64 }),
- FastValue::Bool => q!({ bool }),
+ FastValue::Pointer => q!({ *mut ::std::ffi::c_void }),
FastValue::V8Value => q!({ v8::Local<v8::Value> }),
FastValue::Uint8Array
| FastValue::Uint32Array
@@ -436,13 +437,14 @@ fn q_fast_ty(v: &FastValue) -> Quote {
fn q_fast_ty_variant(v: &FastValue) -> Quote {
match v {
FastValue::Void => q!({ Void }),
+ FastValue::Bool => q!({ Bool }),
FastValue::U32 => q!({ Uint32 }),
FastValue::I32 => q!({ Int32 }),
FastValue::U64 => q!({ Uint64 }),
FastValue::I64 => q!({ Int64 }),
FastValue::F32 => q!({ Float32 }),
FastValue::F64 => q!({ Float64 }),
- FastValue::Bool => q!({ Bool }),
+ FastValue::Pointer => q!({ Pointer }),
FastValue::V8Value => q!({ V8Value }),
FastValue::Uint8Array => q!({ TypedArray(CType::Uint8) }),
FastValue::Uint32Array => q!({ TypedArray(CType::Uint32) }),
diff --git a/ops/lib.rs b/ops/lib.rs
index d8f28dd37..28cb3c320 100644
--- a/ops/lib.rs
+++ b/ops/lib.rs
@@ -474,6 +474,13 @@ fn codegen_arg(
let #ident = #blk;
};
}
+ // Fast path for `*const c_void` and `*mut c_void`
+ if is_ptr_cvoid(&**ty) {
+ let blk = codegen_cvoid_ptr(core, idx);
+ return quote! {
+ let #ident = #blk;
+ };
+ }
// Otherwise deserialize it via serde_v8
quote! {
let #ident = args.get(#idx as i32);
@@ -560,6 +567,19 @@ fn codegen_u8_ptr(core: &TokenStream2, idx: usize) -> TokenStream2 {
}}
}
+fn codegen_cvoid_ptr(core: &TokenStream2, idx: usize) -> TokenStream2 {
+ quote! {{
+ let value = args.get(#idx as i32);
+ if value.is_null() {
+ std::ptr::null_mut()
+ } else if let Ok(b) = #core::v8::Local::<#core::v8::External>::try_from(value) {
+ b.value()
+ } else {
+ return #core::_ops::throw_type_error(scope, format!("Expected External at position {}", #idx));
+ }
+ }}
+}
+
fn codegen_u32_mut_slice(core: &TokenStream2, idx: usize) -> TokenStream2 {
quote! {
if let Ok(view) = #core::v8::Local::<#core::v8::Uint32Array>::try_from(args.get(#idx as i32)) {
@@ -626,6 +646,15 @@ fn codegen_sync_ret(
quote! {
rv.set_uint32(result as u32);
}
+ } else if is_ptr_cvoid(output) || is_ptr_cvoid_rv(output) {
+ quote! {
+ if result.is_null() {
+ // External canot contain a null pointer, null pointers are instead represented as null.
+ rv.set_null();
+ } else {
+ rv.set(v8::External::new(scope, result as *mut ::std::ffi::c_void).into());
+ }
+ }
} else {
quote! {
match #core::serde_v8::to_v8(scope, result) {
@@ -723,6 +752,15 @@ fn is_ptr_u8(ty: impl ToTokens) -> bool {
tokens(ty) == "* const u8"
}
+fn is_ptr_cvoid(ty: impl ToTokens) -> bool {
+ tokens(&ty) == "* const c_void" || tokens(&ty) == "* mut c_void"
+}
+
+fn is_ptr_cvoid_rv(ty: impl ToTokens) -> bool {
+ tokens(&ty).contains("Result < * const c_void")
+ || tokens(&ty).contains("Result < * mut c_void")
+}
+
fn is_optional_fast_callback_option(ty: impl ToTokens) -> bool {
tokens(&ty).contains("Option < & mut FastApiCallbackOptions")
}
diff --git a/ops/optimizer.rs b/ops/optimizer.rs
index ae3175511..a3ccd51b3 100644
--- a/ops/optimizer.rs
+++ b/ops/optimizer.rs
@@ -45,6 +45,7 @@ enum TransformKind {
SliceU8(bool),
SliceF64(bool),
PtrU8,
+ PtrVoid,
WasmMemory,
}
@@ -90,6 +91,13 @@ impl Transform {
index,
}
}
+
+ fn void_ptr(index: usize) -> Self {
+ Transform {
+ kind: TransformKind::PtrVoid,
+ index,
+ }
+ }
}
#[derive(Debug, PartialEq)]
@@ -195,19 +203,25 @@ impl Transform {
.as_ptr();
})
}
+ TransformKind::PtrVoid => {
+ *ty = parse_quote! { *mut ::std::ffi::c_void };
+
+ q!(Vars {}, {})
+ }
}
}
}
fn get_fast_scalar(s: &str) -> Option<FastValue> {
match s {
+ "bool" => Some(FastValue::Bool),
"u32" => Some(FastValue::U32),
"i32" => Some(FastValue::I32),
"u64" => Some(FastValue::U64),
"i64" => Some(FastValue::I64),
"f32" => Some(FastValue::F32),
"f64" => Some(FastValue::F64),
- "bool" => Some(FastValue::Bool),
+ "* const c_void" | "* mut c_void" => Some(FastValue::Pointer),
"ResourceId" => Some(FastValue::U32),
_ => None,
}
@@ -226,13 +240,14 @@ fn can_return_fast(v: &FastValue) -> bool {
#[derive(Debug, PartialEq, Clone)]
pub(crate) enum FastValue {
Void,
+ Bool,
U32,
I32,
U64,
I64,
F32,
F64,
- Bool,
+ Pointer,
V8Value,
Uint8Array,
Uint32Array,
@@ -414,6 +429,31 @@ impl Optimizer {
{
self.fast_result = Some(FastValue::Void);
}
+ Some(GenericArgument::Type(Type::Ptr(TypePtr {
+ mutability: Some(_),
+ elem,
+ ..
+ }))) => {
+ match &**elem {
+ Type::Path(TypePath {
+ path: Path { segments, .. },
+ ..
+ }) => {
+ // Is `T` a c_void?
+ let segment = single_segment(segments)?;
+ match segment {
+ PathSegment { ident, .. } if ident == "c_void" => {
+ self.fast_result = Some(FastValue::Pointer);
+ return Ok(());
+ }
+ _ => {
+ return Err(BailoutReason::FastUnsupportedParamType)
+ }
+ }
+ }
+ _ => return Err(BailoutReason::FastUnsupportedParamType),
+ }
+ }
_ => return Err(BailoutReason::FastUnsupportedParamType),
}
}
@@ -430,6 +470,29 @@ impl Optimizer {
}
};
}
+ Type::Ptr(TypePtr {
+ mutability: Some(_),
+ elem,
+ ..
+ }) => {
+ match &**elem {
+ Type::Path(TypePath {
+ path: Path { segments, .. },
+ ..
+ }) => {
+ // Is `T` a c_void?
+ let segment = single_segment(segments)?;
+ match segment {
+ PathSegment { ident, .. } if ident == "c_void" => {
+ self.fast_result = Some(FastValue::Pointer);
+ return Ok(());
+ }
+ _ => return Err(BailoutReason::FastUnsupportedParamType),
+ }
+ }
+ _ => return Err(BailoutReason::FastUnsupportedParamType),
+ }
+ }
_ => return Err(BailoutReason::FastUnsupportedParamType),
};
@@ -684,6 +747,31 @@ impl Optimizer {
}
_ => return Err(BailoutReason::FastUnsupportedParamType),
},
+ // *const T
+ Type::Ptr(TypePtr {
+ elem,
+ mutability: Some(_),
+ ..
+ }) => match &**elem {
+ Type::Path(TypePath {
+ path: Path { segments, .. },
+ ..
+ }) => {
+ let segment = single_segment(segments)?;
+ match segment {
+ // Is `T` a c_void?
+ PathSegment { ident, .. } if ident == "c_void" => {
+ self.fast_parameters.push(FastValue::Pointer);
+ assert!(self
+ .transforms
+ .insert(index, Transform::void_ptr(index))
+ .is_none());
+ }
+ _ => return Err(BailoutReason::FastUnsupportedParamType),
+ }
+ }
+ _ => return Err(BailoutReason::FastUnsupportedParamType),
+ },
_ => return Err(BailoutReason::FastUnsupportedParamType),
},
_ => return Err(BailoutReason::FastUnsupportedParamType),
diff --git a/ops/optimizer_tests/op_ffi_ptr_value.expected b/ops/optimizer_tests/op_ffi_ptr_value.expected
new file mode 100644
index 000000000..00a28591c
--- /dev/null
+++ b/ops/optimizer_tests/op_ffi_ptr_value.expected
@@ -0,0 +1,11 @@
+=== Optimizer Dump ===
+returns_result: false
+has_ref_opstate: false
+has_rc_opstate: false
+has_fast_callback_option: false
+needs_fast_callback_option: true
+fast_result: Some(Void)
+fast_parameters: [V8Value, Pointer, Uint32Array]
+transforms: {0: Transform { kind: PtrVoid, index: 0 }, 1: Transform { kind: SliceU32(true), index: 1 }}
+is_async: false
+fast_compatible: true
diff --git a/ops/optimizer_tests/op_ffi_ptr_value.out b/ops/optimizer_tests/op_ffi_ptr_value.out
new file mode 100644
index 000000000..bfbbd5ae7
--- /dev/null
+++ b/ops/optimizer_tests/op_ffi_ptr_value.out
@@ -0,0 +1,127 @@
+#[allow(non_camel_case_types)]
+///Auto-generated by `deno_ops`, i.e: `#[op]`
+///
+///Use `op_ffi_ptr_value::decl()` to get an op-declaration
+///you can include in a `deno_core::Extension`.
+pub struct op_ffi_ptr_value;
+#[doc(hidden)]
+impl op_ffi_ptr_value {
+ pub fn name() -> &'static str {
+ stringify!(op_ffi_ptr_value)
+ }
+ pub fn v8_fn_ptr<'scope>() -> deno_core::v8::FunctionCallback {
+ use deno_core::v8::MapFnTo;
+ Self::v8_func.map_fn_to()
+ }
+ pub fn decl<'scope>() -> deno_core::OpDecl {
+ deno_core::OpDecl {
+ name: Self::name(),
+ v8_fn_ptr: Self::v8_fn_ptr(),
+ enabled: true,
+ fast_fn: Some(
+ Box::new(op_ffi_ptr_value_fast {
+ _phantom: ::std::marker::PhantomData,
+ }),
+ ),
+ is_async: false,
+ is_unstable: false,
+ is_v8: false,
+ argc: 2usize,
+ }
+ }
+ #[inline]
+ #[allow(clippy::too_many_arguments)]
+ pub fn call(ptr: *mut c_void, out: &mut [u32]) {}
+ pub fn v8_func<'scope>(
+ scope: &mut deno_core::v8::HandleScope<'scope>,
+ args: deno_core::v8::FunctionCallbackArguments,
+ mut rv: deno_core::v8::ReturnValue,
+ ) {
+ let ctx = unsafe {
+ &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
+ as *const deno_core::_ops::OpCtx)
+ };
+ let arg_0 = {
+ let value = args.get(0usize as i32);
+ if value.is_null() {
+ std::ptr::null_mut()
+ } else if let Ok(b)
+ = deno_core::v8::Local::<deno_core::v8::External>::try_from(value) {
+ b.value()
+ } else {
+ return deno_core::_ops::throw_type_error(
+ scope,
+ format!("Expected External at position {}", 0usize),
+ );
+ }
+ };
+ let arg_1 = if let Ok(view)
+ = deno_core::v8::Local::<
+ deno_core::v8::Uint32Array,
+ >::try_from(args.get(1usize as i32)) {
+ let (offset, len) = (view.byte_offset(), view.byte_length());
+ let buffer = match view.buffer(scope) {
+ Some(v) => v,
+ None => {
+ return deno_core::_ops::throw_type_error(
+ scope,
+ format!("Expected Uint32Array at position {}", 1usize),
+ );
+ }
+ };
+ if let Some(data) = buffer.data() {
+ let store = data.cast::<u8>().as_ptr();
+ unsafe {
+ ::std::slice::from_raw_parts_mut(
+ store.add(offset) as *mut u32,
+ len / 4,
+ )
+ }
+ } else {
+ &mut []
+ }
+ } else {
+ return deno_core::_ops::throw_type_error(
+ scope,
+ format!("Expected Uint32Array at position {}", 1usize),
+ );
+ };
+ let result = Self::call(arg_0, arg_1);
+ let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
+ op_state.tracker.track_sync(ctx.id);
+ }
+}
+struct op_ffi_ptr_value_fast {
+ _phantom: ::std::marker::PhantomData<()>,
+}
+impl<'scope> deno_core::v8::fast_api::FastFunction for op_ffi_ptr_value_fast {
+ fn function(&self) -> *const ::std::ffi::c_void {
+ op_ffi_ptr_value_fast_fn as *const ::std::ffi::c_void
+ }
+ fn args(&self) -> &'static [deno_core::v8::fast_api::Type] {
+ use deno_core::v8::fast_api::Type::*;
+ use deno_core::v8::fast_api::CType;
+ &[V8Value, Pointer, TypedArray(CType::Uint32), CallbackOptions]
+ }
+ fn return_type(&self) -> deno_core::v8::fast_api::CType {
+ deno_core::v8::fast_api::CType::Void
+ }
+}
+fn op_ffi_ptr_value_fast_fn<'scope>(
+ _: deno_core::v8::Local<deno_core::v8::Object>,
+ ptr: *mut ::std::ffi::c_void,
+ out: *const deno_core::v8::fast_api::FastApiTypedArray<u32>,
+ fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
+) -> () {
+ use deno_core::v8;
+ use deno_core::_ops;
+ let out = match unsafe { &*out }.get_storage_if_aligned() {
+ Some(v) => v,
+ None => {
+ unsafe { &mut *fast_api_callback_options }.fallback = true;
+ return Default::default();
+ }
+ };
+ let result = op_ffi_ptr_value::call(ptr, out);
+ result
+}
diff --git a/ops/optimizer_tests/op_ffi_ptr_value.rs b/ops/optimizer_tests/op_ffi_ptr_value.rs
new file mode 100644
index 000000000..4c3364507
--- /dev/null
+++ b/ops/optimizer_tests/op_ffi_ptr_value.rs
@@ -0,0 +1,3 @@
+pub fn op_ffi_ptr_value(ptr: *mut c_void, out: &mut [u32]) {
+ // ...
+}