diff options
author | Matt Mastracci <matthew@mastracci.com> | 2023-07-01 16:07:05 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-01 22:07:05 +0000 |
commit | 6afdcf59b80b4a3ecf60f220ddff14f4309133d0 (patch) | |
tree | d6a6dad1945430e161fba9e86d93fe3d8893d89c /ops/op2/dispatch_slow.rs | |
parent | 0f719aa79c2b471815c9d21014b37719c6557c1b (diff) |
refactor(ops): op2 supports strings in argument and return position (#19613)
Support strings (&str, String, and Cow) in the argument position and String in the return position. Avoids
copies where possible, though this is not always something we can do.
Diffstat (limited to 'ops/op2/dispatch_slow.rs')
-rw-r--r-- | ops/op2/dispatch_slow.rs | 66 |
1 files changed, 62 insertions, 4 deletions
diff --git a/ops/op2/dispatch_slow.rs b/ops/op2/dispatch_slow.rs index bf36e5d83..2ec67cc76 100644 --- a/ops/op2/dispatch_slow.rs +++ b/ops/op2/dispatch_slow.rs @@ -8,6 +8,7 @@ use super::signature::Special; use super::MacroConfig; use super::V8MappingError; use proc_macro2::TokenStream; +use quote::format_ident; use quote::quote; pub(crate) fn generate_dispatch_slow( @@ -151,10 +152,14 @@ pub fn from_arg( arg: &Arg, ) -> Result<TokenStream, V8MappingError> { let GeneratorState { - deno_core, args, .. + deno_core, + args, + scope, + needs_scope, + .. } = &mut generator_state; let arg_ident = args.get_mut(index).expect("Argument at index was missing"); - + let arg_temp = format_ident!("{}_temp", arg_ident); let res = match arg { Arg::Numeric(NumericArg::bool) => quote! { let #arg_ident = #arg_ident.is_true(); @@ -198,13 +203,31 @@ pub fn from_arg( } } Arg::Option(Special::String) => { + *needs_scope = true; + quote! { + let #arg_ident = #arg_ident.to_rust_string_lossy(#scope); + } + } + Arg::Special(Special::String) => { + *needs_scope = true; quote! { - let #arg_ident = #arg_ident.to_rust_string_lossy(); + let #arg_ident = #arg_ident.to_rust_string_lossy(#scope); } } Arg::Special(Special::RefStr) => { + *needs_scope = true; + quote! { + // Trade 1024 bytes of stack space for potentially non-allocating strings + let mut #arg_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024]; + let #arg_ident = &#deno_core::_ops::to_str(#scope, &#arg_ident, &mut #arg_temp); + } + } + Arg::Special(Special::CowStr) => { + *needs_scope = true; quote! { - let #arg_ident = #arg_ident.to_rust_string_lossy(); + // Trade 1024 bytes of stack space for potentially non-allocating strings + let mut #arg_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024]; + let #arg_ident = #deno_core::_ops::to_str(#scope, &#arg_ident, &mut #arg_temp); } } _ => return Err(V8MappingError::NoMapping("a slow argument", arg.clone())), @@ -243,9 +266,12 @@ pub fn return_value_infallible( ret_type: &Arg, ) -> Result<TokenStream, V8MappingError> { let GeneratorState { + deno_core, + scope, result, retval, needs_retval, + needs_scope, .. } = generator_state; @@ -265,6 +291,38 @@ pub fn return_value_infallible( *needs_retval = true; quote!(#retval.set_int32(#result as i32);) } + Arg::Special(Special::String) => { + *needs_retval = true; + *needs_scope = true; + quote! { + if #result.is_empty() { + #retval.set_empty_string(); + } else { + // This should not fail in normal cases + // TODO(mmastrac): This has extra allocations that we need to get rid of, especially if the string + // is ASCII. We could make an "external Rust String" string in V8 from these and re-use the allocation. + let temp = #deno_core::v8::String::new(#scope, &#result).unwrap(); + #retval.set(temp.into()); + } + } + } + Arg::Option(Special::String) => { + *needs_retval = true; + *needs_scope = true; + // End the generator_state borrow + let (result, retval) = (result.clone(), retval.clone()); + let some = return_value_infallible( + generator_state, + &Arg::Special(Special::String), + )?; + quote! { + if let Some(#result) = #result { + #some + } else { + #retval.set_null(); + } + } + } _ => { return Err(V8MappingError::NoMapping( "a slow return value", |