diff --git a/core/cppgc.rs b/core/cppgc.rs index b617606b4..fa6096738 100644 --- a/core/cppgc.rs +++ b/core/cppgc.rs @@ -41,10 +41,16 @@ pub fn make_cppgc_object<'a, T: 'static>( obj } +#[repr(C)] +struct InnerMember { + inner: [usize; 2], + ptr: *mut (), +} + #[allow(clippy::needless_lifetimes)] pub fn try_unwrap_cppgc_object<'sc, T: 'static>( val: v8::Local<'sc, v8::Value>, -) -> Option<&'sc T> { +) -> Option<&'sc mut T> { let Ok(obj): Result, _> = val.try_into() else { return None; }; @@ -60,13 +66,13 @@ pub fn try_unwrap_cppgc_object<'sc, T: 'static>( // The object can only be created by `make_cppgc_object`. let member = unsafe { let ptr = obj.get_aligned_pointer_from_internal_field(SLOT_OFFSET); - let obj = &*(ptr as *const v8::cppgc::InnerMember); - obj.get::>() + let obj = &*(ptr as *mut InnerMember); + obj.ptr.cast::>().as_mut().unwrap() }; if member.tag != TypeId::of::() { return None; } - Some(&member.member) + Some(&mut member.member) } diff --git a/core/runtime/ops.rs b/core/runtime/ops.rs index 6a1c1934c..286d198b0 100644 --- a/core/runtime/ops.rs +++ b/core/runtime/ops.rs @@ -608,6 +608,7 @@ mod tests { op_arraybuffer_slice, op_test_get_cppgc_resource, op_test_make_cppgc_resource, + op_test_set_cppgc_resource, op_external_make, op_external_process, op_external_make_ptr, @@ -1907,14 +1908,24 @@ mod tests { resource.value } + #[op2(fast)] + pub fn op_test_set_cppgc_resource( + #[cppgc] resource: &mut TestResource, + value: u32, + ) { + resource.value = value; + } + #[test] pub fn test_op_cppgc_object() -> Result<(), Box> { run_test2( 10, - "op_test_make_cppgc_resource, op_test_get_cppgc_resource", + "op_test_make_cppgc_resource, op_test_get_cppgc_resource, op_test_set_cppgc_resource", r" const resource = op_test_make_cppgc_resource(); - assert(op_test_get_cppgc_resource(resource) == 42);", + assert(op_test_get_cppgc_resource(resource) == 42); + op_test_set_cppgc_resource(resource, 43); + assert(op_test_get_cppgc_resource(resource) == 43);", )?; Ok(()) } diff --git a/ops/op2/dispatch_async.rs b/ops/op2/dispatch_async.rs index a5ec57977..b07dece35 100644 --- a/ops/op2/dispatch_async.rs +++ b/ops/op2/dispatch_async.rs @@ -47,7 +47,7 @@ pub(crate) fn generate_dispatch_async( let mut output = TokenStream::new(); let with_self = if generator_state.needs_self { - with_self(generator_state, &signature.ret_val) + with_self(generator_state, true, &signature.ret_val) .map_err(V8SignatureMappingError::NoSelfMapping)? } else { quote!() diff --git a/ops/op2/dispatch_slow.rs b/ops/op2/dispatch_slow.rs index 1b6a4764b..c62d32332 100644 --- a/ops/op2/dispatch_slow.rs +++ b/ops/op2/dispatch_slow.rs @@ -92,7 +92,7 @@ pub(crate) fn generate_dispatch_slow( )?); let with_self = if generator_state.needs_self { - with_self(generator_state, &signature.ret_val) + with_self(generator_state, false, &signature.ret_val) .map_err(V8SignatureMappingError::NoSelfMapping)? } else { quote!() @@ -246,6 +246,7 @@ pub(crate) fn with_js_runtime_state( pub(crate) fn with_self( generator_state: &mut GeneratorState, + is_async: bool, ret_val: &RetVal, ) -> Result { generator_state.needs_opctx = true; @@ -254,6 +255,7 @@ pub(crate) fn with_self( format!("expected {}", &generator_state.self_ty), )?; let tokens = if matches!(ret_val, RetVal::Future(_) | RetVal::FutureResult(_)) + || is_async { let tokens = gs_quote!(generator_state(self_ty, fn_args, scope) => { let Some(self_) = deno_core::_ops::CppGcObjectGuard::<#self_ty>::try_new_from_cppgc_object(&mut *#scope, #fn_args.this().into()) else { diff --git a/ops/op2/signature.rs b/ops/op2/signature.rs index 0af1af191..400bdb805 100644 --- a/ops/op2/signature.rs +++ b/ops/op2/signature.rs @@ -1470,12 +1470,10 @@ fn parse_type_state(ty: &Type) -> Result { fn parse_cppgc(position: Position, ty: &Type) -> Result { match (position, ty) { - (Position::Arg, Type::Reference(of)) if of.mutability.is_none() => { - match &*of.elem { - Type::Path(of) => Ok(Arg::CppGcResource(stringify_token(&of.path))), - _ => Err(ArgError::InvalidCppGcType(stringify_token(ty))), - } - } + (Position::Arg, Type::Reference(of)) => match &*of.elem { + Type::Path(of) => Ok(Arg::CppGcResource(stringify_token(&of.path))), + _ => Err(ArgError::InvalidCppGcType(stringify_token(ty))), + }, (Position::RetVal, Type::Path(of)) => { Ok(Arg::CppGcResource(stringify_token(&of.path))) } diff --git a/ops/op2/test_cases/sync/cppgc_resource.out b/ops/op2/test_cases/sync/cppgc_resource.out index a910f3582..1b9994b44 100644 --- a/ops/op2/test_cases/sync/cppgc_resource.out +++ b/ops/op2/test_cases/sync/cppgc_resource.out @@ -252,3 +252,170 @@ const fn op_use_cppgc_object() -> ::deno_core::_ops::OpDecl { } ::DECL } + +#[allow(non_camel_case_types)] +const fn op_use_cppgc_object_mut() -> ::deno_core::_ops::OpDecl { + #[allow(non_camel_case_types)] + struct op_use_cppgc_object_mut { + _unconstructable: ::std::marker::PhantomData<()>, + } + impl ::deno_core::_ops::Op for op_use_cppgc_object_mut { + const NAME: &'static str = stringify!(op_use_cppgc_object_mut); + const DECL: ::deno_core::_ops::OpDecl = ::deno_core::_ops::OpDecl::new_internal_op2( + ::deno_core::__op_name_fast!(op_use_cppgc_object_mut), + false, + false, + 1usize as u8, + Self::v8_fn_ptr as _, + Self::v8_fn_ptr_metrics as _, + Some({ + use deno_core::v8::fast_api::Type; + use deno_core::v8::fast_api::CType; + deno_core::v8::fast_api::FastFunction::new_with_bigint( + &[Type::V8Value, Type::V8Value, Type::CallbackOptions], + CType::Void, + Self::v8_fn_ptr_fast as *const ::std::ffi::c_void, + ) + }), + Some({ + use deno_core::v8::fast_api::Type; + use deno_core::v8::fast_api::CType; + deno_core::v8::fast_api::FastFunction::new_with_bigint( + &[Type::V8Value, Type::V8Value, Type::CallbackOptions], + CType::Void, + Self::v8_fn_ptr_fast_metrics as *const ::std::ffi::c_void, + ) + }), + ::deno_core::OpMetadata { + ..::deno_core::OpMetadata::default() + }, + ); + } + impl op_use_cppgc_object_mut { + pub const fn name() -> &'static str { + stringify!(op_use_cppgc_object_mut) + } + #[allow(clippy::too_many_arguments)] + extern "C" fn v8_fn_ptr_fast_metrics<'s>( + this: deno_core::v8::Local, + arg0: deno_core::v8::Local, + fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions< + 's, + >, + ) -> () { + let fast_api_callback_options: &'s mut _ = unsafe { + &mut *fast_api_callback_options + }; + let opctx: &'s _ = unsafe { + &*(deno_core::v8::Local::< + deno_core::v8::External, + >::cast(unsafe { fast_api_callback_options.data.data }) + .value() as *const deno_core::_ops::OpCtx) + }; + deno_core::_ops::dispatch_metrics_fast( + opctx, + deno_core::_ops::OpMetricsEvent::Dispatched, + ); + let res = Self::v8_fn_ptr_fast(this, arg0, fast_api_callback_options); + deno_core::_ops::dispatch_metrics_fast( + opctx, + deno_core::_ops::OpMetricsEvent::Completed, + ); + res + } + #[allow(clippy::too_many_arguments)] + extern "C" fn v8_fn_ptr_fast<'s>( + this: deno_core::v8::Local, + arg0: deno_core::v8::Local, + fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions< + 's, + >, + ) -> () { + #[cfg(debug_assertions)] + let _reentrancy_check_guard = deno_core::_ops::reentrancy_check( + &::DECL, + ); + let fast_api_callback_options: &'s mut _ = unsafe { + &mut *fast_api_callback_options + }; + let result = { + let Some(arg0) = deno_core::cppgc::try_unwrap_cppgc_object::(arg0) + else { + fast_api_callback_options.fallback = true; + return unsafe { std::mem::zeroed() }; + }; + Self::call(arg0) + }; + result as _ + } + #[inline(always)] + fn slow_function_impl<'s>( + info: &'s deno_core::v8::FunctionCallbackInfo, + ) -> usize { + #[cfg(debug_assertions)] + let _reentrancy_check_guard = deno_core::_ops::reentrancy_check( + &::DECL, + ); + let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(info); + let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info( + info, + ); + let result = { + let arg0 = args.get(0usize as i32); + let Some(arg0) = deno_core::cppgc::try_unwrap_cppgc_object::(arg0) + else { + let mut scope = unsafe { deno_core::v8::CallbackScope::new(info) }; + let msg = deno_core::v8::String::new_from_one_byte( + &mut scope, + "expected Wrap".as_bytes(), + deno_core::v8::NewStringType::Normal, + ) + .unwrap(); + let exc = deno_core::v8::Exception::type_error(&mut scope, msg); + scope.throw_exception(exc); + return 1; + }; + Self::call(arg0) + }; + deno_core::_ops::RustToV8RetVal::to_v8_rv(result, &mut rv); + return 0; + } + extern "C" fn v8_fn_ptr<'s>(info: *const deno_core::v8::FunctionCallbackInfo) { + let info: &'s _ = unsafe { &*info }; + Self::slow_function_impl(info); + } + extern "C" fn v8_fn_ptr_metrics<'s>( + info: *const deno_core::v8::FunctionCallbackInfo, + ) { + let info: &'s _ = unsafe { &*info }; + let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info( + info, + ); + let opctx: &'s _ = unsafe { + &*(deno_core::v8::Local::::cast(args.data()) + .value() as *const deno_core::_ops::OpCtx) + }; + deno_core::_ops::dispatch_metrics_slow( + opctx, + deno_core::_ops::OpMetricsEvent::Dispatched, + ); + let res = Self::slow_function_impl(info); + if res == 0 { + deno_core::_ops::dispatch_metrics_slow( + opctx, + deno_core::_ops::OpMetricsEvent::Completed, + ); + } else { + deno_core::_ops::dispatch_metrics_slow( + opctx, + deno_core::_ops::OpMetricsEvent::Error, + ); + } + } + } + impl op_use_cppgc_object_mut { + #[inline(always)] + fn call(_wrap: &mut Wrap) {} + } + ::DECL +} diff --git a/ops/op2/test_cases/sync/cppgc_resource.rs b/ops/op2/test_cases/sync/cppgc_resource.rs index 43aa4b287..3dea71af6 100644 --- a/ops/op2/test_cases/sync/cppgc_resource.rs +++ b/ops/op2/test_cases/sync/cppgc_resource.rs @@ -12,3 +12,6 @@ fn op_make_cppgc_object() -> Wrap { #[op2(fast)] fn op_use_cppgc_object(#[cppgc] _wrap: &Wrap) {} + +#[op2(fast)] +fn op_use_cppgc_object_mut(#[cppgc] _wrap: &mut Wrap) {} diff --git a/ops/op2/test_cases_fail/lifetimes.rs b/ops/op2/test_cases_fail/lifetimes.rs index 83e4b9412..f1baf297c 100644 --- a/ops/op2/test_cases_fail/lifetimes.rs +++ b/ops/op2/test_cases_fail/lifetimes.rs @@ -11,3 +11,6 @@ fn op_use_cppgc_object(#[cppgc] _wrap: &'static Wrap) {} #[op2(fast)] fn op_use_buffer(#[buffer] _buffer: &'static [u8]) {} + +#[op2(async)] +async fn op_use_cppgc_object_mut_async(#[cppgc] _wrap: &mut Wrap) {}