Repository: denoland/deno_core
Pull request #43 (2023-07-18 19:51:30)

feat(ops): Benchmark sync ops, support for Option<numeric>, faster strings
Approximately 25% faster strings from `op` -> `op2`.




Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 3c1cb88..543f0be 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -292,6 +292,7 @@ name = "deno_core"
 version = "0.195.0"
 dependencies = [
  "anyhow",
+ "bencher",
  "bytes",
  "cooked-waker",
  "deno_ast",
diff --git a/core/Cargo.toml b/core/Cargo.toml
index de54cfa..e89ef11 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -17,6 +17,7 @@ path = "lib.rs"
 default = ["v8_use_custom_libcxx"]
 v8_use_custom_libcxx = ["v8/use_custom_libcxx"]
 include_js_files_for_snapshotting = []
+unsafe_runtime_options = []
 
 [dependencies]
 anyhow.workspace = true
@@ -48,3 +49,10 @@ path = "examples/http_bench_json_ops/main.rs"
 [dev-dependencies]
 cooked-waker = "5"
 deno_ast.workspace = true
+bencher.workspace = true
+
+[[bench]]
+name = "ops_sync"
+path = "benches/ops/sync.rs"
+harness = false
+required-features = ["unsafe_runtime_options"]
diff --git a/core/benches/ops/sync.rs b/core/benches/ops/sync.rs
new file mode 100644
index 0000000..82a16fd
--- /dev/null
+++ b/core/benches/ops/sync.rs
@@ -0,0 +1,275 @@
+use bencher::*;
+use deno_core::error::generic_error;
+use deno_core::*;
+
+deno_core::extension!(
+  testing,
+  ops = [
+    op_void,
+    op_u32,
+    op_option_u32,
+    op_string,
+    op_string_old,
+    op_string_option_u32,
+  ],
+  state = |state| {
+    state.put(1234u32);
+    state.put(10000u16);
+  }
+);
+
+#[op2(fast)]
+pub fn op_void() {}
+
+#[op2(fast)]
+pub fn op_u32() -> u32 {
+  1
+}
+
+#[op2]
+pub fn op_option_u32() -> Option<u32> {
+  Some(1)
+}
+
+#[op2(fast)]
+pub fn op_string(#[string] s: &str) -> u32 {
+  s.len() as _
+}
+
+#[op(fast)]
+pub fn op_string_old(s: &str) -> u32 {
+  s.len() as _
+}
+
+#[op2]
+pub fn op_string_option_u32(#[string] s: &str) -> Option<u32> {
+  Some(s.len() as _)
+}
+
+fn bench_op(
+  b: &mut Bencher,
+  count: usize,
+  op: &str,
+  arg_count: usize,
+  call: &str,
+) {
+  #[cfg(not(feature = "unsafe_runtime_options"))]
+  unreachable!(
+    "This benchmark must be run with --features=unsafe_runtime_options"
+  );
+
+  let mut runtime = JsRuntime::new(RuntimeOptions {
+    extensions: vec![testing::init_ops_and_esm()],
+    // We need to feature gate this here to prevent IDE errors
+    #[cfg(feature = "unsafe_runtime_options")]
+    unsafe_expose_natives_and_gc: true,
+    ..Default::default()
+  });
+  let err_mapper =
+    |err| generic_error(format!("{op} test failed ({call}): {err:?}"));
+
+  let args = (0..arg_count)
+    .map(|n| format!("arg{n}"))
+    .collect::<Vec<_>>()
+    .join(", ");
+
+  // Prime the optimizer
+  runtime
+    .execute_script(
+      "",
+      FastString::Owned(
+        format!(
+          r"
+const LARGE_STRING_1000000 = '*'.repeat(1000000);
+const LARGE_STRING_1000 = '*'.repeat(1000);
+const LARGE_STRING_UTF8_1000000 = '\u1000'.repeat(1000000);
+const LARGE_STRING_UTF8_1000 = '\u1000'.repeat(1000);
+const {{ {op}: op }} = Deno.core.ensureFastOps();
+function {op}({args}) {{
+  op({args});
+}}
+let accum = 0;
+let __index__ = 0;
+%PrepareFunctionForOptimization({op});
+{call};
+%OptimizeFunctionOnNextCall({op});
+{call};
+
+function bench() {{
+  let accum = 0;
+  for (let __index__ = 0; __index__ < {count}; __index__++) {{ {call} }}
+  return accum;
+}}
+%PrepareFunctionForOptimization(bench);
+bench();
+%OptimizeFunctionOnNextCall(bench);
+bench();
+        "
+        )
+        .into(),
+      ),
+    )
+    .map_err(err_mapper)
+    .unwrap();
+  let bench = runtime.execute_script("", ascii_str!("bench")).unwrap();
+  let mut scope = runtime.handle_scope();
+  let bench: v8::Local<v8::Function> =
+    v8::Local::new(&mut scope, bench).try_into().unwrap();
+  b.iter(|| {
+    let recv = v8::undefined(&mut scope).try_into().unwrap();
+    bench.call(&mut scope, recv, &[]);
+  });
+}
+
+const BENCH_COUNT: usize = 1000;
+const LARGE_BENCH_COUNT: usize = 10;
+
+/// Tests the overhead of execute_script.
+fn baseline(b: &mut Bencher) {
+  bench_op(b, BENCH_COUNT, "op_void", 0, "accum += __index__;");
+}
+
+/// A void function with no return value.
+fn bench_op_void(b: &mut Bencher) {
+  bench_op(b, BENCH_COUNT, "op_void", 0, "op_void()");
+}
+
+/// A function with a numeric return value.
+fn bench_op_u32(b: &mut Bencher) {
+  bench_op(b, BENCH_COUNT, "op_u32", 0, "accum += op_u32();");
+}
+
+/// A function with an optional return value (making it non-fast).
+fn bench_op_option_u32(b: &mut Bencher) {
+  bench_op(
+    b,
+    BENCH_COUNT,
+    "op_option_u32",
+    0,
+    "accum += op_option_u32();",
+  );
+}
+
+/// A string function with a numeric return value.
+fn bench_op_string(b: &mut Bencher) {
+  bench_op(b, BENCH_COUNT, "op_string", 1, "accum += op_string('this is a reasonably long string that we would like to get the length of!');");
+}
+
+/// A string function with a numeric return value.
+fn bench_op_string_large_1000(b: &mut Bencher) {
+  bench_op(
+    b,
+    BENCH_COUNT,
+    "op_string",
+    1,
+    "accum += op_string(LARGE_STRING_1000);",
+  );
+}
+
+/// A string function with a numeric return value.
+fn bench_op_string_large_1000000(b: &mut Bencher) {
+  bench_op(
+    b,
+    LARGE_BENCH_COUNT,
+    "op_string",
+    1,
+    "accum += op_string(LARGE_STRING_1000000);",
+  );
+}
+
+/// A string function with a numeric return value.
+fn bench_op_string_large_utf8_1000(b: &mut Bencher) {
+  bench_op(
+    b,
+    BENCH_COUNT,
+    "op_string",
+    1,
+    "accum += op_string(LARGE_STRING_UTF8_1000);",
+  );
+}
+
+/// A string function with a numeric return value.
+fn bench_op_string_large_utf8_1000000(b: &mut Bencher) {
+  bench_op(
+    b,
+    LARGE_BENCH_COUNT,
+    "op_string",
+    1,
+    "accum += op_string(LARGE_STRING_UTF8_1000000);",
+  );
+}
+
+/// A string function with a numeric return value.
+fn bench_op_string_old(b: &mut Bencher) {
+  bench_op(b, BENCH_COUNT, "op_string_old", 1, "accum += op_string_old('this is a reasonably long string that we would like to get the length of!');");
+}
+
+/// A string function with a numeric return value.
+fn bench_op_string_old_large_1000(b: &mut Bencher) {
+  bench_op(
+    b,
+    BENCH_COUNT,
+    "op_string_old",
+    1,
+    "accum += op_string_old(LARGE_STRING_1000);",
+  );
+}
+
+/// A string function with a numeric return value.
+fn bench_op_string_old_large_1000000(b: &mut Bencher) {
+  bench_op(
+    b,
+    LARGE_BENCH_COUNT,
+    "op_string_old",
+    1,
+    "accum += op_string_old(LARGE_STRING_1000000);",
+  );
+}
+
+/// A string function with a numeric return value.
+fn bench_op_string_old_large_utf8_1000(b: &mut Bencher) {
+  bench_op(
+    b,
+    BENCH_COUNT,
+    "op_string_old",
+    1,
+    "accum += op_string_old(LARGE_STRING_UTF8_1000);",
+  );
+}
+
+/// A string function with a numeric return value.
+fn bench_op_string_old_large_utf8_1000000(b: &mut Bencher) {
+  bench_op(
+    b,
+    LARGE_BENCH_COUNT,
+    "op_string_old",
+    1,
+    "accum += op_string_old(LARGE_STRING_UTF8_1000000);",
+  );
+}
+
+/// A string function with an option numeric return value.
+fn bench_op_string_option_u32(b: &mut Bencher) {
+  bench_op(b, BENCH_COUNT, "op_string_option_u32", 1, "accum += op_string_option_u32('this is a reasonably long string that we would like to get the length of!');");
+}
+
+benchmark_group!(
+  benches,
+  baseline,
+  bench_op_void,
+  bench_op_u32,
+  bench_op_option_u32,
+  bench_op_string,
+  bench_op_string_large_1000,
+  bench_op_string_large_1000000,
+  bench_op_string_large_utf8_1000,
+  bench_op_string_large_utf8_1000000,
+  bench_op_string_old,
+  bench_op_string_old_large_1000,
+  bench_op_string_old_large_1000000,
+  bench_op_string_old_large_utf8_1000,
+  bench_op_string_old_large_utf8_1000000,
+  bench_op_string_option_u32,
+);
+
+benchmark_main!(benches);
diff --git a/core/runtime/jsruntime.rs b/core/runtime/jsruntime.rs
index 30ae136..a1ec424 100644
--- a/core/runtime/jsruntime.rs
+++ b/core/runtime/jsruntime.rs
@@ -350,6 +350,7 @@ impl JsRuntimeState {
 fn v8_init(
   v8_platform: Option<v8::SharedRef<v8::Platform>>,
   predictable: bool,
+  expose_natives: bool,
 ) {
   // Include 10MB ICU data file.
   #[repr(C, align(16))]
@@ -357,22 +358,26 @@ fn v8_init(
   static ICU_DATA: IcuData = IcuData(*include_bytes!("icudtl.dat"));
   v8::icu::set_common_data_72(&ICU_DATA.0).unwrap();
 
-  let flags = concat!(
+  let base_flags = concat!(
     " --wasm-test-streaming",
     " --harmony-import-assertions",
     " --no-validate-asm",
     " --turbo_fast_api_calls",
     " --harmony-change-array-by-copy",
   );
-
-  if predictable {
-    v8::V8::set_flags_from_string(&format!(
-      "{}{}",
-      flags, " --predictable --random-seed=42"
-    ));
-  } else {
-    v8::V8::set_flags_from_string(flags);
-  }
+  let predictable_flags = "--predictable --random-seed=42";
+  let expose_natives_flags = "--expose_gc --allow_natives_syntax";
+
+  #[allow(clippy::useless_format)]
+  let flags = match (predictable, expose_natives) {
+    (false, false) => format!("{base_flags}"),
+    (true, false) => format!("{base_flags} {predictable_flags}"),
+    (false, true) => format!("{base_flags} {expose_natives_flags}"),
+    (true, true) => {
+      format!("{base_flags} {predictable_flags} {expose_natives_flags}")
+    }
+  };
+  v8::V8::set_flags_from_string(&flags);
 
   let v8_platform = v8_platform
     .unwrap_or_else(|| v8::new_default_platform(0, false).make_shared());
@@ -441,6 +446,24 @@ pub struct RuntimeOptions {
   /// Describe if this is the main runtime instance, used by debuggers in some
   /// situation - like disconnecting when program finishes running.
   pub is_main: bool,
+
+  #[cfg(any(test, feature = "unsafe_runtime_options"))]
+  /// Should this isolate expose the v8 natives (eg: %OptimizeFunctionOnNextCall) and
+  /// GC control functions (`gc()`)? WARNING: This should not be used for production code as
+  /// this may expose the runtime to security vulnerabilities.
+  pub unsafe_expose_natives_and_gc: bool,
+}
+
+impl RuntimeOptions {
+  #[cfg(any(test, feature = "unsafe_runtime_options"))]
+  fn unsafe_expose_natives_and_gc(&self) -> bool {
+    self.unsafe_expose_natives_and_gc
+  }
+
+  #[cfg(not(any(test, feature = "unsafe_runtime_options")))]
+  fn unsafe_expose_natives_and_gc(&self) -> bool {
+    false
+  }
 }
 
 #[derive(Default)]
@@ -464,7 +487,11 @@ pub struct CreateRealmOptions {
 impl JsRuntime {
   /// Only constructor, configuration is done through `options`.
   pub fn new(mut options: RuntimeOptions) -> JsRuntime {
-    JsRuntime::init_v8(options.v8_platform.take(), cfg!(test));
+    JsRuntime::init_v8(
+      options.v8_platform.take(),
+      cfg!(test),
+      options.unsafe_expose_natives_and_gc(),
+    );
     JsRuntime::new_inner(options, false, None)
   }
 
@@ -517,6 +544,7 @@ impl JsRuntime {
   fn init_v8(
     v8_platform: Option<v8::SharedRef<v8::Platform>>,
     predictable: bool,
+    expose_natives: bool,
   ) {
     static DENO_INIT: Once = Once::new();
     static DENO_PREDICTABLE: AtomicBool = AtomicBool::new(false);
@@ -529,7 +557,8 @@ impl JsRuntime {
       DENO_PREDICTABLE.store(predictable, Ordering::SeqCst);
     }
 
-    DENO_INIT.call_once(move || v8_init(v8_platform, predictable));
+    DENO_INIT
+      .call_once(move || v8_init(v8_platform, predictable, expose_natives));
   }
 
   fn new_inner(
@@ -1571,7 +1600,11 @@ impl JsRuntimeForSnapshot {
     mut options: RuntimeOptions,
     runtime_snapshot_options: RuntimeSnapshotOptions,
   ) -> JsRuntimeForSnapshot {
-    JsRuntime::init_v8(options.v8_platform.take(), true);
+    JsRuntime::init_v8(
+      options.v8_platform.take(),
+      true,
+      options.unsafe_expose_natives_and_gc(),
+    );
     JsRuntimeForSnapshot(JsRuntime::new_inner(
       options,
       true,
diff --git a/core/runtime/ops.rs b/core/runtime/ops.rs
index 9035ce4..2d6797a 100644
--- a/core/runtime/ops.rs
+++ b/core/runtime/ops.rs
@@ -19,6 +19,11 @@ use std::option::Option;
 use std::task::Context;
 use std::task::Poll;
 
+/// The default string buffer size on the stack that prevents mallocs in some
+/// string functions. Keep in mind that Windows only offers 1MB stacks by default,
+/// so this is a limited resource!
+pub const STRING_STACK_BUFFER_SIZE: usize = 1024 * 8;
+
 #[inline]
 pub fn queue_fast_async_op<R: serde::Serialize + 'static>(
   ctx: &OpCtx,
@@ -332,10 +337,17 @@ unsafe fn latin1_to_utf8(
 /// Converts a [`v8::fast_api::FastApiOneByteString`] to either an owned string, or a borrowed string, depending on whether it fits into the
 /// provided buffer.
 pub fn to_str_ptr<'a, const N: usize>(
-  string: &mut v8::fast_api::FastApiOneByteString,
+  string: &'a mut v8::fast_api::FastApiOneByteString,
   buffer: &'a mut [MaybeUninit<u8>; N],
 ) -> Cow<'a, str> {
   let input_buf = string.as_bytes();
+
+  // Per benchmarking results, it's faster to do this check than to copy latin-1 -> utf8
+  if input_buf.is_ascii() {
+    // SAFETY: We just checked that it was ASCII
+    return Cow::Borrowed(unsafe { std::str::from_utf8_unchecked(input_buf) });
+  }
+
   let input_len = input_buf.len();
   let output_len = buffer.len();
 
@@ -362,9 +374,7 @@ pub fn to_str_ptr<'a, const N: usize>(
 
 /// Converts a [`v8::fast_api::FastApiOneByteString`] to an owned string. May over-allocate to avoid
 /// re-allocation.
-pub fn to_string_ptr(
-  string: &mut v8::fast_api::FastApiOneByteString,
-) -> String {
+pub fn to_string_ptr(string: &v8::fast_api::FastApiOneByteString) -> String {
   let input_buf = string.as_bytes();
   let capacity = input_buf.len() * 2;
 
@@ -902,6 +912,12 @@ mod tests {
         // Latin-1 (one byte but two UTF-8 chars)
         (2, "'\\u00a0'"),
         // ASCII
+        (1000, "'a'.repeat(1000)"),
+        // Latin-1
+        (2000, "'\\u00a0'.repeat(1000)"),
+        // 4-byte UTF-8 emoji (1F995 = 🦕)
+        (4000, "'\\u{1F995}'.repeat(1000)"),
+        // ASCII
         (10000, "'a'.repeat(10000)"),
         // Latin-1
         (20000, "'\\u00a0'.repeat(10000)"),
diff --git a/ops/op2/dispatch_fast.rs b/ops/op2/dispatch_fast.rs
index 2722ab2..e2a502e 100644
--- a/ops/op2/dispatch_fast.rs
+++ b/ops/op2/dispatch_fast.rs
@@ -358,7 +358,7 @@ fn map_v8_fastcall_arg_to_arg(
     }
     Arg::Special(Special::RefStr) => {
       quote! {
-        let mut #arg_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
+        let mut #arg_temp: [::std::mem::MaybeUninit<u8>; #deno_core::_ops::STRING_STACK_BUFFER_SIZE] = [::std::mem::MaybeUninit::uninit(); #deno_core::_ops::STRING_STACK_BUFFER_SIZE];
         let #arg_ident = &#deno_core::_ops::to_str_ptr(unsafe { &mut *#arg_ident }, &mut #arg_temp);
       }
     }
@@ -367,7 +367,7 @@ fn map_v8_fastcall_arg_to_arg(
     }
     Arg::Special(Special::CowStr) => {
       quote! {
-        let mut #arg_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
+        let mut #arg_temp: [::std::mem::MaybeUninit<u8>; #deno_core::_ops::STRING_STACK_BUFFER_SIZE] = [::std::mem::MaybeUninit::uninit(); #deno_core::_ops::STRING_STACK_BUFFER_SIZE];
         let #arg_ident = #deno_core::_ops::to_str_ptr(unsafe { &mut *#arg_ident }, &mut #arg_temp);
       }
     }
diff --git a/ops/op2/dispatch_slow.rs b/ops/op2/dispatch_slow.rs
index 24f5d32..7176d4d 100644
--- a/ops/op2/dispatch_slow.rs
+++ b/ops/op2/dispatch_slow.rs
@@ -272,16 +272,16 @@ pub fn from_arg(
     Arg::Special(Special::RefStr) => {
       *needs_scope = true;
       quote! {
-        // Trade 1024 bytes of stack space for potentially non-allocating strings
-        let mut #arg_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
+        // Trade stack space for potentially non-allocating strings
+        let mut #arg_temp: [::std::mem::MaybeUninit<u8>; #deno_core::_ops::STRING_STACK_BUFFER_SIZE] = [::std::mem::MaybeUninit::uninit(); #deno_core::_ops::STRING_STACK_BUFFER_SIZE];
         let #arg_ident = &#deno_core::_ops::to_str(&mut #scope, &#arg_ident, &mut #arg_temp);
       }
     }
     Arg::Special(Special::CowStr) => {
       *needs_scope = true;
       quote! {
-        // Trade 1024 bytes of stack space for potentially non-allocating strings
-        let mut #arg_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
+        // Trade stack space for potentially non-allocating strings
+        let mut #arg_temp: [::std::mem::MaybeUninit<u8>; #deno_core::_ops::STRING_STACK_BUFFER_SIZE] = [::std::mem::MaybeUninit::uninit(); #deno_core::_ops::STRING_STACK_BUFFER_SIZE];
         let #arg_ident = #deno_core::_ops::to_str(&mut #scope, &#arg_ident, &mut #arg_temp);
       }
     }
@@ -519,6 +519,20 @@ pub fn return_value_infallible(
         }
       }
     }
+    Arg::OptionNumeric(n) => {
+      *needs_retval = true;
+      *needs_scope = true;
+      // End the generator_state borrow
+      let (result, retval) = (result.clone(), retval.clone());
+      let some = return_value_infallible(generator_state, &Arg::Numeric(*n))?;
+      quote! {
+        if let Some(#result) = #result {
+          #some
+        } else {
+          #retval.set_null();
+        }
+      }
+    }
     Arg::Option(Special::String) => {
       *needs_retval = true;
       *needs_scope = true;


Test patch:
diff --git a/ops/op2/test_cases/sync/string_cow.out b/ops/op2/test_cases/sync/string_cow.out
index 7df29c5..58e4c9a 100644
--- a/ops/op2/test_cases/sync/string_cow.out
+++ b/ops/op2/test_cases/sync/string_cow.out
@@ -34,7 +34,9 @@ impl op_string_cow {
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: *mut deno_core::v8::fast_api::FastApiOneByteString,
     ) -> u32 {
-        let mut arg0_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
+        let mut arg0_temp: [::std::mem::MaybeUninit<
+            u8,
+        >; deno_core::_ops::STRING_STACK_BUFFER_SIZE] = [::std::mem::MaybeUninit::uninit(); deno_core::_ops::STRING_STACK_BUFFER_SIZE];
         let arg0 = deno_core::_ops::to_str_ptr(unsafe { &mut *arg0 }, &mut arg0_temp);
         let result = Self::call(arg0);
         result
@@ -48,7 +50,9 @@ impl op_string_cow {
             &*info
         });
         let arg0 = args.get(0usize as i32);
-        let mut arg0_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
+        let mut arg0_temp: [::std::mem::MaybeUninit<
+            u8,
+        >; deno_core::_ops::STRING_STACK_BUFFER_SIZE] = [::std::mem::MaybeUninit::uninit(); deno_core::_ops::STRING_STACK_BUFFER_SIZE];
         let arg0 = deno_core::_ops::to_str(&mut scope, &arg0, &mut arg0_temp);
         let result = Self::call(arg0);
         rv.set_uint32(result as u32);
diff --git a/ops/op2/test_cases/sync/string_ref.out b/ops/op2/test_cases/sync/string_ref.out
index a845fa4..35dfb79 100644
--- a/ops/op2/test_cases/sync/string_ref.out
+++ b/ops/op2/test_cases/sync/string_ref.out
@@ -34,7 +34,9 @@ impl op_string_owned {
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: *mut deno_core::v8::fast_api::FastApiOneByteString,
     ) -> u32 {
-        let mut arg0_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
+        let mut arg0_temp: [::std::mem::MaybeUninit<
+            u8,
+        >; deno_core::_ops::STRING_STACK_BUFFER_SIZE] = [::std::mem::MaybeUninit::uninit(); deno_core::_ops::STRING_STACK_BUFFER_SIZE];
         let arg0 = &deno_core::_ops::to_str_ptr(unsafe { &mut *arg0 }, &mut arg0_temp);
         let result = Self::call(arg0);
         result
@@ -48,7 +50,9 @@ impl op_string_owned {
             &*info
         });
         let arg0 = args.get(0usize as i32);
-        let mut arg0_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
+        let mut arg0_temp: [::std::mem::MaybeUninit<
+            u8,
+        >; deno_core::_ops::STRING_STACK_BUFFER_SIZE] = [::std::mem::MaybeUninit::uninit(); deno_core::_ops::STRING_STACK_BUFFER_SIZE];
         let arg0 = &deno_core::_ops::to_str(&mut scope, &arg0, &mut arg0_temp);
         let result = Self::call(arg0);
         rv.set_uint32(result as u32);