diff options
Diffstat (limited to 'ops/op2/dispatch_fast.rs')
-rw-r--r-- | ops/op2/dispatch_fast.rs | 327 |
1 files changed, 0 insertions, 327 deletions
diff --git a/ops/op2/dispatch_fast.rs b/ops/op2/dispatch_fast.rs deleted file mode 100644 index f9d74416a..000000000 --- a/ops/op2/dispatch_fast.rs +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -use super::generator_state::GeneratorState; -use super::signature::Arg; -use super::signature::NumericArg; -use super::signature::ParsedSignature; -use super::signature::RetVal; -use super::signature::Special; -use super::V8MappingError; -use proc_macro2::Ident; -use proc_macro2::TokenStream; -use quote::format_ident; -use quote::quote; -use std::iter::zip; - -#[allow(unused)] -#[derive(Debug, Default, PartialEq, Clone)] -pub(crate) enum V8FastCallType { - #[default] - Void, - Bool, - U32, - I32, - U64, - I64, - F32, - F64, - Pointer, - V8Value, - Uint8Array, - Uint32Array, - Float64Array, - SeqOneByteString, - CallbackOptions, -} - -impl V8FastCallType { - /// Quote fast value type. - fn quote_rust_type(&self, deno_core: &TokenStream) -> TokenStream { - match self { - V8FastCallType::Void => quote!(()), - V8FastCallType::Bool => quote!(bool), - V8FastCallType::U32 => quote!(u32), - V8FastCallType::I32 => quote!(i32), - V8FastCallType::U64 => quote!(u64), - V8FastCallType::I64 => quote!(i64), - V8FastCallType::F32 => quote!(f32), - V8FastCallType::F64 => quote!(f64), - V8FastCallType::Pointer => quote!(*mut ::std::ffi::c_void), - V8FastCallType::V8Value => { - quote!(#deno_core::v8::Local<#deno_core::v8::Value>) - } - V8FastCallType::CallbackOptions => { - quote!(*mut #deno_core::v8::fast_api::FastApiCallbackOptions) - } - V8FastCallType::SeqOneByteString => { - quote!(*mut #deno_core::v8::fast_api::FastApiOneByteString) - } - V8FastCallType::Uint8Array - | V8FastCallType::Uint32Array - | V8FastCallType::Float64Array => unreachable!(), - } - } - - /// Quote fast value type's variant. - fn quote_ctype(&self) -> TokenStream { - match &self { - V8FastCallType::Void => quote!(CType::Void), - V8FastCallType::Bool => quote!(CType::Bool), - V8FastCallType::U32 => quote!(CType::Uint32), - V8FastCallType::I32 => quote!(CType::Int32), - V8FastCallType::U64 => quote!(CType::Uint64), - V8FastCallType::I64 => quote!(CType::Int64), - V8FastCallType::F32 => quote!(CType::Float32), - V8FastCallType::F64 => quote!(CType::Float64), - V8FastCallType::Pointer => quote!(CType::Pointer), - V8FastCallType::V8Value => quote!(CType::V8Value), - V8FastCallType::CallbackOptions => quote!(CType::CallbackOptions), - V8FastCallType::Uint8Array => unreachable!(), - V8FastCallType::Uint32Array => unreachable!(), - V8FastCallType::Float64Array => unreachable!(), - V8FastCallType::SeqOneByteString => quote!(CType::SeqOneByteString), - } - } - - /// Quote fast value type's variant. - fn quote_type(&self) -> TokenStream { - match &self { - V8FastCallType::Void => quote!(Type::Void), - V8FastCallType::Bool => quote!(Type::Bool), - V8FastCallType::U32 => quote!(Type::Uint32), - V8FastCallType::I32 => quote!(Type::Int32), - V8FastCallType::U64 => quote!(Type::Uint64), - V8FastCallType::I64 => quote!(Type::Int64), - V8FastCallType::F32 => quote!(Type::Float32), - V8FastCallType::F64 => quote!(Type::Float64), - V8FastCallType::Pointer => quote!(Type::Pointer), - V8FastCallType::V8Value => quote!(Type::V8Value), - V8FastCallType::CallbackOptions => quote!(Type::CallbackOptions), - V8FastCallType::Uint8Array => quote!(Type::TypedArray(CType::Uint8)), - V8FastCallType::Uint32Array => quote!(Type::TypedArray(CType::Uint32)), - V8FastCallType::Float64Array => quote!(Type::TypedArray(CType::Float64)), - V8FastCallType::SeqOneByteString => quote!(Type::SeqOneByteString), - } - } -} - -pub fn generate_dispatch_fast( - generator_state: &mut GeneratorState, - signature: &ParsedSignature, -) -> Result<Option<(TokenStream, TokenStream)>, V8MappingError> { - let mut inputs = vec![]; - for arg in &signature.args { - let Some(fv) = map_arg_to_v8_fastcall_type(arg)? else { - return Ok(None); - }; - inputs.push(fv); - } - let mut names = inputs - .iter() - .enumerate() - .map(|(i, _)| format_ident!("arg{i}")) - .collect::<Vec<_>>(); - - let ret_val = match &signature.ret_val { - RetVal::Infallible(arg) => arg, - RetVal::Result(arg) => arg, - }; - - let output = match map_retval_to_v8_fastcall_type(ret_val)? { - None => return Ok(None), - Some(rv) => rv, - }; - - let GeneratorState { - fast_function, - deno_core, - result, - opctx, - fast_api_callback_options, - needs_fast_api_callback_options, - needs_fast_opctx, - .. - } = generator_state; - - let handle_error = match signature.ret_val { - RetVal::Infallible(_) => quote!(), - RetVal::Result(_) => { - *needs_fast_api_callback_options = true; - *needs_fast_opctx = true; - inputs.push(V8FastCallType::CallbackOptions); - quote! { - let #result = match #result { - Ok(#result) => #result, - Err(err) => { - // FASTCALL FALLBACK: This is where we set 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. - - // The reason we need to do this is because V8 does not allow exceptions to be thrown from the - // fast call. Instead, you are required to set the fallback flag, which indicates to V8 that it - // should re-call the slow version of the function. Technically the slow call should perform the - // same operation and then throw the same error (because it should be idempotent), but in our - // case we stash the error and pick it up on the slow path before doing any work. - - // TODO(mmastrac): We should allow an #[op] flag to re-perform slow calls without the error path when - // the method is performance sensitive. - - // 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. - unsafe { #opctx.unsafely_set_last_error_for_ops_only(err); } - #fast_api_callback_options.fallback = true; - return ::std::default::Default::default(); - } - }; - } - } - }; - - let input_types = inputs.iter().map(|fv| fv.quote_type()).collect::<Vec<_>>(); - let output_type = output.quote_ctype(); - - let fast_definition = quote! { - use #deno_core::v8::fast_api::Type; - use #deno_core::v8::fast_api::CType; - #deno_core::v8::fast_api::FastFunction::new( - &[ Type::V8Value, #( #input_types ),* ], - #output_type, - Self::#fast_function as *const ::std::ffi::c_void - ) - }; - - let output_type = output.quote_rust_type(deno_core); - let mut types = inputs - .iter() - .map(|rv| rv.quote_rust_type(deno_core)) - .collect::<Vec<_>>(); - - let call_idents = names.clone(); - let call_args = zip(names.iter(), signature.args.iter()) - .map(|(name, arg)| map_v8_fastcall_arg_to_arg(deno_core, name, arg)) - .collect::<Vec<_>>(); - - let with_fast_api_callback_options = if *needs_fast_api_callback_options { - types.push(V8FastCallType::CallbackOptions.quote_rust_type(deno_core)); - names.push(fast_api_callback_options.clone()); - quote! { - let #fast_api_callback_options = unsafe { &mut *#fast_api_callback_options }; - } - } else { - quote!() - }; - let with_opctx = if *needs_fast_opctx { - quote!( - let #opctx = unsafe { - &*(#deno_core::v8::Local::<v8::External>::cast(unsafe { #fast_api_callback_options.data.data }).value() - as *const #deno_core::_ops::OpCtx) - }; - ) - } else { - quote!() - }; - - let fast_fn = quote!( - fn #fast_function( - _: #deno_core::v8::Local<#deno_core::v8::Object>, - #( #names: #types, )* - ) -> #output_type { - #with_fast_api_callback_options - #with_opctx - #(#call_args)* - let #result = Self::call(#(#call_idents),*); - #handle_error - #result - } - ); - - Ok(Some((fast_definition, fast_fn))) -} - -fn map_v8_fastcall_arg_to_arg( - deno_core: &TokenStream, - arg_ident: &Ident, - arg: &Arg, -) -> TokenStream { - let arg_temp = format_ident!("{}_temp", arg_ident); - match arg { - Arg::Special(Special::RefStr) => { - quote! { - let mut #arg_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024]; - let #arg_ident = &#deno_core::_ops::to_str_ptr(unsafe { &mut *#arg_ident }, &mut #arg_temp); - } - } - Arg::Special(Special::String) => { - quote!(let #arg_ident = #deno_core::_ops::to_string_ptr(unsafe { &mut *#arg_ident });) - } - Arg::Special(Special::CowStr) => { - quote! { - let mut #arg_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024]; - let #arg_ident = #deno_core::_ops::to_str_ptr(unsafe { &mut *#arg_ident }, &mut #arg_temp); - } - } - _ => quote!(let #arg_ident = #arg_ident as _;), - } -} - -fn map_arg_to_v8_fastcall_type( - arg: &Arg, -) -> Result<Option<V8FastCallType>, V8MappingError> { - let rv = match arg { - Arg::OptionNumeric(_) | Arg::SerdeV8(_) => return Ok(None), - Arg::Numeric(NumericArg::bool) => V8FastCallType::Bool, - Arg::Numeric(NumericArg::u32) - | Arg::Numeric(NumericArg::u16) - | Arg::Numeric(NumericArg::u8) => V8FastCallType::U32, - Arg::Numeric(NumericArg::i32) - | Arg::Numeric(NumericArg::i16) - | Arg::Numeric(NumericArg::i8) - | Arg::Numeric(NumericArg::__SMI__) => V8FastCallType::I32, - Arg::Numeric(NumericArg::u64) | Arg::Numeric(NumericArg::usize) => { - V8FastCallType::U64 - } - Arg::Numeric(NumericArg::i64) | Arg::Numeric(NumericArg::isize) => { - V8FastCallType::I64 - } - // Ref strings that are one byte internally may be passed as a SeqOneByteString, - // which gives us a FastApiOneByteString. - Arg::Special(Special::RefStr) => V8FastCallType::SeqOneByteString, - // Owned strings can be fast, but we'll have to copy them. - Arg::Special(Special::String) => V8FastCallType::SeqOneByteString, - // Cow strings can be fast, but may require copying - Arg::Special(Special::CowStr) => V8FastCallType::SeqOneByteString, - _ => return Err(V8MappingError::NoMapping("a fast argument", arg.clone())), - }; - Ok(Some(rv)) -} - -fn map_retval_to_v8_fastcall_type( - arg: &Arg, -) -> Result<Option<V8FastCallType>, V8MappingError> { - let rv = match arg { - Arg::OptionNumeric(_) | Arg::SerdeV8(_) => return Ok(None), - Arg::Void => V8FastCallType::Void, - Arg::Numeric(NumericArg::bool) => V8FastCallType::Bool, - Arg::Numeric(NumericArg::u32) - | Arg::Numeric(NumericArg::u16) - | Arg::Numeric(NumericArg::u8) => V8FastCallType::U32, - Arg::Numeric(NumericArg::i32) - | Arg::Numeric(NumericArg::i16) - | Arg::Numeric(NumericArg::i8) => V8FastCallType::I32, - Arg::Numeric(NumericArg::u64) | Arg::Numeric(NumericArg::usize) => { - V8FastCallType::U64 - } - Arg::Numeric(NumericArg::i64) | Arg::Numeric(NumericArg::isize) => { - V8FastCallType::I64 - } - // We don't return special return types - Arg::Option(_) => return Ok(None), - Arg::Special(_) => return Ok(None), - _ => { - return Err(V8MappingError::NoMapping( - "a fast return value", - arg.clone(), - )) - } - }; - Ok(Some(rv)) -} |