summaryrefslogtreecommitdiff
path: root/ops/op2
diff options
context:
space:
mode:
Diffstat (limited to 'ops/op2')
-rw-r--r--ops/op2/dispatch_slow.rs2
-rw-r--r--ops/op2/mod.rs38
-rw-r--r--ops/op2/signature.rs243
-rw-r--r--ops/op2/test_cases/sync/add.out47
-rw-r--r--ops/op2/test_cases/sync/add_options.out21
-rw-r--r--ops/op2/test_cases/sync/doc_comment.out35
-rw-r--r--ops/op2/test_cases/sync/generics.out59
-rw-r--r--ops/op2/test_cases/sync/generics.rs4
-rw-r--r--ops/op2/test_cases/sync/result_primitive.out79
-rw-r--r--ops/op2/test_cases/sync/result_void.out79
-rw-r--r--ops/op2/test_cases/sync/smi.out47
11 files changed, 544 insertions, 110 deletions
diff --git a/ops/op2/dispatch_slow.rs b/ops/op2/dispatch_slow.rs
index 478f872cd..bf36e5d83 100644
--- a/ops/op2/dispatch_slow.rs
+++ b/ops/op2/dispatch_slow.rs
@@ -74,7 +74,7 @@ pub(crate) fn generate_dispatch_slow(
} = &generator_state;
Ok(quote! {
- pub extern "C" fn #slow_function(#info: *const #deno_core::v8::FunctionCallbackInfo) {
+ extern "C" fn #slow_function(#info: *const #deno_core::v8::FunctionCallbackInfo) {
#with_scope
#with_retval
#with_args
diff --git a/ops/op2/mod.rs b/ops/op2/mod.rs
index 67a92d450..7f652fe1b 100644
--- a/ops/op2/mod.rs
+++ b/ops/op2/mod.rs
@@ -8,6 +8,7 @@ use quote::quote;
use quote::ToTokens;
use std::iter::zip;
use syn2::parse2;
+use syn2::parse_str;
use syn2::FnArg;
use syn2::ItemFn;
use syn2::Path;
@@ -104,6 +105,7 @@ fn generate_op2(
let call = Ident::new("call", Span::call_site());
let mut op_fn = func.clone();
op_fn.attrs.clear();
+ op_fn.sig.generics.params.clear();
op_fn.sig.ident = call.clone();
// Clear inert attributes
@@ -133,8 +135,8 @@ fn generate_op2(
let scope = Ident::new("scope", Span::call_site());
let info = Ident::new("info", Span::call_site());
let opctx = Ident::new("opctx", Span::call_site());
- let slow_function = Ident::new("slow_function", Span::call_site());
- let fast_function = Ident::new("fast_function", Span::call_site());
+ let slow_function = Ident::new("v8_fn_ptr", Span::call_site());
+ let fast_function = Ident::new("v8_fn_ptr_fast", Span::call_site());
let fast_api_callback_options =
Ident::new("fast_api_callback_options", Span::call_site());
@@ -196,13 +198,39 @@ fn generate_op2(
let arg_count: usize = generator_state.args.len();
let vis = func.vis;
+ let generic = signature
+ .generic_bounds
+ .keys()
+ .map(|s| format_ident!("{s}"))
+ .collect::<Vec<_>>();
+ let bound = signature
+ .generic_bounds
+ .values()
+ .map(|p| parse_str::<Path>(p).expect("Failed to reparse path"))
+ .collect::<Vec<_>>();
Ok(quote! {
#[allow(non_camel_case_types)]
- #vis struct #name {
+ #vis struct #name <#(#generic),*> {
+ // We need to mark these type parameters as used, so we use a PhantomData
+ _unconstructable: ::std::marker::PhantomData<(#(#generic),*)>
}
- impl #name {
+ impl <#(#generic : #bound),*> #deno_core::_ops::Op for #name <#(#generic),*> {
+ const NAME: &'static str = stringify!(#name);
+ const DECL: #deno_core::_ops::OpDecl = #deno_core::_ops::OpDecl {
+ name: stringify!(#name),
+ v8_fn_ptr: Self::#slow_function as _,
+ enabled: true,
+ fast_fn: #fast_definition,
+ is_async: false,
+ is_unstable: false,
+ is_v8: false,
+ arg_count: #arg_count as u8,
+ };
+ }
+
+ impl <#(#generic : #bound),*> #name <#(#generic),*> {
pub const fn name() -> &'static str {
stringify!(#name)
}
@@ -220,8 +248,8 @@ fn generate_op2(
}
}
- #slow_fn
#fast_fn
+ #slow_fn
#[inline(always)]
#op_fn
diff --git a/ops/op2/signature.rs b/ops/op2/signature.rs
index 6158b2a55..15c40e007 100644
--- a/ops/op2/signature.rs
+++ b/ops/op2/signature.rs
@@ -4,12 +4,15 @@ use proc_macro2::Ident;
use proc_macro2::Span;
use quote::quote;
use quote::ToTokens;
+use std::collections::BTreeMap;
use strum::IntoEnumIterator;
use strum::IntoStaticStr;
use strum_macros::EnumIter;
use strum_macros::EnumString;
use syn2::Attribute;
use syn2::FnArg;
+use syn2::GenericParam;
+use syn2::Generics;
use syn2::Pat;
use syn2::ReturnType;
use syn2::Signature;
@@ -136,9 +139,16 @@ pub enum RetVal {
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ParsedSignature {
+ // The parsed arguments
pub args: Vec<Arg>,
+ // The argument names
pub names: Vec<String>,
+ // The parsed return value
pub ret_val: RetVal,
+ // One and only one lifetime allowed
+ pub lifetime: Option<String>,
+ // Generic bounds: each generic must have one and only simple trait bound
+ pub generic_bounds: BTreeMap<String, String>,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -153,10 +163,24 @@ enum AttributeModifier {
#[derive(Error, Debug)]
pub enum SignatureError {
- #[error("Invalid argument: {0}")]
+ #[error("Invalid argument: '{0}'")]
ArgError(String, #[source] ArgError),
#[error("Invalid return type")]
RetError(#[from] ArgError),
+ #[error("Only one lifetime is permitted")]
+ TooManyLifetimes,
+ #[error("Generic '{0}' must have one and only bound (either <T> and 'where T: Trait', or <T: Trait>)")]
+ GenericBoundCardinality(String),
+ #[error("Where clause predicate '{0}' (eg: where T: Trait) must appear in generics list (eg: <T>)")]
+ WherePredicateMustAppearInGenerics(String),
+ #[error("All generics must appear only once in the generics parameter list or where clause")]
+ DuplicateGeneric(String),
+ #[error("Generic lifetime '{0}' may not have bounds (eg: <'a: 'b>)")]
+ LifetimesMayNotHaveBounds(String),
+ #[error("Invalid generic: '{0}' Only simple generics bounds are allowed (eg: T: Trait)")]
+ InvalidGeneric(String),
+ #[error("Invalid predicate: '{0}' Only simple where predicates are allowed (eg: T: Trait)")]
+ InvalidWherePredicate(String),
}
#[derive(Error, Debug)]
@@ -216,13 +240,107 @@ pub fn parse_signature(
parse_arg(input).map_err(|err| SignatureError::ArgError(name, err))?,
);
}
+ let ret_val =
+ parse_return(parse_attributes(&attributes)?, &signature.output)?;
+ let lifetime = parse_lifetime(&signature.generics)?;
+ let generic_bounds = parse_generics(&signature.generics)?;
Ok(ParsedSignature {
args,
names,
- ret_val: parse_return(parse_attributes(&attributes)?, &signature.output)?,
+ ret_val,
+ lifetime,
+ generic_bounds,
})
}
+/// Extract one lifetime from the [`syn2::Generics`], ensuring that the lifetime is valid
+/// and has no bounds.
+fn parse_lifetime(
+ generics: &Generics,
+) -> Result<Option<String>, SignatureError> {
+ let mut res = None;
+ for param in &generics.params {
+ if let GenericParam::Lifetime(lt) = param {
+ if !lt.bounds.is_empty() {
+ return Err(SignatureError::LifetimesMayNotHaveBounds(
+ lt.lifetime.to_string(),
+ ));
+ }
+ if res.is_some() {
+ return Err(SignatureError::TooManyLifetimes);
+ }
+ res = Some(lt.lifetime.ident.to_string());
+ }
+ }
+ Ok(res)
+}
+
+/// Parse and validate generics. We require one and only one trait bound for each generic
+/// parameter. Tries to sanity check and return reasonable errors for possible signature errors.
+fn parse_generics(
+ generics: &Generics,
+) -> Result<BTreeMap<String, String>, SignatureError> {
+ let mut where_clauses = BTreeMap::new();
+
+ // First, extract the where clause so we can detect duplicated predicates
+ if let Some(where_clause) = &generics.where_clause {
+ for predicate in &where_clause.predicates {
+ let predicate = predicate.to_token_stream();
+ let (generic_name, bound) = std::panic::catch_unwind(|| {
+ use syn2 as syn;
+ rules!(predicate => {
+ ($t:ident : $bound:path) => (t.to_string(), stringify_token(bound)),
+ })
+ })
+ .map_err(|_| {
+ SignatureError::InvalidWherePredicate(predicate.to_string())
+ })?;
+ if where_clauses.insert(generic_name.clone(), bound).is_some() {
+ return Err(SignatureError::DuplicateGeneric(generic_name));
+ }
+ }
+ }
+
+ let mut res = BTreeMap::new();
+ for param in &generics.params {
+ if let GenericParam::Type(ty) = param {
+ let ty = ty.to_token_stream();
+ let (name, bound) = std::panic::catch_unwind(|| {
+ use syn2 as syn;
+ rules!(ty => {
+ ($t:ident : $bound:path) => (t.to_string(), Some(stringify_token(bound))),
+ ($t:ident) => (t.to_string(), None),
+ })
+ }).map_err(|_| SignatureError::InvalidGeneric(ty.to_string()))?;
+ let bound = match bound {
+ Some(bound) => {
+ if where_clauses.contains_key(&name) {
+ return Err(SignatureError::GenericBoundCardinality(name));
+ }
+ bound
+ }
+ None => {
+ let Some(bound) = where_clauses.remove(&name) else {
+ return Err(SignatureError::GenericBoundCardinality(name));
+ };
+ bound
+ }
+ };
+ if res.contains_key(&name) {
+ return Err(SignatureError::DuplicateGeneric(name));
+ }
+ res.insert(name, bound);
+ }
+ }
+ if !where_clauses.is_empty() {
+ return Err(SignatureError::WherePredicateMustAppearInGenerics(
+ where_clauses.into_keys().next().unwrap(),
+ ));
+ }
+
+ Ok(res)
+}
+
fn parse_attributes(attributes: &[Attribute]) -> Result<Attributes, ArgError> {
let attrs = attributes
.iter()
@@ -447,11 +565,27 @@ mod tests {
// We can't test pattern args :/
// https://github.com/rust-lang/rfcs/issues/2688
macro_rules! test {
- ( $(# [ $fn_attr:ident ])? fn $name:ident ( $( $(# [ $attr:ident ])? $ident:ident : $ty:ty ),* ) $(-> $(# [ $ret_attr:ident ])? $ret:ty)?, ( $( $arg_res:expr ),* ) -> $ret_res:expr ) => {
+ (
+ // Function attributes
+ $(# [ $fn_attr:ident ])?
+ // fn name < 'scope, GENERIC1, GENERIC2, ... >
+ fn $name:ident $( < $scope:lifetime $( , $generic:ident)* >)?
+ (
+ // Argument attribute, argument
+ $( $(# [ $attr:ident ])? $ident:ident : $ty:ty ),*
+ )
+ // Return value
+ $(-> $(# [ $ret_attr:ident ])? $ret:ty)?
+ // Where clause
+ $( where $($trait:ident : $bounds:path),* )?
+ ;
+ // Expected return value
+ $( < $( $lifetime_res:lifetime )? $(, $generic_res:ident : $bounds_res:path )* >)? ( $( $arg_res:expr ),* ) -> $ret_res:expr ) => {
#[test]
fn $name() {
test(
- stringify!($( #[$fn_attr] )? fn op( $( $( #[$attr] )? $ident : $ty ),* ) $(-> $( #[$ret_attr] )? $ret)? {}),
+ stringify!($( #[$fn_attr] )? fn op $( < $scope $( , $generic)* >)? ( $( $( #[$attr] )? $ident : $ty ),* ) $(-> $( #[$ret_attr] )? $ret)? $( where $($trait : $bounds),* )? {}),
+ stringify!($( < $( $lifetime_res )? $(, $generic_res : $bounds_res)* > )?),
stringify!($($arg_res),*),
stringify!($ret_res)
);
@@ -459,14 +593,35 @@ mod tests {
};
}
- fn test(op: &str, args_expected: &str, return_expected: &str) {
+ fn test(
+ op: &str,
+ generics_expected: &str,
+ args_expected: &str,
+ return_expected: &str,
+ ) {
+ // Parse the provided macro input as an ItemFn
let item_fn = parse_str::<ItemFn>(op)
.unwrap_or_else(|_| panic!("Failed to parse {op} as a ItemFn"));
+
let attrs = item_fn.attrs;
- let sig = parse_signature(attrs, item_fn.sig).unwrap_or_else(|_| {
- panic!("Failed to successfully parse signature from {op}")
+ let sig = parse_signature(attrs, item_fn.sig).unwrap_or_else(|err| {
+ panic!("Failed to successfully parse signature from {op} ({err:?})")
});
+ println!("Raw parsed signatures = {sig:?}");
+ let mut generics_res = vec![];
+ if let Some(lifetime) = sig.lifetime {
+ generics_res.push(format!("'{lifetime}"));
+ }
+ for (name, bounds) in sig.generic_bounds {
+ generics_res.push(format!("{name} : {bounds}"));
+ }
+ if !generics_res.is_empty() {
+ assert_eq!(
+ generics_expected,
+ format!("< {} >", generics_res.join(", "))
+ );
+ }
assert_eq!(
args_expected,
format!("{:?}", sig.args).trim_matches(|c| c == '[' || c == ']')
@@ -474,38 +629,96 @@ mod tests {
assert_eq!(return_expected, format!("{:?}", sig.ret_val));
}
+ macro_rules! expect_fail {
+ ($name:ident, $error:expr, $f:item) => {
+ #[test]
+ pub fn $name() {
+ expect_fail(stringify!($f), stringify!($error));
+ }
+ };
+ }
+
+ fn expect_fail(op: &str, error: &str) {
+ // Parse the provided macro input as an ItemFn
+ let item_fn = parse_str::<ItemFn>(op)
+ .unwrap_or_else(|_| panic!("Failed to parse {op} as a ItemFn"));
+ let attrs = item_fn.attrs;
+ let err = parse_signature(attrs, item_fn.sig)
+ .expect_err("Expected function to fail to parse");
+ assert_eq!(format!("{err:?}"), error.to_owned());
+ }
+
test!(
- fn op_state_and_number(opstate: &mut OpState, a: u32) -> (),
+ fn op_state_and_number(opstate: &mut OpState, a: u32) -> ();
(Ref(Mut, OpState), Numeric(u32)) -> Infallible(Void)
);
test!(
- fn op_slices(r#in: &[u8], out: &mut [u8]),
+ fn op_slices(r#in: &[u8], out: &mut [u8]);
(Slice(Ref, u8), Slice(Mut, u8)) -> Infallible(Void)
);
test!(
- #[serde] fn op_serde(#[serde] input: package::SerdeInputType) -> Result<package::SerdeReturnType, Error>,
+ #[serde] fn op_serde(#[serde] input: package::SerdeInputType) -> Result<package::SerdeReturnType, Error>;
(SerdeV8("package::SerdeInputType")) -> Result(SerdeV8("package::SerdeReturnType"))
);
test!(
- fn op_local(input: v8::Local<v8::String>) -> Result<v8::Local<v8::String>, Error>,
+ fn op_local(input: v8::Local<v8::String>) -> Result<v8::Local<v8::String>, Error>;
(V8Local(String)) -> Result(V8Local(String))
);
test!(
- fn op_resource(#[smi] rid: ResourceId, buffer: &[u8]),
+ fn op_resource(#[smi] rid: ResourceId, buffer: &[u8]);
(Numeric(__SMI__), Slice(Ref, u8)) -> Infallible(Void)
);
test!(
- fn op_option_numeric_result(state: &mut OpState) -> Result<Option<u32>, AnyError>,
+ fn op_option_numeric_result(state: &mut OpState) -> Result<Option<u32>, AnyError>;
(Ref(Mut, OpState)) -> Result(OptionNumeric(u32))
);
test!(
- fn op_ffi_read_f64(state: &mut OpState, ptr: * mut c_void, offset: isize) -> Result <f64, AnyError>,
+ fn op_ffi_read_f64(state: &mut OpState, ptr: * mut c_void, offset: isize) -> Result <f64, AnyError>;
(Ref(Mut, OpState), Ptr(Mut, __VOID__), Numeric(isize)) -> Result(Numeric(f64))
);
test!(
- fn op_print(#[string] msg: &str, is_err: bool) -> Result<(), Error>,
+ fn op_print(#[string] msg: &str, is_err: bool) -> Result<(), Error>;
(Special(RefStr), Numeric(bool)) -> Result(Void)
);
+ test!(
+ fn op_scope<'s>(#[string] msg: &'s str);
+ <'s> (Special(RefStr)) -> Infallible(Void)
+ );
+ test!(
+ fn op_scope_and_generics<'s, AB, BC>(#[string] msg: &'s str) where AB: some::Trait, BC: OtherTrait;
+ <'s, AB: some::Trait, BC: OtherTrait> (Special(RefStr)) -> Infallible(Void)
+ );
+
+ expect_fail!(op_with_two_lifetimes, TooManyLifetimes, fn f<'a, 'b>() {});
+ expect_fail!(
+ op_with_lifetime_bounds,
+ LifetimesMayNotHaveBounds("'a"),
+ fn f<'a: 'b, 'b>() {}
+ );
+ expect_fail!(
+ op_with_missing_bounds,
+ GenericBoundCardinality("B"),
+ fn f<'a, B>() {}
+ );
+ expect_fail!(
+ op_with_duplicate_bounds,
+ GenericBoundCardinality("B"),
+ fn f<'a, B: Trait>()
+ where
+ B: Trait,
+ {
+ }
+ );
+ expect_fail!(
+ op_with_extra_bounds,
+ WherePredicateMustAppearInGenerics("C"),
+ fn f<'a, B>()
+ where
+ B: Trait,
+ C: Trait,
+ {
+ }
+ );
#[test]
fn test_parse_result() {
diff --git a/ops/op2/test_cases/sync/add.out b/ops/op2/test_cases/sync/add.out
index 7d97a7161..c8f77ab92 100644
--- a/ops/op2/test_cases/sync/add.out
+++ b/ops/op2/test_cases/sync/add.out
@@ -1,5 +1,28 @@
#[allow(non_camel_case_types)]
-struct op_add {}
+struct op_add {
+ _unconstructable: ::std::marker::PhantomData<()>,
+}
+impl deno_core::_ops::Op for op_add {
+ const NAME: &'static str = stringify!(op_add);
+ const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
+ name: stringify!(op_add),
+ v8_fn_ptr: Self::v8_fn_ptr as _,
+ enabled: true,
+ fast_fn: Some({
+ use deno_core::v8::fast_api::Type;
+ use deno_core::v8::fast_api::CType;
+ deno_core::v8::fast_api::FastFunction::new(
+ &[Type::V8Value, Type::Uint32, Type::Uint32],
+ CType::Uint32,
+ Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
+ )
+ }),
+ is_async: false,
+ is_unstable: false,
+ is_v8: false,
+ arg_count: 2usize as u8,
+ };
+}
impl op_add {
pub const fn name() -> &'static str {
stringify!(op_add)
@@ -7,7 +30,7 @@ impl op_add {
pub const fn decl() -> deno_core::_ops::OpDecl {
deno_core::_ops::OpDecl {
name: stringify!(op_add),
- v8_fn_ptr: Self::slow_function as _,
+ v8_fn_ptr: Self::v8_fn_ptr as _,
enabled: true,
fast_fn: Some({
use deno_core::v8::fast_api::Type;
@@ -15,7 +38,7 @@ impl op_add {
deno_core::v8::fast_api::FastFunction::new(
&[Type::V8Value, Type::Uint32, Type::Uint32],
CType::Uint32,
- Self::fast_function as *const ::std::ffi::c_void,
+ Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
)
}),
is_async: false,
@@ -24,7 +47,15 @@ impl op_add {
arg_count: 2usize as u8,
}
}
- pub extern "C" fn slow_function(info: *const deno_core::v8::FunctionCallbackInfo) {
+ fn v8_fn_ptr_fast(
+ _: deno_core::v8::Local<deno_core::v8::Object>,
+ arg0: u32,
+ arg1: u32,
+ ) -> u32 {
+ let result = Self::call(arg0 as _, arg1 as _);
+ result
+ }
+ extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe {
&*info
});
@@ -38,14 +69,6 @@ impl op_add {
let result = Self::call(arg0, arg1);
rv.set_uint32(result as u32);
}
- fn fast_function(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- arg0: u32,
- arg1: u32,
- ) -> u32 {
- let result = Self::call(arg0 as _, arg1 as _);
- result
- }
#[inline(always)]
fn call(a: u32, b: u32) -> u32 {
a + b
diff --git a/ops/op2/test_cases/sync/add_options.out b/ops/op2/test_cases/sync/add_options.out
index ca1da8fbe..9fada187f 100644
--- a/ops/op2/test_cases/sync/add_options.out
+++ b/ops/op2/test_cases/sync/add_options.out
@@ -1,5 +1,20 @@
#[allow(non_camel_case_types)]
-pub struct op_test_add_option {}
+pub struct op_test_add_option {
+ _unconstructable: ::std::marker::PhantomData<()>,
+}
+impl crate::_ops::Op for op_test_add_option {
+ const NAME: &'static str = stringify!(op_test_add_option);
+ const DECL: crate::_ops::OpDecl = crate::_ops::OpDecl {
+ name: stringify!(op_test_add_option),
+ v8_fn_ptr: Self::v8_fn_ptr as _,
+ enabled: true,
+ fast_fn: None,
+ is_async: false,
+ is_unstable: false,
+ is_v8: false,
+ arg_count: 2usize as u8,
+ };
+}
impl op_test_add_option {
pub const fn name() -> &'static str {
stringify!(op_test_add_option)
@@ -7,7 +22,7 @@ impl op_test_add_option {
pub const fn decl() -> crate::_ops::OpDecl {
crate::_ops::OpDecl {
name: stringify!(op_test_add_option),
- v8_fn_ptr: Self::slow_function as _,
+ v8_fn_ptr: Self::v8_fn_ptr as _,
enabled: true,
fast_fn: None,
is_async: false,
@@ -16,7 +31,7 @@ impl op_test_add_option {
arg_count: 2usize as u8,
}
}
- pub extern "C" fn slow_function(info: *const crate::v8::FunctionCallbackInfo) {
+ extern "C" fn v8_fn_ptr(info: *const crate::v8::FunctionCallbackInfo) {
let mut rv = crate::v8::ReturnValue::from_function_callback_info(unsafe {
&*info
});
diff --git a/ops/op2/test_cases/sync/doc_comment.out b/ops/op2/test_cases/sync/doc_comment.out
index e9f063102..d7e8005d9 100644
--- a/ops/op2/test_cases/sync/doc_comment.out
+++ b/ops/op2/test_cases/sync/doc_comment.out
@@ -1,5 +1,28 @@
#[allow(non_camel_case_types)]
-pub struct op_has_doc_comment {}
+pub struct op_has_doc_comment {
+ _unconstructable: ::std::marker::PhantomData<()>,
+}
+impl deno_core::_ops::Op for op_has_doc_comment {
+ const NAME: &'static str = stringify!(op_has_doc_comment);
+ const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
+ name: stringify!(op_has_doc_comment),
+ v8_fn_ptr: Self::v8_fn_ptr as _,
+ enabled: true,
+ fast_fn: Some({
+ use deno_core::v8::fast_api::Type;
+ use deno_core::v8::fast_api::CType;
+ deno_core::v8::fast_api::FastFunction::new(
+ &[Type::V8Value],
+ CType::Void,
+ Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
+ )
+ }),
+ is_async: false,
+ is_unstable: false,
+ is_v8: false,
+ arg_count: 0usize as u8,
+ };
+}
impl op_has_doc_comment {
pub const fn name() -> &'static str {
stringify!(op_has_doc_comment)
@@ -7,7 +30,7 @@ impl op_has_doc_comment {
pub const fn decl() -> deno_core::_ops::OpDecl {
deno_core::_ops::OpDecl {
name: stringify!(op_has_doc_comment),
- v8_fn_ptr: Self::slow_function as _,
+ v8_fn_ptr: Self::v8_fn_ptr as _,
enabled: true,
fast_fn: Some({
use deno_core::v8::fast_api::Type;
@@ -15,7 +38,7 @@ impl op_has_doc_comment {
deno_core::v8::fast_api::FastFunction::new(
&[Type::V8Value],
CType::Void,
- Self::fast_function as *const ::std::ffi::c_void,
+ Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
)
}),
is_async: false,
@@ -24,12 +47,12 @@ impl op_has_doc_comment {
arg_count: 0usize as u8,
}
}
- pub extern "C" fn slow_function(info: *const deno_core::v8::FunctionCallbackInfo) {
+ fn v8_fn_ptr_fast(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
let result = Self::call();
+ result
}
- fn fast_function(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
+ extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
let result = Self::call();
- result
}
#[inline(always)]
pub fn call() -> () {}
diff --git a/ops/op2/test_cases/sync/generics.out b/ops/op2/test_cases/sync/generics.out
new file mode 100644
index 000000000..26e3af9b7
--- /dev/null
+++ b/ops/op2/test_cases/sync/generics.out
@@ -0,0 +1,59 @@
+#[allow(non_camel_case_types)]
+pub struct op_generics<T> {
+ _unconstructable: ::std::marker::PhantomData<(T)>,
+}
+impl<T: Trait> deno_core::_ops::Op for op_generics<T> {
+ const NAME: &'static str = stringify!(op_generics);
+ const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
+ name: stringify!(op_generics),
+ v8_fn_ptr: Self::v8_fn_ptr as _,
+ enabled: true,
+ fast_fn: Some({
+ use deno_core::v8::fast_api::Type;
+ use deno_core::v8::fast_api::CType;
+ deno_core::v8::fast_api::FastFunction::new(
+ &[Type::V8Value],
+ CType::Void,
+ Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
+ )
+ }),
+ is_async: false,
+ is_unstable: false,
+ is_v8: false,
+ arg_count: 0usize as u8,
+ };
+}
+impl<T: Trait> op_generics<T> {
+ pub const fn name() -> &'static str {
+ stringify!(op_generics)
+ }
+ pub const fn decl() -> deno_core::_ops::OpDecl {
+ deno_core::_ops::OpDecl {
+ name: stringify!(op_generics),
+ v8_fn_ptr: Self::v8_fn_ptr as _,
+ enabled: true,
+ fast_fn: Some({
+ use deno_core::v8::fast_api::Type;
+ use deno_core::v8::fast_api::CType;
+ deno_core::v8::fast_api::FastFunction::new(
+ &[Type::V8Value],
+ CType::Void,
+ Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
+ )
+ }),
+ is_async: false,
+ is_unstable: false,
+ is_v8: false,
+ arg_count: 0usize as u8,
+ }
+ }
+ fn v8_fn_ptr_fast(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
+ let result = Self::call();
+ result
+ }
+ extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
+ let result = Self::call();
+ }
+ #[inline(always)]
+ pub fn call() {}
+}
diff --git a/ops/op2/test_cases/sync/generics.rs b/ops/op2/test_cases/sync/generics.rs
new file mode 100644
index 000000000..b412a7f93
--- /dev/null
+++ b/ops/op2/test_cases/sync/generics.rs
@@ -0,0 +1,4 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+#[op2(fast)]
+pub fn op_generics<T: Trait>() {}
diff --git a/ops/op2/test_cases/sync/result_primitive.out b/ops/op2/test_cases/sync/result_primitive.out
index 151e8e730..4f296a893 100644
--- a/ops/op2/test_cases/sync/result_primitive.out
+++ b/ops/op2/test_cases/sync/result_primitive.out
@@ -1,5 +1,28 @@
#[allow(non_camel_case_types)]
-pub struct op_u32_with_result {}
+pub struct op_u32_with_result {
+ _unconstructable: ::std::marker::PhantomData<()>,
+}
+impl deno_core::_ops::Op for op_u32_with_result {
+ const NAME: &'static str = stringify!(op_u32_with_result);
+ const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
+ name: stringify!(op_u32_with_result),
+ v8_fn_ptr: Self::v8_fn_ptr as _,
+ enabled: true,
+ fast_fn: Some({
+ use deno_core::v8::fast_api::Type;
+ use deno_core::v8::fast_api::CType;
+ deno_core::v8::fast_api::FastFunction::new(
+ &[Type::V8Value, Type::CallbackOptions],
+ CType::Uint32,
+ Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
+ )
+ }),
+ is_async: false,
+ is_unstable: false,
+ is_v8: false,
+ arg_count: 0usize as u8,
+ };
+}
impl op_u32_with_result {
pub const fn name() -> &'static str {
stringify!(op_u32_with_result)
@@ -7,7 +30,7 @@ impl op_u32_with_result {
pub const fn decl() -> deno_core::_ops::OpDecl {
deno_core::_ops::OpDecl {
name: stringify!(op_u32_with_result),
- v8_fn_ptr: Self::slow_function as _,
+ v8_fn_ptr: Self::v8_fn_ptr as _,
enabled: true,
fast_fn: Some({
use deno_core::v8::fast_api::Type;
@@ -15,7 +38,7 @@ impl op_u32_with_result {
deno_core::v8::fast_api::FastFunction::new(
&[Type::V8Value, Type::CallbackOptions],
CType::Uint32,
- Self::fast_function as *const ::std::ffi::c_void,
+ Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
)
}),
is_async: false,
@@ -24,7 +47,31 @@ impl op_u32_with_result {
arg_count: 0usize as u8,
}
}
- pub extern "C" fn slow_function(info: *const deno_core::v8::FunctionCallbackInfo) {
+ fn v8_fn_ptr_fast(
+ _: deno_core::v8::Local<deno_core::v8::Object>,
+ fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
+ ) -> u32 {
+ let fast_api_callback_options = unsafe { &mut *fast_api_callback_options };
+ let opctx = unsafe {
+ &*(deno_core::v8::Local::<
+ v8::External,
+ >::cast(unsafe { fast_api_callback_options.data.data })
+ .value() as *const deno_core::_ops::OpCtx)
+ };
+ let result = Self::call();
+ let result = match result {
+ Ok(result) => result,
+ Err(err) => {
+ unsafe {
+ opctx.unsafely_set_last_error_for_ops_only(err);
+ }
+ fast_api_callback_options.fallback = true;
+ return ::std::default::Default::default();
+ }
+ };
+ result
+ }
+ extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe {
&*info
});
@@ -70,30 +117,6 @@ impl op_u32_with_result {
}
};
}
- fn fast_function(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> u32 {
- let fast_api_callback_options = unsafe { &mut *fast_api_callback_options };
- let opctx = unsafe {
- &*(deno_core::v8::Local::<
- v8::External,
- >::cast(unsafe { fast_api_callback_options.data.data })
- .value() as *const deno_core::_ops::OpCtx)
- };
- let result = Self::call();
- let result = match result {
- Ok(result) => result,
- Err(err) => {
- unsafe {
- opctx.unsafely_set_last_error_for_ops_only(err);
- }
- fast_api_callback_options.fallback = true;
- return ::std::default::Default::default();
- }
- };
- result
- }
#[inline(always)]
pub fn call() -> Result<u32, AnyError> {}
}
diff --git a/ops/op2/test_cases/sync/result_void.out b/ops/op2/test_cases/sync/result_void.out
index afc10582b..74aa84a8d 100644
--- a/ops/op2/test_cases/sync/result_void.out
+++ b/ops/op2/test_cases/sync/result_void.out
@@ -1,5 +1,28 @@
#[allow(non_camel_case_types)]
-pub struct op_void_with_result {}
+pub struct op_void_with_result {
+ _unconstructable: ::std::marker::PhantomData<()>,
+}
+impl deno_core::_ops::Op for op_void_with_result {
+ const NAME: &'static str = stringify!(op_void_with_result);
+ const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
+ name: stringify!(op_void_with_result),
+ v8_fn_ptr: Self::v8_fn_ptr as _,
+ enabled: true,
+ fast_fn: Some({
+ use deno_core::v8::fast_api::Type;
+ use deno_core::v8::fast_api::CType;
+ deno_core::v8::fast_api::FastFunction::new(
+ &[Type::V8Value, Type::CallbackOptions],
+ CType::Void,
+ Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
+ )
+ }),
+ is_async: false,
+ is_unstable: false,
+ is_v8: false,
+ arg_count: 0usize as u8,
+ };
+}
impl op_void_with_result {
pub const fn name() -> &'static str {
stringify!(op_void_with_result)
@@ -7,7 +30,7 @@ impl op_void_with_result {
pub const fn decl() -> deno_core::_ops::OpDecl {
deno_core::_ops::OpDecl {
name: stringify!(op_void_with_result),
- v8_fn_ptr: Self::slow_function as _,
+ v8_fn_ptr: Self::v8_fn_ptr as _,
enabled: true,
fast_fn: Some({
use deno_core::v8::fast_api::Type;
@@ -15,7 +38,7 @@ impl op_void_with_result {
deno_core::v8::fast_api::FastFunction::new(
&[Type::V8Value, Type::CallbackOptions],
CType::Void,
- Self::fast_function as *const ::std::ffi::c_void,
+ Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
)
}),
is_async: false,
@@ -24,7 +47,31 @@ impl op_void_with_result {
arg_count: 0usize as u8,
}
}
- pub extern "C" fn slow_function(info: *const deno_core::v8::FunctionCallbackInfo) {
+ fn v8_fn_ptr_fast(
+ _: deno_core::v8::Local<deno_core::v8::Object>,
+ fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
+ ) -> () {
+ let fast_api_callback_options = unsafe { &mut *fast_api_callback_options };
+ let opctx = unsafe {
+ &*(deno_core::v8::Local::<
+ v8::External,
+ >::cast(unsafe { fast_api_callback_options.data.data })
+ .value() as *const deno_core::_ops::OpCtx)
+ };
+ let result = Self::call();
+ let result = match result {
+ Ok(result) => result,
+ Err(err) => {
+ unsafe {
+ opctx.unsafely_set_last_error_for_ops_only(err);
+ }
+ fast_api_callback_options.fallback = true;
+ return ::std::default::Default::default();
+ }
+ };
+ result
+ }
+ extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
&*info
});
@@ -65,30 +112,6 @@ impl op_void_with_result {
}
};
}
- fn fast_function(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- let fast_api_callback_options = unsafe { &mut *fast_api_callback_options };
- let opctx = unsafe {
- &*(deno_core::v8::Local::<
- v8::External,
- >::cast(unsafe { fast_api_callback_options.data.data })
- .value() as *const deno_core::_ops::OpCtx)
- };
- let result = Self::call();
- let result = match result {
- Ok(result) => result,
- Err(err) => {
- unsafe {
- opctx.unsafely_set_last_error_for_ops_only(err);
- }
- fast_api_callback_options.fallback = true;
- return ::std::default::Default::default();
- }
- };
- result
- }
#[inline(always)]
pub fn call() -> Result<(), AnyError> {}
}
diff --git a/ops/op2/test_cases/sync/smi.out b/ops/op2/test_cases/sync/smi.out
index 7210e0572..85db2576e 100644
--- a/ops/op2/test_cases/sync/smi.out
+++ b/ops/op2/test_cases/sync/smi.out
@@ -1,5 +1,28 @@
#[allow(non_camel_case_types)]
-struct op_add {}
+struct op_add {
+ _unconstructable: ::std::marker::PhantomData<()>,
+}
+impl deno_core::_ops::Op for op_add {
+ const NAME: &'static str = stringify!(op_add);
+ const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
+ name: stringify!(op_add),
+ v8_fn_ptr: Self::v8_fn_ptr as _,
+ enabled: true,
+ fast_fn: Some({
+ use deno_core::v8::fast_api::Type;
+ use deno_core::v8::fast_api::CType;
+ deno_core::v8::fast_api::FastFunction::new(
+ &[Type::V8Value, Type::Int32, Type::Uint32],
+ CType::Uint32,
+ Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
+ )
+ }),
+ is_async: false,
+ is_unstable: false,
+ is_v8: false,
+ arg_count: 2usize as u8,
+ };
+}
impl op_add {
pub const fn name() -> &'static str {
stringify!(op_add)
@@ -7,7 +30,7 @@ impl op_add {
pub const fn decl() -> deno_core::_ops::OpDecl {
deno_core::_ops::OpDecl {
name: stringify!(op_add),
- v8_fn_ptr: Self::slow_function as _,
+ v8_fn_ptr: Self::v8_fn_ptr as _,
enabled: true,
fast_fn: Some({
use deno_core::v8::fast_api::Type;
@@ -15,7 +38,7 @@ impl op_add {
deno_core::v8::fast_api::FastFunction::new(
&[Type::V8Value, Type::Int32, Type::Uint32],
CType::Uint32,
- Self::fast_function as *const ::std::ffi::c_void,
+ Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
)
}),
is_async: false,
@@ -24,7 +47,15 @@ impl op_add {
arg_count: 2usize as u8,
}
}
- pub extern "C" fn slow_function(info: *const deno_core::v8::FunctionCallbackInfo) {
+ fn v8_fn_ptr_fast(
+ _: deno_core::v8::Local<deno_core::v8::Object>,
+ arg0: i32,
+ arg1: u32,
+ ) -> u32 {
+ let result = Self::call(arg0 as _, arg1 as _);
+ result
+ }
+ extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe {
&*info
});
@@ -38,14 +69,6 @@ impl op_add {
let result = Self::call(arg0, arg1);
rv.set_uint32(result as u32);
}
- fn fast_function(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- arg0: i32,
- arg1: u32,
- ) -> u32 {
- let result = Self::call(arg0 as _, arg1 as _);
- result
- }
#[inline(always)]
fn call(id: ResourceId, extra: u16) -> u32 {}
}