diff options
author | Divy Srivastava <dj.srivastava23@gmail.com> | 2022-12-01 21:29:15 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-02 05:29:15 +0000 |
commit | 9b2b8df927ac23cfa99016a684179f2a3198ba2e (patch) | |
tree | 1d13b575bc7c4f7279b2ff3fdde175a7522d643a /ops/optimizer.rs | |
parent | 075854e5162c3d9f4fd7061d19acbe2c5855536e (diff) |
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
https://chromium-review.googlesource.com/c/v8/v8/+/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
}
```
Diffstat (limited to 'ops/optimizer.rs')
-rw-r--r-- | ops/optimizer.rs | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/ops/optimizer.rs b/ops/optimizer.rs index d25857032..17435407c 100644 --- a/ops/optimizer.rs +++ b/ops/optimizer.rs @@ -20,11 +20,19 @@ pub(crate) enum BailoutReason { } #[derive(Debug, PartialEq)] +enum StringType { + Cow, + Ref, + Owned, +} + +#[derive(Debug, PartialEq)] enum TransformKind { // serde_v8::Value V8Value, SliceU32(bool), SliceU8(bool), + SeqOneByteString(StringType), PtrU8, WasmMemory, } @@ -51,6 +59,13 @@ impl Transform { } } + fn seq_one_byte_string(index: usize, is_ref: StringType) -> Self { + Transform { + kind: TransformKind::SeqOneByteString(is_ref), + index, + } + } + fn wasm_memory(index: usize) -> Self { Transform { kind: TransformKind::WasmMemory, @@ -132,6 +147,21 @@ impl Transform { }; }) } + // &str + TransformKind::SeqOneByteString(str_ty) => { + *ty = parse_quote! { *const #core::v8::fast_api::FastApiOneByteString }; + match str_ty { + StringType::Ref => q!(Vars { var: &ident }, { + let var = unsafe { &*var }.as_str(); + }), + StringType::Cow => q!(Vars { var: &ident }, { + let var = ::std::borrow::Cow::Borrowed(unsafe { &*var }.as_str()); + }), + StringType::Owned => q!(Vars { var: &ident }, { + let var = unsafe { &*var }.as_str().to_owned(); + }), + } + } TransformKind::WasmMemory => { // Note: `ty` is correctly set to __opts by the fast call tier. q!(Vars { var: &ident, core }, { @@ -198,6 +228,7 @@ pub(crate) enum FastValue { V8Value, Uint8Array, Uint32Array, + SeqOneByteString, } impl Default for FastValue { @@ -550,10 +581,58 @@ impl Optimizer { } } } + // Cow<'_, str> + PathSegment { + ident, arguments, .. + } if ident == "Cow" => { + if let PathArguments::AngleBracketed( + AngleBracketedGenericArguments { args, .. }, + ) = arguments + { + assert_eq!(args.len(), 2); + + let ty = &args[1]; + match ty { + GenericArgument::Type(Type::Path(TypePath { + path: Path { segments, .. }, + .. + })) => { + let segment = single_segment(segments)?; + match segment { + PathSegment { ident, .. } if ident == "str" => { + self.fast_parameters.push(FastValue::SeqOneByteString); + assert!(self + .transforms + .insert( + index, + Transform::seq_one_byte_string( + index, + StringType::Cow + ) + ) + .is_none()); + } + _ => return Err(BailoutReason::FastUnsupportedParamType), + } + } + _ => return Err(BailoutReason::FastUnsupportedParamType), + } + } + } // Is `T` a fast scalar? PathSegment { ident, .. } => { if let Some(val) = get_fast_scalar(ident.to_string().as_str()) { self.fast_parameters.push(val); + } else if ident == "String" { + // Is `T` an owned String? + self.fast_parameters.push(FastValue::SeqOneByteString); + assert!(self + .transforms + .insert( + index, + Transform::seq_one_byte_string(index, StringType::Owned) + ) + .is_none()); } else { return Err(BailoutReason::FastUnsupportedParamType); } @@ -574,6 +653,17 @@ impl Optimizer { PathSegment { ident, .. } if ident == "OpState" => { self.has_ref_opstate = true; } + // Is `T` a str? + PathSegment { ident, .. } if ident == "str" => { + self.fast_parameters.push(FastValue::SeqOneByteString); + assert!(self + .transforms + .insert( + index, + Transform::seq_one_byte_string(index, StringType::Ref) + ) + .is_none()); + } _ => return Err(BailoutReason::FastUnsupportedParamType), } } |