From 482ffcf475cd210aac3b8597ef9a36fa0ff75cea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 25 Jul 2023 23:43:41 +0200 Subject: [PATCH] feat(ops): support SMI in return types (#86) --- ops/op2/dispatch_fast.rs | 3 +- ops/op2/dispatch_slow.rs | 9 +- ops/op2/signature.rs | 4 + ops/op2/test_cases/async/async_arg_return.out | 4 +- .../async/async_arg_return_result.out | 4 +- ops/op2/test_cases/async/async_opstate.out | 4 +- ops/op2/test_cases/async/async_result.out | 4 +- .../test_cases/async/async_result_impl.out | 4 +- ops/op2/test_cases/async/async_result_smi.out | 87 ++++++++++++++++++ ops/op2/test_cases/async/async_result_smi.rs | 11 +++ ops/op2/test_cases/sync/smi.out | 90 +++++++++++++++++++ ops/op2/test_cases/sync/smi.rs | 8 ++ 12 files changed, 223 insertions(+), 9 deletions(-) create mode 100644 ops/op2/test_cases/async/async_result_smi.out create mode 100644 ops/op2/test_cases/async/async_result_smi.rs diff --git a/ops/op2/dispatch_fast.rs b/ops/op2/dispatch_fast.rs index 05926648c..0d309da86 100644 --- a/ops/op2/dispatch_fast.rs +++ b/ops/op2/dispatch_fast.rs @@ -471,7 +471,8 @@ fn map_retval_to_v8_fastcall_type( Arg::Numeric(NumericArg::u32) | Arg::Numeric(NumericArg::u16) | Arg::Numeric(NumericArg::u8) => V8FastCallType::U32, - Arg::Numeric(NumericArg::i32) + Arg::Numeric(NumericArg::__SMI__) + | Arg::Numeric(NumericArg::i32) | Arg::Numeric(NumericArg::i16) | Arg::Numeric(NumericArg::i8) => V8FastCallType::I32, Arg::Numeric(NumericArg::u64) | Arg::Numeric(NumericArg::usize) => { diff --git a/ops/op2/dispatch_slow.rs b/ops/op2/dispatch_slow.rs index b559ad5c5..58c4b3a51 100644 --- a/ops/op2/dispatch_slow.rs +++ b/ops/op2/dispatch_slow.rs @@ -522,7 +522,8 @@ pub fn return_value_infallible( } Arg::Numeric(NumericArg::i8) | Arg::Numeric(NumericArg::i16) - | Arg::Numeric(NumericArg::i32) => { + | Arg::Numeric(NumericArg::i32) + | Arg::Numeric(NumericArg::__SMI__) => { quote!(#retval.set_int32(#result as i32);) } Arg::Numeric(NumericArg::i64 | NumericArg::isize) => { @@ -644,8 +645,10 @@ pub fn return_value_v8_value( Arg::Numeric(NumericArg::bool) => { quote!(Ok(#deno_core::v8::Boolean::new(#result).into())) } - Arg::Numeric(NumericArg::i8 | NumericArg::i16 | NumericArg::i32) => { - quote!(Ok(#deno_core::v8::Integer::new(#scope, #result).into())) + Arg::Numeric( + NumericArg::i8 | NumericArg::i16 | NumericArg::i32 | NumericArg::__SMI__, + ) => { + quote!(Ok(#deno_core::v8::Integer::new(#scope, #result as i32).into())) } Arg::Numeric(NumericArg::u8 | NumericArg::u16 | NumericArg::u32) => { quote!(Ok(#deno_core::v8::Integer::new_from_unsigned(#scope, #result).into())) diff --git a/ops/op2/signature.rs b/ops/op2/signature.rs index 1bfa790f1..26a0bffab 100644 --- a/ops/op2/signature.rs +++ b/ops/op2/signature.rs @@ -1231,6 +1231,10 @@ mod tests { fn op_resource(#[smi] rid: ResourceId, #[buffer] buffer: &[u8]); (Numeric(__SMI__), Buffer(Slice(Ref, u8))) -> Infallible(Void) ); + test!( + #[smi] fn op_resource2(#[smi] rid: ResourceId) -> Result; + (Numeric(__SMI__)) -> Result(Numeric(__SMI__)) + ); test!( fn op_option_numeric_result(state: &mut OpState) -> Result, AnyError>; (Ref(Mut, OpState)) -> Result(OptionNumeric(u32)) diff --git a/ops/op2/test_cases/async/async_arg_return.out b/ops/op2/test_cases/async/async_arg_return.out index 56a063b3e..3f01cfe9f 100644 --- a/ops/op2/test_cases/async/async_arg_return.out +++ b/ops/op2/test_cases/async/async_arg_return.out @@ -58,7 +58,9 @@ impl op_async { opctx, promise_id, result, - |scope, result| { Ok(deno_core::v8::Integer::new(scope, result).into()) }, + |scope, result| { + Ok(deno_core::v8::Integer::new(scope, result as i32).into()) + }, ) { rv.set_int32(result as i32); } diff --git a/ops/op2/test_cases/async/async_arg_return_result.out b/ops/op2/test_cases/async/async_arg_return_result.out index 2bfe2a29e..caf693c07 100644 --- a/ops/op2/test_cases/async/async_arg_return_result.out +++ b/ops/op2/test_cases/async/async_arg_return_result.out @@ -58,7 +58,9 @@ impl op_async { opctx, promise_id, result, - |scope, result| { Ok(deno_core::v8::Integer::new(scope, result).into()) }, + |scope, result| { + Ok(deno_core::v8::Integer::new(scope, result as i32).into()) + }, ) { match result { Ok(result) => { diff --git a/ops/op2/test_cases/async/async_opstate.out b/ops/op2/test_cases/async/async_opstate.out index d4cb2b81b..4513d8b59 100644 --- a/ops/op2/test_cases/async/async_opstate.out +++ b/ops/op2/test_cases/async/async_opstate.out @@ -46,7 +46,9 @@ impl op_async_opstate { opctx, promise_id, result, - |scope, result| { Ok(deno_core::v8::Integer::new(scope, result).into()) }, + |scope, result| { + Ok(deno_core::v8::Integer::new(scope, result as i32).into()) + }, ) { match result { Ok(result) => { diff --git a/ops/op2/test_cases/async/async_result.out b/ops/op2/test_cases/async/async_result.out index a9ac49a2a..d0838e3ca 100644 --- a/ops/op2/test_cases/async/async_result.out +++ b/ops/op2/test_cases/async/async_result.out @@ -42,7 +42,9 @@ impl op_async { opctx, promise_id, result, - |scope, result| { Ok(deno_core::v8::Integer::new(scope, result).into()) }, + |scope, result| { + Ok(deno_core::v8::Integer::new(scope, result as i32).into()) + }, ) { match result { Ok(result) => { diff --git a/ops/op2/test_cases/async/async_result_impl.out b/ops/op2/test_cases/async/async_result_impl.out index 7021f0ff5..43bc20930 100644 --- a/ops/op2/test_cases/async/async_result_impl.out +++ b/ops/op2/test_cases/async/async_result_impl.out @@ -72,7 +72,9 @@ impl op_async_result_impl { opctx, promise_id, result, - |scope, result| { Ok(deno_core::v8::Integer::new(scope, result).into()) }, + |scope, result| { + Ok(deno_core::v8::Integer::new(scope, result as i32).into()) + }, ) { match result { Ok(result) => { diff --git a/ops/op2/test_cases/async/async_result_smi.out b/ops/op2/test_cases/async/async_result_smi.out new file mode 100644 index 000000000..fb55b89b9 --- /dev/null +++ b/ops/op2/test_cases/async/async_result_smi.out @@ -0,0 +1,87 @@ +#[allow(non_camel_case_types)] +pub struct op_async { + _unconstructable: ::std::marker::PhantomData<()>, +} +impl deno_core::_ops::Op for op_async { + const NAME: &'static str = stringify!(op_async); + const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl::new_internal( + stringify!(op_async), + true, + false, + false, + 2usize as u8, + Self::v8_fn_ptr as _, + None, + ); +} +impl op_async { + pub const fn name() -> &'static str { + stringify!(op_async) + } + #[deprecated(note = "Use the const op::DECL instead")] + pub const fn decl() -> deno_core::_ops::OpDecl { + ::DECL + } + extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) { + let mut scope = unsafe { deno_core::v8::CallbackScope::new(&*info) }; + let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe { + &*info + }); + let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe { + &*info + }); + let opctx = unsafe { + &*(deno_core::v8::Local::::cast(args.data()).value() + as *const deno_core::_ops::OpCtx) + }; + let result = { + let arg0 = args.get(1usize as i32); + let Some(arg0) = deno_core::_ops::to_i32_option(&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 i32".as_bytes(), + deno_core::v8::NewStringType::Normal, + ) + .unwrap(); + let exc = deno_core::v8::Exception::type_error(&mut scope, msg); + scope.throw_exception(exc); + return; + }; + let arg0 = arg0 as _; + Self::call(arg0) + }; + let promise_id = deno_core::_ops::to_i32_option(&args.get(0)) + .unwrap_or_default(); + if let Some(result) + = deno_core::_ops::map_async_op_fallible( + opctx, + promise_id, + result, + |scope, result| { + Ok(deno_core::v8::Integer::new(scope, result as i32).into()) + }, + ) { + match result { + Ok(result) => { + rv.set_int32(result as i32); + } + Err(err) => { + let err = err.into(); + let opstate = ::std::cell::RefCell::borrow(&*opctx.state); + let exception = deno_core::error::to_v8_error( + &mut scope, + opstate.get_error_class_fn, + &err, + ); + scope.throw_exception(exception); + return; + } + }; + } + } + #[inline(always)] + pub async fn call(rid: ResourceId) -> std::io::Result { + Ok(rid as _) + } +} diff --git a/ops/op2/test_cases/async/async_result_smi.rs b/ops/op2/test_cases/async/async_result_smi.rs new file mode 100644 index 000000000..f6208454f --- /dev/null +++ b/ops/op2/test_cases/async/async_result_smi.rs @@ -0,0 +1,11 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +#![deny(warnings)] +deno_ops_compile_test_runner::prelude!(); + +pub type ResourceId = i16; + +#[op2(async)] +#[smi] +pub async fn op_async(#[smi] rid: ResourceId) -> std::io::Result { + Ok(rid as _) +} diff --git a/ops/op2/test_cases/sync/smi.out b/ops/op2/test_cases/sync/smi.out index a61cfca7e..580f4ce67 100644 --- a/ops/op2/test_cases/sync/smi.out +++ b/ops/op2/test_cases/sync/smi.out @@ -87,3 +87,93 @@ impl op_add { id as u32 + extra as u32 } } + +#[allow(non_camel_case_types)] +struct op_subtract { + _unconstructable: ::std::marker::PhantomData<()>, +} +impl deno_core::_ops::Op for op_subtract { + const NAME: &'static str = stringify!(op_subtract); + const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl::new_internal( + stringify!(op_subtract), + false, + false, + false, + 2usize as u8, + Self::v8_fn_ptr 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::Int32, Type::Int32], + CType::Int32, + Self::v8_fn_ptr_fast as *const ::std::ffi::c_void, + ) + }), + ); +} +impl op_subtract { + pub const fn name() -> &'static str { + stringify!(op_subtract) + } + #[deprecated(note = "Use the const op::DECL instead")] + pub const fn decl() -> deno_core::_ops::OpDecl { + ::DECL + } + fn v8_fn_ptr_fast( + _: deno_core::v8::Local, + arg0: i32, + arg1: i32, + ) -> i32 { + let result = { + let arg0 = arg0 as _; + let arg1 = arg1 as _; + Self::call(arg0, arg1) + }; + 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 + }); + let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe { + &*info + }); + let result = { + let arg0 = args.get(0usize as i32); + let Some(arg0) = deno_core::_ops::to_i32_option(&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 i32".as_bytes(), + deno_core::v8::NewStringType::Normal, + ) + .unwrap(); + let exc = deno_core::v8::Exception::type_error(&mut scope, msg); + scope.throw_exception(exc); + return; + }; + let arg0 = arg0 as _; + let arg1 = args.get(1usize as i32); + let Some(arg1) = deno_core::_ops::to_i32_option(&arg1) else { + let mut scope = unsafe { deno_core::v8::CallbackScope::new(&*info) }; + let msg = deno_core::v8::String::new_from_one_byte( + &mut scope, + "expected i32".as_bytes(), + deno_core::v8::NewStringType::Normal, + ) + .unwrap(); + let exc = deno_core::v8::Exception::type_error(&mut scope, msg); + scope.throw_exception(exc); + return; + }; + let arg1 = arg1 as _; + Self::call(arg0, arg1) + }; + rv.set_int32(result as i32); + } + #[inline(always)] + fn call(id: StubId, extra: i32) -> StubId { + id - extra + } +} diff --git a/ops/op2/test_cases/sync/smi.rs b/ops/op2/test_cases/sync/smi.rs index 22db30d03..2bb1ca213 100644 --- a/ops/op2/test_cases/sync/smi.rs +++ b/ops/op2/test_cases/sync/smi.rs @@ -8,3 +8,11 @@ pub type ResourceId = i16; fn op_add(#[smi] id: ResourceId, extra: u16) -> u32 { id as u32 + extra as u32 } + +pub type StubId = i32; + +#[op2(fast)] +#[smi] +fn op_subtract(#[smi] id: StubId, extra: i32) -> StubId { + id - extra +}