diff options
Diffstat (limited to 'ops/op2')
-rw-r--r-- | ops/op2/dispatch_slow.rs | 2 | ||||
-rw-r--r-- | ops/op2/mod.rs | 38 | ||||
-rw-r--r-- | ops/op2/signature.rs | 243 | ||||
-rw-r--r-- | ops/op2/test_cases/sync/add.out | 47 | ||||
-rw-r--r-- | ops/op2/test_cases/sync/add_options.out | 21 | ||||
-rw-r--r-- | ops/op2/test_cases/sync/doc_comment.out | 35 | ||||
-rw-r--r-- | ops/op2/test_cases/sync/generics.out | 59 | ||||
-rw-r--r-- | ops/op2/test_cases/sync/generics.rs | 4 | ||||
-rw-r--r-- | ops/op2/test_cases/sync/result_primitive.out | 79 | ||||
-rw-r--r-- | ops/op2/test_cases/sync/result_void.out | 79 | ||||
-rw-r--r-- | ops/op2/test_cases/sync/smi.out | 47 |
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 {} } |