Skip to content

Commit 9b2b8df

Browse files
authored
feat(ops): Fast zero copy string arguments (denoland#16777)
Uses SeqOneByteString optimization to do zero-copy `&str` arguments in fast calls. - [x] Depends on denoland/rusty_v8#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 } ```
1 parent 075854e commit 9b2b8df

34 files changed

+805
-98
lines changed

cli/bench/console.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
11
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
22
const count = 100000;
3-
4-
const start = Date.now();
53
for (let i = 0; i < count; i++) console.log("Hello World");
6-
const elapsed = Date.now() - start;
7-
const rate = Math.floor(count / (elapsed / 1000));
8-
console.log(`time ${elapsed} ms rate ${rate}`);

cli/bench/encode_into.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
2-
const queueMicrotask = globalThis.queueMicrotask || process.nextTick;
32
let [total, count] = typeof Deno !== "undefined"
43
? Deno.args
54
: [process.argv[2], process.argv[3]];
65

76
total = total ? parseInt(total, 0) : 50;
8-
count = count ? parseInt(count, 10) : 1000000;
7+
count = count ? parseInt(count, 10) : 10000000;
98

109
function bench(fun) {
1110
const start = Date.now();
1211
for (let i = 0; i < count; i++) fun();
1312
const elapsed = Date.now() - start;
1413
const rate = Math.floor(count / (elapsed / 1000));
1514
console.log(`time ${elapsed} ms rate ${rate}`);
16-
if (--total) queueMicrotask(() => bench(fun));
15+
if (--total) bench(fun);
1716
}
1817

1918
const encoder = new TextEncoder();

cli/bench/webstorage.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
2+
3+
// Note: when benchmarking across different Deno version, make sure to clear
4+
// the DENO_DIR cache.
5+
let [total, count] = typeof Deno !== "undefined" ? Deno.args : [];
6+
7+
total = total ? parseInt(total, 0) : 50;
8+
count = count ? parseInt(count, 10) : 1000000;
9+
10+
function bench(fun) {
11+
const start = Date.now();
12+
for (let i = 0; i < count; i++) fun(i);
13+
const elapsed = Date.now() - start;
14+
const rate = Math.floor(count / (elapsed / 1000));
15+
console.log(`time ${elapsed} ms rate ${rate}`);
16+
if (--total) queueMicrotask(() => bench(fun));
17+
}
18+
19+
localStorage.clear();
20+
localStorage.setItem("foo", "bar");
21+
bench(() => localStorage.getItem("foo"));

cli/tsc/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -683,9 +683,9 @@ pub fn resolve_npm_package_reference_types(
683683
}
684684

685685
#[op]
686-
fn op_is_node_file(state: &mut OpState, path: String) -> bool {
686+
fn op_is_node_file(state: &mut OpState, path: &str) -> bool {
687687
let state = state.borrow::<State>();
688-
match ModuleSpecifier::parse(&path) {
688+
match ModuleSpecifier::parse(path) {
689689
Ok(specifier) => state
690690
.maybe_npm_resolver
691691
.as_ref()

core/ops_builtin.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ pub fn op_metrics(state: &mut OpState) -> (OpMetrics, Vec<OpMetrics>) {
107107

108108
/// Builtin utility to print to stdout/stderr
109109
#[op]
110-
pub fn op_print(msg: String, is_err: bool) -> Result<(), Error> {
110+
pub fn op_print(msg: &str, is_err: bool) -> Result<(), Error> {
111111
if is_err {
112112
stderr().write_all(msg.as_bytes())?;
113113
stderr().flush().unwrap();
@@ -152,12 +152,12 @@ pub fn op_wasm_streaming_feed(
152152
pub fn op_wasm_streaming_set_url(
153153
state: &mut OpState,
154154
rid: ResourceId,
155-
url: String,
155+
url: &str,
156156
) -> Result<(), Error> {
157157
let wasm_streaming =
158158
state.resource_table.get::<WasmStreamingResource>(rid)?;
159159

160-
wasm_streaming.0.borrow_mut().set_url(&url);
160+
wasm_streaming.0.borrow_mut().set_url(url);
161161

162162
Ok(())
163163
}

ext/node/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ fn op_require_proxy_path(filename: String) -> String {
262262
}
263263

264264
#[op]
265-
fn op_require_is_request_relative(request: String) -> bool {
265+
fn op_require_is_request_relative(request: &str) -> bool {
266266
if request.starts_with("./") || request.starts_with("../") || request == ".."
267267
{
268268
return true;

ext/url/00_url.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@
5656
function opUrlParse(href, maybeBase) {
5757
let status;
5858
if (maybeBase === undefined) {
59-
status = ops.op_url_parse(href, componentsBuf.buffer);
59+
status = ops.op_url_parse(href, componentsBuf);
6060
} else {
61-
status = core.ops.op_url_parse_with_base(
61+
status = ops.op_url_parse_with_base(
6262
href,
6363
maybeBase,
64-
componentsBuf.buffer,
64+
componentsBuf,
6565
);
6666
}
6767
return getSerialization(status, href);
@@ -71,7 +71,7 @@
7171
if (status === 0) {
7272
return href;
7373
} else if (status === 1) {
74-
return core.ops.op_url_get_serialization();
74+
return ops.op_url_get_serialization();
7575
} else {
7676
throw new TypeError("Invalid URL");
7777
}

ext/url/lib.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ pub fn init() -> Extension {
4141
#[op]
4242
pub fn op_url_parse_with_base(
4343
state: &mut OpState,
44-
href: String,
45-
base_href: String,
46-
buf: &mut [u8],
44+
href: &str,
45+
base_href: &str,
46+
buf: &mut [u32],
4747
) -> u32 {
48-
let base_url = match Url::parse(&base_href) {
48+
let base_url = match Url::parse(base_href) {
4949
Ok(url) => url,
5050
Err(_) => return ParseStatus::Err as u32,
5151
};
@@ -67,8 +67,8 @@ pub fn op_url_get_serialization(state: &mut OpState) -> String {
6767
}
6868

6969
/// Parse `href` without a `base_url`. Fills the out `buf` with URL components.
70-
#[op]
71-
pub fn op_url_parse(state: &mut OpState, href: String, buf: &mut [u8]) -> u32 {
70+
#[op(fast)]
71+
pub fn op_url_parse(state: &mut OpState, href: &str, buf: &mut [u32]) -> u32 {
7272
parse_url(state, href, None, buf)
7373
}
7474

@@ -99,15 +99,14 @@ pub fn op_url_parse(state: &mut OpState, href: String, buf: &mut [u8]) -> u32 {
9999
#[inline]
100100
fn parse_url(
101101
state: &mut OpState,
102-
href: String,
102+
href: &str,
103103
base_href: Option<&Url>,
104-
buf: &mut [u8],
104+
buf: &mut [u32],
105105
) -> u32 {
106-
match Url::options().base_url(base_href).parse(&href) {
106+
match Url::options().base_url(base_href).parse(href) {
107107
Ok(url) => {
108108
let inner_url = quirks::internal_components(&url);
109109

110-
let buf: &mut [u32] = as_u32_slice(buf);
111110
buf[0] = inner_url.scheme_end;
112111
buf[1] = inner_url.username_end;
113112
buf[2] = inner_url.host_start;

ext/web/blob.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,9 @@ pub fn op_blob_create_object_url(
252252
#[op]
253253
pub fn op_blob_revoke_object_url(
254254
state: &mut deno_core::OpState,
255-
url: String,
255+
url: &str,
256256
) -> Result<(), AnyError> {
257-
let url = Url::parse(&url)?;
257+
let url = Url::parse(url)?;
258258
let blob_store = state.borrow::<BlobStore>();
259259
blob_store.remove_object_url(&url);
260260
Ok(())

ext/web/compression.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ impl Resource for CompressionResource {
4141
#[op]
4242
pub fn op_compression_new(
4343
state: &mut OpState,
44-
format: String,
44+
format: &str,
4545
is_decoder: bool,
4646
) -> ResourceId {
4747
let w = Vec::new();
48-
let inner = match (format.as_str(), is_decoder) {
48+
let inner = match (format, is_decoder) {
4949
("deflate", true) => Inner::DeflateDecoder(ZlibDecoder::new(w)),
5050
("deflate", false) => {
5151
Inner::DeflateEncoder(ZlibEncoder::new(w, Compression::default()))

0 commit comments

Comments
 (0)