feat(ops): Fast zero copy string arguments (#16777)

Uses SeqOneByteString optimization to do zero-copy `&str` arguments in
fast calls.

- [x] Depends on https://github.com/denoland/rusty_v8/pull/1129
- [x] Depends on
4036884
- [x] Disable in async ops
- [x] Make it work with owned `String` with an extra alloc in fast path.
- [x] Support `Cow<'_, str>`. Owned for slow case, Borrowed for fast
case

```rust
#[op]
fn op_string_len(s: &str) -> u32 { 
  str.len() as u32 
}
```
This commit is contained in:
Divy Srivastava 2022-12-01 21:29:15 -08:00 committed by GitHub
parent 075854e516
commit 9b2b8df927
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 804 additions and 97 deletions

View file

@ -400,7 +400,12 @@ fn codegen_arg(
return quote! { let #ident = (); };
}
// Fast path for `String`
if is_string(&**ty) {
if let Some(is_ref) = is_string(&**ty) {
let ref_block = if is_ref {
quote! { let #ident = #ident.as_ref(); }
} else {
quote! {}
};
return quote! {
let #ident = match #core::v8::Local::<#core::v8::String>::try_from(args.get(#idx as i32)) {
Ok(v8_string) => #core::serde_v8::to_utf8(v8_string, scope),
@ -408,6 +413,18 @@ fn codegen_arg(
return #core::_ops::throw_type_error(scope, format!("Expected string at position {}", #idx));
}
};
#ref_block
};
}
// Fast path for `Cow<'_, str>`
if is_cow_str(&**ty) {
return quote! {
let #ident = match #core::v8::Local::<#core::v8::String>::try_from(args.get(#idx as i32)) {
Ok(v8_string) => ::std::borrow::Cow::Owned(#core::serde_v8::to_utf8(v8_string, scope)),
Err(_) => {
return #core::_ops::throw_type_error(scope, format!("Expected string at position {}", #idx));
}
};
};
}
// Fast path for `Option<String>`
@ -618,14 +635,25 @@ fn is_result(ty: impl ToTokens) -> bool {
}
}
fn is_string(ty: impl ToTokens) -> bool {
tokens(ty) == "String"
fn is_string(ty: impl ToTokens) -> Option<bool> {
let toks = tokens(ty);
if toks == "String" {
return Some(false);
}
if toks == "& str" {
return Some(true);
}
None
}
fn is_option_string(ty: impl ToTokens) -> bool {
tokens(ty) == "Option < String >"
}
fn is_cow_str(ty: impl ToTokens) -> bool {
tokens(&ty).starts_with("Cow <") && tokens(&ty).ends_with("str >")
}
enum SliceType {
U8,
U8Mut,