summaryrefslogtreecommitdiff
path: root/ops/optimizer.rs
diff options
context:
space:
mode:
authorDivy Srivastava <dj.srivastava23@gmail.com>2022-12-01 21:29:15 -0800
committerGitHub <noreply@github.com>2022-12-02 05:29:15 +0000
commit9b2b8df927ac23cfa99016a684179f2a3198ba2e (patch)
tree1d13b575bc7c4f7279b2ff3fdde175a7522d643a /ops/optimizer.rs
parent075854e5162c3d9f4fd7061d19acbe2c5855536e (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.rs90
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),
}
}