diff options
Diffstat (limited to 'ops/op2/dispatch_slow.rs')
-rw-r--r-- | ops/op2/dispatch_slow.rs | 100 |
1 files changed, 71 insertions, 29 deletions
diff --git a/ops/op2/dispatch_slow.rs b/ops/op2/dispatch_slow.rs index f54a28f1c..f10217a2d 100644 --- a/ops/op2/dispatch_slow.rs +++ b/ops/op2/dispatch_slow.rs @@ -1,3 +1,4 @@ +use super::MacroConfig; // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use super::generator_state::GeneratorState; use super::signature::Arg; @@ -9,11 +10,31 @@ use super::V8MappingError; use proc_macro2::TokenStream; use quote::quote; -pub fn generate_dispatch_slow( +pub(crate) fn generate_dispatch_slow( + config: &MacroConfig, generator_state: &mut GeneratorState, signature: &ParsedSignature, ) -> Result<TokenStream, V8MappingError> { let mut output = TokenStream::new(); + + // Fast ops require the slow op to check op_ctx for the last error + if config.fast && matches!(signature.ret_val, RetVal::Result(_)) { + generator_state.needs_opctx = true; + let throw_exception = throw_exception(generator_state)?; + // If the fast op returned an error, we must throw it rather than doing work. + output.extend(quote!{ + // FASTCALL FALLBACK: This is where we pick up the errors for the slow-call error pickup + // path. There is no code running between this and the other FASTCALL FALLBACK comment, + // except some V8 code required to perform the fallback process. This is why the below call is safe. + + // SAFETY: We guarantee that OpCtx has no mutable references once ops are live and being called, + // allowing us to perform this one little bit of mutable magic. + if let Some(err) = unsafe { opctx.unsafely_take_last_error_for_ops_only() } { + #throw_exception + } + }); + } + for (index, arg) in signature.args.iter().enumerate() { output.extend(extract_arg(generator_state, index)?); output.extend(from_arg(generator_state, index, arg)?); @@ -27,6 +48,12 @@ pub fn generate_dispatch_slow( quote!() }; + let with_opctx = if generator_state.needs_opctx { + with_opctx(generator_state) + } else { + quote!() + }; + let with_retval = if generator_state.needs_retval { with_retval(generator_state) } else { @@ -51,6 +78,7 @@ pub fn generate_dispatch_slow( #with_scope #with_retval #with_args + #with_opctx #output }}) @@ -94,9 +122,11 @@ fn with_opctx(generator_state: &mut GeneratorState) -> TokenStream { deno_core, opctx, fn_args, + needs_args, .. - } = &generator_state; + } = generator_state; + *needs_args = true; quote!(let #opctx = unsafe { &*(#deno_core::v8::Local::<#deno_core::v8::External>::cast(#fn_args.data()).value() as *const #deno_core::_ops::OpCtx) @@ -246,56 +276,68 @@ pub fn return_value_infallible( Ok(res) } -pub fn return_value_result( +fn return_value_result( generator_state: &mut GeneratorState, ret_type: &Arg, ) -> Result<TokenStream, V8MappingError> { let infallible = return_value_infallible(generator_state, ret_type)?; + let exception = throw_exception(generator_state)?; + + let GeneratorState { result, .. } = &generator_state; + + let tokens = quote!( + match #result { + Ok(#result) => { + #infallible + } + Err(err) => { + #exception + } + }; + ); + Ok(tokens) +} + +/// Generates code to throw an exception, adding required additional dependencies as needed. +fn throw_exception( + generator_state: &mut GeneratorState, +) -> Result<TokenStream, V8MappingError> { let maybe_scope = if generator_state.needs_scope { quote!() } else { with_scope(generator_state) }; - let maybe_args = if generator_state.needs_args { + let maybe_opctx = if generator_state.needs_opctx { quote!() } else { - with_fn_args(generator_state) + with_opctx(generator_state) }; - let maybe_opctx = if generator_state.needs_opctx { + let maybe_args = if generator_state.needs_args { quote!() } else { - with_opctx(generator_state) + with_fn_args(generator_state) }; let GeneratorState { deno_core, - result, scope, opctx, .. } = &generator_state; - let tokens = quote!( - match #result { - Ok(#result) => { - #infallible - } - Err(err) => { - #maybe_scope - #maybe_args - #maybe_opctx - let opstate = ::std::cell::RefCell::borrow(&*#opctx.state); - let exception = #deno_core::error::to_v8_error( - #scope, - opstate.get_error_class_fn, - &err, - ); - scope.throw_exception(exception); - return; - } - }; - ); - Ok(tokens) + Ok(quote! { + #maybe_scope + #maybe_args + #maybe_opctx + let opstate = ::std::cell::RefCell::borrow(&*#opctx.state); + let exception = #deno_core::error::to_v8_error( + #scope, + opstate.get_error_class_fn, + &err, + ); + scope.throw_exception(exception); + return; + }) } |