diff --git a/core/lib.rs b/core/lib.rs index 20001d6ca..595d3641a 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -117,6 +117,7 @@ pub use crate::modules::ResolutionKind; pub use crate::modules::StaticModuleLoader; pub use crate::modules::ValidateImportAttributesCb; pub use crate::normalize_path::normalize_path; +pub use crate::ops::OpCtx; pub use crate::ops::OpId; pub use crate::ops::OpMetadata; pub use crate::ops::OpState; @@ -171,6 +172,7 @@ pub mod _ops { pub use super::ops_metrics::dispatch_metrics_fast; pub use super::ops_metrics::dispatch_metrics_slow; pub use super::ops_metrics::OpMetricsEvent; + pub use super::runtime::bindings::register_op_method; pub use super::runtime::ops::*; pub use super::runtime::ops_rust_to_v8::*; pub use super::runtime::V8_WRAPPER_OBJECT_INDEX; diff --git a/core/ops.rs b/core/ops.rs index 12c373081..c63da75c0 100644 --- a/core/ops.rs +++ b/core/ops.rs @@ -154,6 +154,20 @@ impl OpCtx { } } + pub fn clone_for_method(&self, decl: OpDecl) -> Self { + // id and metrics_fn are not used in method ops + Self::new( + 0, + self.isolate, + self.op_driver.clone(), + decl, + self.state.clone(), + self.runtime_state.clone(), + self.get_error_class_fn, + None, + ) + } + #[inline(always)] pub const fn decl(&self) -> &OpDecl { &self.decl diff --git a/core/runtime/bindings.rs b/core/runtime/bindings.rs index 6d8e74170..6c73b3de8 100644 --- a/core/runtime/bindings.rs +++ b/core/runtime/bindings.rs @@ -323,6 +323,17 @@ pub(crate) fn initialize_deno_core_ops_bindings<'s>( } } +pub fn register_op_method( + scope: &mut v8::HandleScope, + op_ctx: OpCtx, + obj: v8::Local, +) { + let key = op_ctx.decl.name_fast.v8_string(scope); + let op_fn = op_ctx_function(scope, Box::leak(Box::new(op_ctx))); + + obj.set(scope, key.into(), op_fn.into()).unwrap(); +} + fn op_ctx_function<'s>( scope: &mut v8::HandleScope<'s>, op_ctx: &OpCtx, diff --git a/core/runtime/jsruntime.rs b/core/runtime/jsruntime.rs index c087cb415..c0b1052e0 100644 --- a/core/runtime/jsruntime.rs +++ b/core/runtime/jsruntime.rs @@ -183,8 +183,6 @@ impl InnerIsolateState { unsafe { ManuallyDrop::take(&mut self.main_realm).0.destroy(); } - - debug_assert_eq!(Rc::strong_count(&self.state), 1); } pub fn prepare_for_snapshot(mut self) -> v8::OwnedIsolate { diff --git a/ops/op2/config.rs b/ops/op2/config.rs index 17436ae9e..87b7b7dc9 100644 --- a/ops/op2/config.rs +++ b/ops/op2/config.rs @@ -22,6 +22,8 @@ pub(crate) struct MacroConfig { pub async_deferred: bool, /// Marks an op as re-entrant (can safely call other ops). pub reentrant: bool, + /// Marks an op as a method on a wrapped object. + pub method: Option, } impl MacroConfig { @@ -85,6 +87,17 @@ impl MacroConfig { config.async_deferred = true; } else if flag == "reentrant" { config.reentrant = true; + } else if flag.starts_with("method(") { + let tokens = + syn::parse_str::(&flag[6..])?.into_token_stream(); + config.method = std::panic::catch_unwind(|| { + rules!(tokens => { + ( ( $s:ty ) ) => { + Some(s.into_token_stream().to_string()) + } + }) + }) + .map_err(|_| Op2Error::PatternMatchFailed("attribute", flag))?; } else { return Err(Op2Error::InvalidAttribute(flag)); } @@ -226,5 +239,21 @@ mod tests { ..Default::default() }, ); + + test_parse( + "(method(A))", + MacroConfig { + method: Some("A".to_owned()), + ..Default::default() + }, + ); + test_parse( + "(fast, method(T))", + MacroConfig { + method: Some("T".to_owned()), + fast: true, + ..Default::default() + }, + ); } } diff --git a/ops/op2/dispatch_async.rs b/ops/op2/dispatch_async.rs index 6634238a3..d9cfbea40 100644 --- a/ops/op2/dispatch_async.rs +++ b/ops/op2/dispatch_async.rs @@ -10,6 +10,7 @@ use super::dispatch_slow::with_opctx; use super::dispatch_slow::with_opstate; use super::dispatch_slow::with_retval; use super::dispatch_slow::with_scope; +use super::dispatch_slow::with_self; use super::generator_state::gs_quote; use super::generator_state::GeneratorState; use super::signature::ParsedSignature; @@ -136,6 +137,12 @@ pub(crate) fn generate_dispatch_async( quote!() }; + let with_self = if generator_state.needs_self { + with_self(generator_state) + } else { + quote!() + }; + Ok( gs_quote!(generator_state(info, slow_function, slow_function_metrics, opctx) => { #[inline(always)] @@ -148,6 +155,7 @@ pub(crate) fn generate_dispatch_async( #with_args #with_opctx #with_opstate + #with_self #output } diff --git a/ops/op2/dispatch_fast.rs b/ops/op2/dispatch_fast.rs index 226aead7c..0235517e0 100644 --- a/ops/op2/dispatch_fast.rs +++ b/ops/op2/dispatch_fast.rs @@ -439,6 +439,21 @@ pub(crate) fn generate_dispatch_fast( quote!() }; + let with_self = if generator_state.needs_self { + gs_quote!(generator_state(self_ty) => { + let self_: &#self_ty = deno_core::cppgc::try_unwrap_cppgc_object(this.into()).unwrap(); + }) + } else { + quote!() + }; + + let name = &generator_state.name; + let call = if generator_state.needs_self { + quote!(self_. #name) + } else { + quote!(Self:: #name) + }; + let with_opctx = if generator_state.needs_fast_opctx { generator_state.needs_fast_api_callback_options = true; gs_quote!(generator_state(opctx, fast_api_callback_options) => { @@ -503,7 +518,7 @@ pub(crate) fn generate_dispatch_fast( #[allow(clippy::too_many_arguments)] extern "C" fn #fast_function( - _: deno_core::v8::Local, + this: deno_core::v8::Local, #( #fastcall_names: #fastcall_types, )* ) -> #output_type { #[cfg(debug_assertions)] @@ -512,9 +527,11 @@ pub(crate) fn generate_dispatch_fast( #with_fast_api_callback_options #with_opctx #with_js_runtime_state + #with_self + let #result = { #(#call_args)* - Self::call(#(#call_names),*) + #call (#(#call_names),*) }; #handle_error #handle_result @@ -624,6 +641,10 @@ fn map_v8_fastcall_arg_to_arg( *needs_js_runtime_state = true; quote!(let #arg_ident = &#js_runtime_state;) } + Arg::Ref(RefType::Ref, Special::OpCtx) => { + *needs_opctx = true; + quote!(let #arg_ident = #opctx;) + } Arg::State(RefType::Ref, state) => { *needs_opctx = true; let state = @@ -783,6 +804,7 @@ fn map_arg_to_v8_fastcall_type( | Arg::Ref(_, Special::OpState) | Arg::Rc(Special::JsRuntimeState) | Arg::Ref(RefType::Ref, Special::JsRuntimeState) + | Arg::Ref(RefType::Ref, Special::OpCtx) | Arg::State(..) | Arg::Special(Special::Isolate) | Arg::OptionState(..) diff --git a/ops/op2/dispatch_slow.rs b/ops/op2/dispatch_slow.rs index 748223adf..facaa44dd 100644 --- a/ops/op2/dispatch_slow.rs +++ b/ops/op2/dispatch_slow.rs @@ -135,6 +135,12 @@ pub(crate) fn generate_dispatch_slow( quote!() }; + let with_self = if generator_state.needs_self { + with_self(generator_state) + } else { + quote!() + }; + Ok( gs_quote!(generator_state(opctx, info, slow_function, slow_function_metrics) => { #[inline(always)] @@ -149,6 +155,7 @@ pub(crate) fn generate_dispatch_slow( #with_isolate #with_opstate #with_js_runtime_state + #with_self #output; return 0; @@ -236,6 +243,13 @@ pub(crate) fn with_js_runtime_state( ) } +pub(crate) fn with_self(generator_state: &mut GeneratorState) -> TokenStream { + generator_state.needs_opctx = true; + gs_quote!(generator_state(fn_args, self_ty) => + (let self_: &#self_ty = unsafe { deno_core::cppgc::try_unwrap_cppgc_object(#fn_args.this().into()).unwrap() };) + ) +} + pub fn extract_arg( generator_state: &mut GeneratorState, index: usize, @@ -430,6 +444,10 @@ pub fn from_arg( *needs_js_runtime_state = true; quote!(let #arg_ident = &#js_runtime_state;) } + Arg::Ref(RefType::Ref, Special::OpCtx) => { + *needs_opctx = true; + quote!(let #arg_ident = #opctx;) + } Arg::State(RefType::Ref, state) => { *needs_opstate = true; let state = @@ -679,7 +697,15 @@ pub fn call(generator_state: &mut GeneratorState) -> TokenStream { for arg in &generator_state.args { tokens.extend(quote!( #arg , )); } - quote!(Self::call( #tokens )) + + let name = &generator_state.name; + let call_ = if generator_state.needs_self { + quote!(self_. #name) + } else { + quote!(Self:: #name) + }; + + quote!(#call_ ( #tokens )) } pub fn return_value( diff --git a/ops/op2/generator_state.rs b/ops/op2/generator_state.rs index cfbfd94dc..0b3556450 100644 --- a/ops/op2/generator_state.rs +++ b/ops/op2/generator_state.rs @@ -2,6 +2,7 @@ use proc_macro2::Ident; pub struct GeneratorState { + pub name: Ident, /// Identifiers for each of the arguments of the original function pub args: Vec, /// The result of the `call` function @@ -33,6 +34,8 @@ pub struct GeneratorState { pub fast_function_metrics: Ident, /// The async function promise ID argument pub promise_id: Ident, + /// Type of the self argument + pub self_ty: Ident, pub needs_args: bool, pub needs_retval: bool, @@ -44,6 +47,7 @@ pub struct GeneratorState { pub needs_fast_opctx: bool, pub needs_fast_api_callback_options: bool, pub needs_fast_js_runtime_state: bool, + pub needs_self: bool, } /// Quotes a set of generator_state fields, along with variables captured from diff --git a/ops/op2/mod.rs b/ops/op2/mod.rs index 5119b513e..658c7091e 100644 --- a/ops/op2/mod.rs +++ b/ops/op2/mod.rs @@ -87,8 +87,7 @@ fn generate_op2( config: MacroConfig, func: ItemFn, ) -> Result { - // Create a copy of the original function, named "call" - let call = Ident::new("call", Span::call_site()); + // Create a copy of the original function let mut op_fn = func.clone(); // Collect non-special attributes let attrs = op_fn @@ -97,7 +96,10 @@ fn generate_op2( .filter(|attr| !is_attribute_special(attr)) .collect::>(); op_fn.sig.generics.params.clear(); - op_fn.sig.ident = call.clone(); + // rename to "call" for non-methods + if config.method.is_none() { + op_fn.sig.ident = Ident::new("call", Span::call_site()); + } // Clear inert attributes // TODO(mmastrac): This should limit itself to clearing ours only @@ -122,13 +124,14 @@ fn generate_op2( zip(signature.args.iter(), &func.sig.inputs).collect::>(); let mut args = vec![]; - let mut needs_args = false; + let mut needs_args = config.method.is_some(); for (index, _) in processed_args.iter().enumerate() { let input = format_ident!("arg{index}"); args.push(input); needs_args = true; } + let name = op_fn.sig.ident.clone(); let retval = Ident::new("rv", Span::call_site()); let result = Ident::new("result", Span::call_site()); let fn_args = Ident::new("args", Span::call_site()); @@ -146,8 +149,14 @@ fn generate_op2( Ident::new("v8_fn_ptr_fast_metrics", Span::call_site()); let fast_api_callback_options = Ident::new("fast_api_callback_options", Span::call_site()); + let self_ty = if let Some(ref ty) = config.method { + format_ident!("{ty}") + } else { + Ident::new("UNINIT", Span::call_site()) + }; let mut generator_state = GeneratorState { + name, args, fn_args, scope, @@ -163,6 +172,7 @@ fn generate_op2( slow_function_metrics, fast_function, fast_function_metrics, + self_ty, promise_id, needs_retval: false, needs_scope: false, @@ -173,6 +183,7 @@ fn generate_op2( needs_fast_opctx: false, needs_fast_api_callback_options: false, needs_fast_js_runtime_state: false, + needs_self: config.method.is_some(), }; let name = func.sig.ident; @@ -223,6 +234,7 @@ fn generate_op2( let GeneratorState { slow_function, slow_function_metrics, + needs_self, .. } = &generator_state; @@ -242,7 +254,17 @@ fn generate_op2( let meta_key = signature.metadata.keys().collect::>(); let meta_value = signature.metadata.values().collect::>(); - Ok(quote! { + let op_fn_impl = if !*needs_self { + quote! { + #[inline(always)] + #(#attrs)* + #op_fn + } + } else { + quote!() + }; + + let tmpl = quote! { #[allow(non_camel_case_types)] #(#attrs)* #vis struct #name <#(#generic),*> { @@ -281,11 +303,37 @@ fn generate_op2( #fast_fn #slow_fn - #[inline(always)] - #(#attrs)* - #op_fn + #op_fn_impl } - }) + }; + + if *needs_self { + let register = format_ident!("register_{name}"); + // Create a registration function for the method + return Ok(quote! { + pub fn #register( + scope: &mut deno_core::v8::HandleScope, + ctx: &deno_core::_ops::OpCtx, + obj: deno_core::v8::Local, + ) { + #tmpl + + use deno_core::Op; + let ctx = ctx.clone_for_method(#name::DECL); + deno_core::_ops::register_op_method( + scope, + ctx, + obj, + ); + } + + #[inline(always)] + #(#attrs)* + #op_fn + }); + } + + Ok(tmpl) } #[cfg(test)] diff --git a/ops/op2/signature.rs b/ops/op2/signature.rs index ad45e2d84..d432801c4 100644 --- a/ops/op2/signature.rs +++ b/ops/op2/signature.rs @@ -145,6 +145,7 @@ pub enum Special { HandleScope, OpState, JsRuntimeState, + OpCtx, FastApiCallbackOptions, Isolate, } @@ -351,6 +352,7 @@ impl Arg { Special::FastApiCallbackOptions | Special::OpState | Special::JsRuntimeState + | Special::OpCtx | Special::HandleScope | Special::Isolate, ) => true, @@ -359,6 +361,7 @@ impl Arg { Special::FastApiCallbackOptions | Special::OpState | Special::JsRuntimeState + | Special::OpCtx | Special::HandleScope, ) => true, Self::RcRefCell( @@ -989,7 +992,8 @@ pub fn parse_signature( let mut names = vec![]; for input in signature.inputs { let name = match &input { - FnArg::Receiver(_) => "self".to_owned(), + // Skip reciever + FnArg::Receiver(_) => continue, FnArg::Typed(ty) => match &*ty.pat { Pat::Ident(ident) => ident.ident.to_string(), _ => "(complex)".to_owned(), @@ -1345,6 +1349,7 @@ fn parse_type_path( } ( OpState ) => Ok(CBare(TSpecial(Special::OpState))), ( JsRuntimeState ) => Ok(CBare(TSpecial(Special::JsRuntimeState))), + ( OpCtx ) => Ok(CBare(TSpecial(Special::OpCtx))), ( v8 :: Isolate ) => Ok(CBare(TSpecial(Special::Isolate))), ( v8 :: HandleScope $( < $_scope:lifetime >)? ) => Ok(CBare(TSpecial(Special::HandleScope))), ( v8 :: FastApiCallbackOptions ) => Ok(CBare(TSpecial(Special::FastApiCallbackOptions))), @@ -1384,7 +1389,9 @@ fn parse_type_path( // the easiest way to work with the 'rules!' macro above. match res { // OpState and JsRuntimeState appears in both ways - CBare(TSpecial(Special::OpState | Special::JsRuntimeState)) => {} + CBare(TSpecial( + Special::OpState | Special::JsRuntimeState | Special::OpCtx, + )) => {} CBare( TString(Strings::RefStr) | TSpecial(Special::HandleScope) | TV8(_), ) => { diff --git a/ops/op2/test_cases/async/async_deferred.out b/ops/op2/test_cases/async/async_deferred.out index 8e135995f..518da34a4 100644 --- a/ops/op2/test_cases/async/async_deferred.out +++ b/ops/op2/test_cases/async/async_deferred.out @@ -68,7 +68,7 @@ impl op_async_deferred { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, promise_id: i32, fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions, ) -> () { diff --git a/ops/op2/test_cases/async/async_lazy.out b/ops/op2/test_cases/async/async_lazy.out index f1312d91c..49f8b4b80 100644 --- a/ops/op2/test_cases/async/async_lazy.out +++ b/ops/op2/test_cases/async/async_lazy.out @@ -68,7 +68,7 @@ impl op_async_lazy { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, promise_id: i32, fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions, ) -> () { diff --git a/ops/op2/test_cases/sync/add.out b/ops/op2/test_cases/sync/add.out index 3bba11d25..65391f704 100644 --- a/ops/op2/test_cases/sync/add.out +++ b/ops/op2/test_cases/sync/add.out @@ -69,7 +69,7 @@ impl op_add { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: u32, arg1: u32, ) -> u32 { diff --git a/ops/op2/test_cases/sync/bigint.out b/ops/op2/test_cases/sync/bigint.out index 8a597afde..504c46715 100644 --- a/ops/op2/test_cases/sync/bigint.out +++ b/ops/op2/test_cases/sync/bigint.out @@ -66,7 +66,9 @@ impl op_bigint { res } #[allow(clippy::too_many_arguments)] - extern "C" fn v8_fn_ptr_fast(_: deno_core::v8::Local) -> u64 { + extern "C" fn v8_fn_ptr_fast( + this: deno_core::v8::Local, + ) -> u64 { #[cfg(debug_assertions)] let _reentrancy_check_guard = deno_core::_ops::reentrancy_check( &::DECL, diff --git a/ops/op2/test_cases/sync/bool.out b/ops/op2/test_cases/sync/bool.out index 188f2f1bb..3cc154267 100644 --- a/ops/op2/test_cases/sync/bool.out +++ b/ops/op2/test_cases/sync/bool.out @@ -68,7 +68,7 @@ impl op_bool { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: bool, ) -> bool { #[cfg(debug_assertions)] diff --git a/ops/op2/test_cases/sync/bool_result.out b/ops/op2/test_cases/sync/bool_result.out index e131340f1..4a6eecf6c 100644 --- a/ops/op2/test_cases/sync/bool_result.out +++ b/ops/op2/test_cases/sync/bool_result.out @@ -68,7 +68,7 @@ impl op_bool { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: bool, fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions, ) -> bool { diff --git a/ops/op2/test_cases/sync/buffers.out b/ops/op2/test_cases/sync/buffers.out index 52e33fdad..0f58f99e4 100644 --- a/ops/op2/test_cases/sync/buffers.out +++ b/ops/op2/test_cases/sync/buffers.out @@ -84,7 +84,7 @@ impl op_buffers { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: *mut deno_core::v8::fast_api::FastApiTypedArray, arg1: *mut deno_core::v8::fast_api::FastApiTypedArray, arg2: *mut deno_core::v8::fast_api::FastApiTypedArray, @@ -351,7 +351,7 @@ impl op_buffers_32 { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: *mut deno_core::v8::fast_api::FastApiTypedArray, arg1: *mut deno_core::v8::fast_api::FastApiTypedArray, arg2: *mut deno_core::v8::fast_api::FastApiTypedArray, diff --git a/ops/op2/test_cases/sync/buffers_copy.out b/ops/op2/test_cases/sync/buffers_copy.out index 42f9dfa27..0b2788f68 100644 --- a/ops/op2/test_cases/sync/buffers_copy.out +++ b/ops/op2/test_cases/sync/buffers_copy.out @@ -81,7 +81,7 @@ impl op_buffers { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: *mut deno_core::v8::fast_api::FastApiTypedArray, arg1: *mut deno_core::v8::fast_api::FastApiTypedArray, arg2: *mut deno_core::v8::fast_api::FastApiTypedArray, @@ -300,7 +300,7 @@ impl op_buffers_32 { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: *mut deno_core::v8::fast_api::FastApiTypedArray, arg1: *mut deno_core::v8::fast_api::FastApiTypedArray, ) -> () { diff --git a/ops/op2/test_cases/sync/cfg.out b/ops/op2/test_cases/sync/cfg.out index 006a549cf..914b9c1da 100644 --- a/ops/op2/test_cases/sync/cfg.out +++ b/ops/op2/test_cases/sync/cfg.out @@ -68,7 +68,9 @@ impl op_maybe_windows { res } #[allow(clippy::too_many_arguments)] - extern "C" fn v8_fn_ptr_fast(_: deno_core::v8::Local) -> () { + extern "C" fn v8_fn_ptr_fast( + this: deno_core::v8::Local, + ) -> () { #[cfg(debug_assertions)] let _reentrancy_check_guard = deno_core::_ops::reentrancy_check( &::DECL, @@ -193,7 +195,9 @@ impl op_maybe_windows { res } #[allow(clippy::too_many_arguments)] - extern "C" fn v8_fn_ptr_fast(_: deno_core::v8::Local) -> () { + extern "C" fn v8_fn_ptr_fast( + this: deno_core::v8::Local, + ) -> () { #[cfg(debug_assertions)] let _reentrancy_check_guard = deno_core::_ops::reentrancy_check( &::DECL, diff --git a/ops/op2/test_cases/sync/clippy_allow.out b/ops/op2/test_cases/sync/clippy_allow.out index a9c89a83b..b1b3f1f6f 100644 --- a/ops/op2/test_cases/sync/clippy_allow.out +++ b/ops/op2/test_cases/sync/clippy_allow.out @@ -68,7 +68,9 @@ impl op_extra_annotation { res } #[allow(clippy::too_many_arguments)] - extern "C" fn v8_fn_ptr_fast(_: deno_core::v8::Local) -> () { + extern "C" fn v8_fn_ptr_fast( + this: deno_core::v8::Local, + ) -> () { #[cfg(debug_assertions)] let _reentrancy_check_guard = deno_core::_ops::reentrancy_check( &::DECL, @@ -191,7 +193,9 @@ impl op_clippy_internal { res } #[allow(clippy::too_many_arguments)] - extern "C" fn v8_fn_ptr_fast(_: deno_core::v8::Local) -> () { + extern "C" fn v8_fn_ptr_fast( + this: deno_core::v8::Local, + ) -> () { #[cfg(debug_assertions)] let _reentrancy_check_guard = deno_core::_ops::reentrancy_check( &::DECL, diff --git a/ops/op2/test_cases/sync/cppgc_resource.out b/ops/op2/test_cases/sync/cppgc_resource.out index dea8d635d..fed21f23d 100644 --- a/ops/op2/test_cases/sync/cppgc_resource.out +++ b/ops/op2/test_cases/sync/cppgc_resource.out @@ -68,7 +68,7 @@ impl op_file { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: deno_core::v8::Local, fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions, ) -> () { diff --git a/ops/op2/test_cases/sync/doc_comment.out b/ops/op2/test_cases/sync/doc_comment.out index a25f3afe3..01f355386 100644 --- a/ops/op2/test_cases/sync/doc_comment.out +++ b/ops/op2/test_cases/sync/doc_comment.out @@ -67,7 +67,9 @@ impl op_has_doc_comment { res } #[allow(clippy::too_many_arguments)] - extern "C" fn v8_fn_ptr_fast(_: deno_core::v8::Local) -> () { + extern "C" fn v8_fn_ptr_fast( + this: deno_core::v8::Local, + ) -> () { #[cfg(debug_assertions)] let _reentrancy_check_guard = deno_core::_ops::reentrancy_check( &::DECL, diff --git a/ops/op2/test_cases/sync/fast_alternative.out b/ops/op2/test_cases/sync/fast_alternative.out index f84ce51db..677c7bd88 100644 --- a/ops/op2/test_cases/sync/fast_alternative.out +++ b/ops/op2/test_cases/sync/fast_alternative.out @@ -177,7 +177,7 @@ impl op_fast { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: u32, arg1: u32, ) -> u32 { @@ -451,7 +451,7 @@ impl op_fast_generic { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: u32, arg1: u32, ) -> u32 { diff --git a/ops/op2/test_cases/sync/generics.out b/ops/op2/test_cases/sync/generics.out index f9da0101e..d9bca6e9c 100644 --- a/ops/op2/test_cases/sync/generics.out +++ b/ops/op2/test_cases/sync/generics.out @@ -66,7 +66,9 @@ impl op_generics { res } #[allow(clippy::too_many_arguments)] - extern "C" fn v8_fn_ptr_fast(_: deno_core::v8::Local) -> () { + extern "C" fn v8_fn_ptr_fast( + this: deno_core::v8::Local, + ) -> () { #[cfg(debug_assertions)] let _reentrancy_check_guard = deno_core::_ops::reentrancy_check( &::DECL, @@ -187,7 +189,9 @@ impl op_generics_static { res } #[allow(clippy::too_many_arguments)] - extern "C" fn v8_fn_ptr_fast(_: deno_core::v8::Local) -> () { + extern "C" fn v8_fn_ptr_fast( + this: deno_core::v8::Local, + ) -> () { #[cfg(debug_assertions)] let _reentrancy_check_guard = deno_core::_ops::reentrancy_check( &::DECL, @@ -308,7 +312,9 @@ impl op_generics_static_where { res } #[allow(clippy::too_many_arguments)] - extern "C" fn v8_fn_ptr_fast(_: deno_core::v8::Local) -> () { + extern "C" fn v8_fn_ptr_fast( + this: deno_core::v8::Local, + ) -> () { #[cfg(debug_assertions)] let _reentrancy_check_guard = deno_core::_ops::reentrancy_check( &::DECL, diff --git a/ops/op2/test_cases/sync/op_state_attr.out b/ops/op2/test_cases/sync/op_state_attr.out index 4e6cd73bc..fb8efee6b 100644 --- a/ops/op2/test_cases/sync/op_state_attr.out +++ b/ops/op2/test_cases/sync/op_state_attr.out @@ -67,7 +67,7 @@ impl op_state_rc { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions, ) -> () { #[cfg(debug_assertions)] diff --git a/ops/op2/test_cases/sync/op_state_rc.out b/ops/op2/test_cases/sync/op_state_rc.out index 64651898d..f44667e5c 100644 --- a/ops/op2/test_cases/sync/op_state_rc.out +++ b/ops/op2/test_cases/sync/op_state_rc.out @@ -67,7 +67,7 @@ impl op_state_rc { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions, ) -> () { #[cfg(debug_assertions)] diff --git a/ops/op2/test_cases/sync/op_state_ref.out b/ops/op2/test_cases/sync/op_state_ref.out index a914a5758..ed408061f 100644 --- a/ops/op2/test_cases/sync/op_state_ref.out +++ b/ops/op2/test_cases/sync/op_state_ref.out @@ -67,7 +67,7 @@ impl op_state_ref { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions, ) -> () { #[cfg(debug_assertions)] @@ -212,7 +212,7 @@ impl op_state_mut { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions, ) -> () { #[cfg(debug_assertions)] @@ -459,7 +459,7 @@ impl op_state_and_v8_local { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg1: deno_core::v8::Local, fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions, ) -> () { diff --git a/ops/op2/test_cases/sync/result_external.out b/ops/op2/test_cases/sync/result_external.out index 38ab70ddc..2a252bea3 100644 --- a/ops/op2/test_cases/sync/result_external.out +++ b/ops/op2/test_cases/sync/result_external.out @@ -67,7 +67,7 @@ impl op_external_with_result { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions, ) -> *mut ::std::ffi::c_void { #[cfg(debug_assertions)] diff --git a/ops/op2/test_cases/sync/result_primitive.out b/ops/op2/test_cases/sync/result_primitive.out index 42138b8f3..994ac3da5 100644 --- a/ops/op2/test_cases/sync/result_primitive.out +++ b/ops/op2/test_cases/sync/result_primitive.out @@ -67,7 +67,7 @@ impl op_u32_with_result { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions, ) -> u32 { #[cfg(debug_assertions)] diff --git a/ops/op2/test_cases/sync/result_void.out b/ops/op2/test_cases/sync/result_void.out index 03593384e..a900b0250 100644 --- a/ops/op2/test_cases/sync/result_void.out +++ b/ops/op2/test_cases/sync/result_void.out @@ -67,7 +67,7 @@ impl op_void_with_result { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions, ) -> () { #[cfg(debug_assertions)] diff --git a/ops/op2/test_cases/sync/smi.out b/ops/op2/test_cases/sync/smi.out index c7e5180ab..7ddf32b2d 100644 --- a/ops/op2/test_cases/sync/smi.out +++ b/ops/op2/test_cases/sync/smi.out @@ -78,7 +78,7 @@ impl op_smi_unsigned_return { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: i32, arg1: i32, arg2: i32, @@ -291,7 +291,7 @@ impl op_smi_signed_return { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: i32, arg1: i32, arg2: i32, diff --git a/ops/op2/test_cases/sync/string_cow.out b/ops/op2/test_cases/sync/string_cow.out index ab08e70fd..be93440bf 100644 --- a/ops/op2/test_cases/sync/string_cow.out +++ b/ops/op2/test_cases/sync/string_cow.out @@ -68,7 +68,7 @@ impl op_string_cow { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: *mut deno_core::v8::fast_api::FastApiOneByteString, ) -> u32 { #[cfg(debug_assertions)] diff --git a/ops/op2/test_cases/sync/string_onebyte.out b/ops/op2/test_cases/sync/string_onebyte.out index bf690df9d..b59b3eed8 100644 --- a/ops/op2/test_cases/sync/string_onebyte.out +++ b/ops/op2/test_cases/sync/string_onebyte.out @@ -68,7 +68,7 @@ impl op_string_onebyte { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: *mut deno_core::v8::fast_api::FastApiOneByteString, ) -> u32 { #[cfg(debug_assertions)] diff --git a/ops/op2/test_cases/sync/string_owned.out b/ops/op2/test_cases/sync/string_owned.out index 52e67ed9c..034221ac7 100644 --- a/ops/op2/test_cases/sync/string_owned.out +++ b/ops/op2/test_cases/sync/string_owned.out @@ -68,7 +68,7 @@ impl op_string_owned { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: *mut deno_core::v8::fast_api::FastApiOneByteString, ) -> u32 { #[cfg(debug_assertions)] diff --git a/ops/op2/test_cases/sync/string_ref.out b/ops/op2/test_cases/sync/string_ref.out index c4badc64a..4ca97a6f4 100644 --- a/ops/op2/test_cases/sync/string_ref.out +++ b/ops/op2/test_cases/sync/string_ref.out @@ -68,7 +68,7 @@ impl op_string_owned { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: *mut deno_core::v8::fast_api::FastApiOneByteString, ) -> u32 { #[cfg(debug_assertions)] diff --git a/ops/op2/test_cases/sync/v8_ref_option.out b/ops/op2/test_cases/sync/v8_ref_option.out index a00419034..d366d56ec 100644 --- a/ops/op2/test_cases/sync/v8_ref_option.out +++ b/ops/op2/test_cases/sync/v8_ref_option.out @@ -69,7 +69,7 @@ impl op_v8_lifetime { } #[allow(clippy::too_many_arguments)] extern "C" fn v8_fn_ptr_fast( - _: deno_core::v8::Local, + this: deno_core::v8::Local, arg0: deno_core::v8::Local, arg1: deno_core::v8::Local, fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions, diff --git a/testing/checkin/runner/mod.rs b/testing/checkin/runner/mod.rs index 075d3a0f2..d6897d045 100644 --- a/testing/checkin/runner/mod.rs +++ b/testing/checkin/runner/mod.rs @@ -46,6 +46,7 @@ deno_core::extension!( ops::op_stats_diff, ops::op_stats_dump, ops::op_stats_delete, + ops::op_stateful_new, ops_io::op_pipe_create, ops_io::op_file_open, ops_async::op_async_yield, diff --git a/testing/checkin/runner/ops.rs b/testing/checkin/runner/ops.rs index 529091abc..f2f49d979 100644 --- a/testing/checkin/runner/ops.rs +++ b/testing/checkin/runner/ops.rs @@ -9,6 +9,7 @@ use deno_core::stats::RuntimeActivityStats; use deno_core::stats::RuntimeActivityStatsFactory; use deno_core::stats::RuntimeActivityStatsFilter; use deno_core::v8; +use deno_core::OpCtx; use deno_core::OpState; use super::testing::Output; @@ -76,3 +77,39 @@ pub fn op_stats_delete( ) { test_data.take::(name); } + +pub struct Stateful { + name: String, +} + +impl Stateful { + #[op2(method(Stateful))] + #[string] + fn get_name(&self) -> String { + self.name.clone() + } + + #[op2(fast, method(Stateful))] + fn print_name(&self) { + println!("{}", self.name); + } + + #[op2(async, method(Stateful))] + #[string] + async fn async_method(&self) -> String { + self.name.clone() + } +} + +#[op2] +pub fn op_stateful_new<'a>( + scope: &mut v8::HandleScope<'a>, + ctx: &OpCtx, + #[string] name: String, +) -> v8::Local<'a, v8::Object> { + let obj = deno_core::cppgc::make_cppgc_object(scope, Stateful { name }); + Stateful::register_get_name(scope, ctx, obj); + Stateful::register_print_name(scope, ctx, obj); + Stateful::register_async_method(scope, ctx, obj); + obj +} diff --git a/testing/unit/resource_test.ts b/testing/unit/resource_test.ts index 5b52a7d0f..f630b5116 100644 --- a/testing/unit/resource_test.ts +++ b/testing/unit/resource_test.ts @@ -6,6 +6,7 @@ const { op_file_open, op_async_make_cppgc_resource, op_async_get_cppgc_resource, + op_stateful_new, } = Deno.core.ops; test(async function testPipe() { @@ -62,3 +63,11 @@ test(async function testCppgcAsync() { const resource = await op_async_make_cppgc_resource(); assertEquals(await op_async_get_cppgc_resource(resource), 42); }); + +test(function testCppgcObjectMethods() { + const obj = op_stateful_new("A"); + const name = obj.get_name(); + + assertEquals(name, "A"); + obj.print_name(); +});