mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 09:31:22 -05:00
perf(ext/web): Add fast path for non-streaming TextDecoder (#14217)
Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com>
This commit is contained in:
parent
8879244f72
commit
e58f77e431
4 changed files with 134 additions and 11 deletions
|
@ -95,16 +95,6 @@
|
|||
context: "Argument 2",
|
||||
});
|
||||
|
||||
// TODO(lucacasonato): add fast path for non-streaming decoder & decode
|
||||
|
||||
if (this.#rid === null) {
|
||||
this.#rid = core.opSync("op_encoding_new_decoder", {
|
||||
label: this.#encoding,
|
||||
fatal: this.#fatal,
|
||||
ignoreBom: this.#ignoreBOM,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
if (ArrayBufferIsView(input)) {
|
||||
|
@ -132,12 +122,28 @@
|
|||
// with a TypedArray argument copies the data.
|
||||
input = new Uint8Array(input);
|
||||
}
|
||||
|
||||
if (!options.stream && this.#rid === null) {
|
||||
return core.opSync("op_encoding_decode_single", input, {
|
||||
label: this.#encoding,
|
||||
fatal: this.#fatal,
|
||||
ignoreBom: this.#ignoreBOM,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.#rid === null) {
|
||||
this.#rid = core.opSync("op_encoding_new_decoder", {
|
||||
label: this.#encoding,
|
||||
fatal: this.#fatal,
|
||||
ignoreBom: this.#ignoreBOM,
|
||||
});
|
||||
}
|
||||
return core.opSync("op_encoding_decode", input, {
|
||||
rid: this.#rid,
|
||||
stream: options.stream,
|
||||
});
|
||||
} finally {
|
||||
if (!options.stream) {
|
||||
if (!options.stream && this.#rid) {
|
||||
core.close(this.#rid);
|
||||
this.#rid = null;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,10 @@ deno_bench_util = { version = "0.46.0", path = "../../bench_util" }
|
|||
deno_url = { version = "0.52.0", path = "../url" }
|
||||
deno_webidl = { version = "0.52.0", path = "../webidl" }
|
||||
|
||||
[[bench]]
|
||||
name = "encoding"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "timers_ops"
|
||||
harness = false
|
||||
|
|
54
ext/web/benches/encoding.rs
Normal file
54
ext/web/benches/encoding.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use deno_core::Extension;
|
||||
|
||||
use deno_bench_util::bench_js_sync;
|
||||
use deno_bench_util::bench_or_profile;
|
||||
use deno_bench_util::bencher::{benchmark_group, Bencher};
|
||||
use deno_web::BlobStore;
|
||||
|
||||
struct Permissions;
|
||||
|
||||
impl deno_web::TimersPermission for Permissions {
|
||||
fn allow_hrtime(&mut self) -> bool {
|
||||
false
|
||||
}
|
||||
fn check_unstable(
|
||||
&self,
|
||||
_state: &deno_core::OpState,
|
||||
_api_name: &'static str,
|
||||
) {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
fn setup() -> Vec<Extension> {
|
||||
vec![
|
||||
deno_webidl::init(),
|
||||
deno_url::init(),
|
||||
deno_web::init::<Permissions>(BlobStore::default(), None),
|
||||
Extension::builder()
|
||||
.js(vec![(
|
||||
"setup",
|
||||
Box::new(|| {
|
||||
Ok(
|
||||
r#"
|
||||
const { TextDecoder } = globalThis.__bootstrap.encoding;
|
||||
const hello12k = Deno.core.encode("hello world\n".repeat(1e3));
|
||||
"#
|
||||
.to_owned(),
|
||||
)
|
||||
}),
|
||||
)])
|
||||
.state(|state| {
|
||||
state.put(Permissions {});
|
||||
Ok(())
|
||||
})
|
||||
.build(),
|
||||
]
|
||||
}
|
||||
|
||||
fn bench_encode_12kb(b: &mut Bencher) {
|
||||
bench_js_sync(b, r#"new TextDecoder().decode(hello12k);"#, setup);
|
||||
}
|
||||
|
||||
benchmark_group!(benches, bench_encode_12kb);
|
||||
bench_or_profile!(benches);
|
|
@ -90,6 +90,7 @@ pub fn init<P: TimersPermission + 'static>(
|
|||
op_base64_atob::decl(),
|
||||
op_base64_btoa::decl(),
|
||||
op_encoding_normalize_label::decl(),
|
||||
op_encoding_decode_single::decl(),
|
||||
op_encoding_new_decoder::decl(),
|
||||
op_encoding_decode::decl(),
|
||||
op_encoding_encode_into::decl(),
|
||||
|
@ -215,6 +216,64 @@ fn op_encoding_normalize_label(label: String) -> Result<String, AnyError> {
|
|||
Ok(encoding.name().to_lowercase())
|
||||
}
|
||||
|
||||
#[op]
|
||||
fn op_encoding_decode_single(
|
||||
data: ZeroCopyBuf,
|
||||
options: DecoderOptions,
|
||||
) -> Result<U16String, AnyError> {
|
||||
let DecoderOptions {
|
||||
label,
|
||||
ignore_bom,
|
||||
fatal,
|
||||
} = options;
|
||||
|
||||
let encoding = Encoding::for_label(label.as_bytes()).ok_or_else(|| {
|
||||
range_error(format!(
|
||||
"The encoding label provided ('{}') is invalid.",
|
||||
label
|
||||
))
|
||||
})?;
|
||||
|
||||
let mut decoder = if ignore_bom {
|
||||
encoding.new_decoder_without_bom_handling()
|
||||
} else {
|
||||
encoding.new_decoder_with_bom_removal()
|
||||
};
|
||||
|
||||
let max_buffer_length = decoder
|
||||
.max_utf16_buffer_length(data.len())
|
||||
.ok_or_else(|| range_error("Value too large to decode."))?;
|
||||
|
||||
let mut output = vec![0; max_buffer_length];
|
||||
|
||||
if fatal {
|
||||
let (result, _, written) =
|
||||
decoder.decode_to_utf16_without_replacement(&data, &mut output, true);
|
||||
match result {
|
||||
DecoderResult::InputEmpty => {
|
||||
output.truncate(written);
|
||||
Ok(output.into())
|
||||
}
|
||||
DecoderResult::OutputFull => {
|
||||
Err(range_error("Provided buffer too small."))
|
||||
}
|
||||
DecoderResult::Malformed(_, _) => {
|
||||
Err(type_error("The encoded data is not valid."))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let (result, _, written, _) =
|
||||
decoder.decode_to_utf16(&data, &mut output, true);
|
||||
match result {
|
||||
CoderResult::InputEmpty => {
|
||||
output.truncate(written);
|
||||
Ok(output.into())
|
||||
}
|
||||
CoderResult::OutputFull => Err(range_error("Provided buffer too small.")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[op]
|
||||
fn op_encoding_new_decoder(
|
||||
state: &mut OpState,
|
||||
|
|
Loading…
Add table
Reference in a new issue