Repository: denoland/deno_core
Pull request #323 (2023-11-09 20:56:58)

feat(core): speedier async stubs + template opAsync
Adds a new template system for op async dispatch generation, and starts generating opAsync from it as well so we can play with performance more easily.

First pass at optimization: 5% improvement in async dispatch by avoiding allocation of promise IDs and generally doing less work in the async handlers.

Before:

```
test bench_op_async_void                  ... bench:      80,853 ns/iter (+/- 2,123)
```

After:

```
test bench_op_async_void                  ... bench:      76,799 ns/iter (+/- 1,158)
```



Patch:
diff --git a/core/01_core.js b/core/01_core.js
index d0f6762..2a174ec 100644
--- a/core/01_core.js
+++ b/core/01_core.js
@@ -71,7 +71,7 @@
   registerErrorClass("TypeError", TypeError);
   registerErrorClass("URIError", URIError);
 
-  let nextPromiseId = 0xffffffff;
+  let nextPromiseId = 0;
   const promiseMap = new SafeMap();
   const RING_SIZE = 4 * 1024;
   const NO_PROMISE = null; // Alias to null is faster than plain nulls
@@ -91,17 +91,6 @@
     return opCallTracingEnabled;
   }
 
-  function movePromise(promiseId) {
-    const idx = promiseId % RING_SIZE;
-    // Move old promise from ring to map
-    const oldPromise = promiseRing[idx];
-    if (oldPromise !== NO_PROMISE) {
-      const oldPromiseId = promiseId - RING_SIZE;
-      MapPrototypeSet(promiseMap, oldPromiseId, oldPromise);
-    }
-    return promiseRing[idx] = NO_PROMISE;
-  }
-
   function setPromise(promiseId) {
     const idx = promiseId % RING_SIZE;
     // Move old promise from ring to map
@@ -262,64 +251,6 @@
     };
   }
 
-  function unwrapOpResultNewPromise(id, res, hideFunction) {
-    // .$err_class_name is a special key that should only exist on errors
-    if (res?.$err_class_name) {
-      const className = res.$err_class_name;
-      const errorBuilder = errorMap[className];
-      const err = errorBuilder ? errorBuilder(res.message) : new Error(
-        `Unregistered error class: "${className}"\n  ${res.message}\n  Classes of errors returned from ops should be registered via Deno.core.registerErrorClass().`,
-      );
-      // Set .code if error was a known OS error, see error_codes.rs
-      if (res.code) {
-        err.code = res.code;
-      }
-      // Strip unwrapOpResult() and errorBuilder() calls from stack trace
-      ErrorCaptureStackTrace(err, hideFunction);
-      return PromiseReject(err);
-    }
-    const promise = PromiseResolve(res);
-    promise[promiseIdSymbol] = id;
-    return promise;
-  }
-
-  /*
-Basic codegen.
-
-TODO(mmastrac): automate this (handlebars?)
-
-let s = "";
-const vars = "abcdefghijklm";
-for (let i = 0; i < 10; i++) {
-  let args = "";
-  for (let j = 0; j < i; j++) {
-    args += `${vars[j]},`;
-  }
-  s += `
-      case ${i}:
-        fn = function async_op_${i}(${args}) {
-          const id = (nextPromiseId = (nextPromiseId + 1) & 0xffffffff);
-          try {
-            const maybeResult = originalOp(id, ${args});
-            if (maybeResult !== undefined) {
-              movePromise(id);
-              return unwrapOpResultNewPromise(id, maybeResult, async_op_${i});
-            }
-          } catch (err) {
-            movePromise(id);
-            ErrorCaptureStackTrace(err, async_op_${i});
-            return PromiseReject(err);
-          }
-          let promise = PromisePrototypeThen(setPromise(id), unwrapOpError(eventLoopTick));
-          promise = handleOpCallTracing(opName, id, promise);
-          promise[promiseIdSymbol] = id;
-          return promise;
-        };
-        break;
-  `;
-}
-  */
-
   // This function is called once per async stub
   function asyncStub(opName, args) {
     setUpAsyncStub(opName);
@@ -331,20 +262,21 @@ for (let i = 0; i < 10; i++) {
     let fn;
     // The body of this switch statement can be generated using the script above.
     switch (originalOp.length - 1) {
+      /* BEGIN TEMPLATE setUpAsyncStub */
+      /* DO NOT MODIFY: use rebuild_async_stubs.js to regenerate */
       case 0:
         fn = function async_op_0() {
-          const id = (nextPromiseId = (nextPromiseId + 1) & 0xffffffff);
+          const id = nextPromiseId;
           try {
             const maybeResult = originalOp(id);
             if (maybeResult !== undefined) {
-              movePromise(id);
-              return unwrapOpResultNewPromise(id, maybeResult, async_op_0);
+              return PromiseResolve(maybeResult);
             }
           } catch (err) {
-            movePromise(id);
             ErrorCaptureStackTrace(err, async_op_0);
             return PromiseReject(err);
           }
+          nextPromiseId = (id + 1) & 0xffffffff;
           let promise = PromisePrototypeThen(
             setPromise(id),
             unwrapOpError(eventLoopTick),
@@ -354,21 +286,19 @@ for (let i = 0; i < 10; i++) {
           return promise;
         };
         break;
-
       case 1:
         fn = function async_op_1(a) {
-          const id = (nextPromiseId = (nextPromiseId + 1) & 0xffffffff);
+          const id = nextPromiseId;
           try {
             const maybeResult = originalOp(id, a);
             if (maybeResult !== undefined) {
-              movePromise(id);
-              return unwrapOpResultNewPromise(id, maybeResult, async_op_1);
+              return PromiseResolve(maybeResult);
             }
           } catch (err) {
-            movePromise(id);
             ErrorCaptureStackTrace(err, async_op_1);
             return PromiseReject(err);
           }
+          nextPromiseId = (id + 1) & 0xffffffff;
           let promise = PromisePrototypeThen(
             setPromise(id),
             unwrapOpError(eventLoopTick),
@@ -378,21 +308,19 @@ for (let i = 0; i < 10; i++) {
           return promise;
         };
         break;
-
       case 2:
         fn = function async_op_2(a, b) {
-          const id = (nextPromiseId = (nextPromiseId + 1) & 0xffffffff);
+          const id = nextPromiseId;
           try {
             const maybeResult = originalOp(id, a, b);
             if (maybeResult !== undefined) {
-              movePromise(id);
-              return unwrapOpResultNewPromise(id, maybeResult, async_op_2);
+              return PromiseResolve(maybeResult);
             }
           } catch (err) {
-            movePromise(id);
             ErrorCaptureStackTrace(err, async_op_2);
             return PromiseReject(err);
           }
+          nextPromiseId = (id + 1) & 0xffffffff;
           let promise = PromisePrototypeThen(
             setPromise(id),
             unwrapOpError(eventLoopTick),
@@ -402,21 +330,19 @@ for (let i = 0; i < 10; i++) {
           return promise;
         };
         break;
-
       case 3:
         fn = function async_op_3(a, b, c) {
-          const id = (nextPromiseId = (nextPromiseId + 1) & 0xffffffff);
+          const id = nextPromiseId;
           try {
             const maybeResult = originalOp(id, a, b, c);
             if (maybeResult !== undefined) {
-              movePromise(id);
-              return unwrapOpResultNewPromise(id, maybeResult, async_op_3);
+              return PromiseResolve(maybeResult);
             }
           } catch (err) {
-            movePromise(id);
             ErrorCaptureStackTrace(err, async_op_3);
             return PromiseReject(err);
           }
+          nextPromiseId = (id + 1) & 0xffffffff;
           let promise = PromisePrototypeThen(
             setPromise(id),
             unwrapOpError(eventLoopTick),
@@ -426,21 +352,19 @@ for (let i = 0; i < 10; i++) {
           return promise;
         };
         break;
-
       case 4:
         fn = function async_op_4(a, b, c, d) {
-          const id = (nextPromiseId = (nextPromiseId + 1) & 0xffffffff);
+          const id = nextPromiseId;
           try {
             const maybeResult = originalOp(id, a, b, c, d);
             if (maybeResult !== undefined) {
-              movePromise(id);
-              return unwrapOpResultNewPromise(id, maybeResult, async_op_4);
+              return PromiseResolve(maybeResult);
             }
           } catch (err) {
-            movePromise(id);
             ErrorCaptureStackTrace(err, async_op_4);
             return PromiseReject(err);
           }
+          nextPromiseId = (id + 1) & 0xffffffff;
           let promise = PromisePrototypeThen(
             setPromise(id),
             unwrapOpError(eventLoopTick),
@@ -450,21 +374,19 @@ for (let i = 0; i < 10; i++) {
           return promise;
         };
         break;
-
       case 5:
         fn = function async_op_5(a, b, c, d, e) {
-          const id = (nextPromiseId = (nextPromiseId + 1) & 0xffffffff);
+          const id = nextPromiseId;
           try {
             const maybeResult = originalOp(id, a, b, c, d, e);
             if (maybeResult !== undefined) {
-              movePromise(id);
-              return unwrapOpResultNewPromise(id, maybeResult, async_op_5);
+              return PromiseResolve(maybeResult);
             }
           } catch (err) {
-            movePromise(id);
             ErrorCaptureStackTrace(err, async_op_5);
             return PromiseReject(err);
           }
+          nextPromiseId = (id + 1) & 0xffffffff;
           let promise = PromisePrototypeThen(
             setPromise(id),
             unwrapOpError(eventLoopTick),
@@ -474,21 +396,19 @@ for (let i = 0; i < 10; i++) {
           return promise;
         };
         break;
-
       case 6:
         fn = function async_op_6(a, b, c, d, e, f) {
-          const id = (nextPromiseId = (nextPromiseId + 1) & 0xffffffff);
+          const id = nextPromiseId;
           try {
             const maybeResult = originalOp(id, a, b, c, d, e, f);
             if (maybeResult !== undefined) {
-              movePromise(id);
-              return unwrapOpResultNewPromise(id, maybeResult, async_op_6);
+              return PromiseResolve(maybeResult);
             }
           } catch (err) {
-            movePromise(id);
             ErrorCaptureStackTrace(err, async_op_6);
             return PromiseReject(err);
           }
+          nextPromiseId = (id + 1) & 0xffffffff;
           let promise = PromisePrototypeThen(
             setPromise(id),
             unwrapOpError(eventLoopTick),
@@ -498,21 +418,19 @@ for (let i = 0; i < 10; i++) {
           return promise;
         };
         break;
-
       case 7:
         fn = function async_op_7(a, b, c, d, e, f, g) {
-          const id = (nextPromiseId = (nextPromiseId + 1) & 0xffffffff);
+          const id = nextPromiseId;
           try {
             const maybeResult = originalOp(id, a, b, c, d, e, f, g);
             if (maybeResult !== undefined) {
-              movePromise(id);
-              return unwrapOpResultNewPromise(id, maybeResult, async_op_7);
+              return PromiseResolve(maybeResult);
             }
           } catch (err) {
-            movePromise(id);
             ErrorCaptureStackTrace(err, async_op_7);
             return PromiseReject(err);
           }
+          nextPromiseId = (id + 1) & 0xffffffff;
           let promise = PromisePrototypeThen(
             setPromise(id),
             unwrapOpError(eventLoopTick),
@@ -522,21 +440,19 @@ for (let i = 0; i < 10; i++) {
           return promise;
         };
         break;
-
       case 8:
         fn = function async_op_8(a, b, c, d, e, f, g, h) {
-          const id = (nextPromiseId = (nextPromiseId + 1) & 0xffffffff);
+          const id = nextPromiseId;
           try {
             const maybeResult = originalOp(id, a, b, c, d, e, f, g, h);
             if (maybeResult !== undefined) {
-              movePromise(id);
-              return unwrapOpResultNewPromise(id, maybeResult, async_op_8);
+              return PromiseResolve(maybeResult);
             }
           } catch (err) {
-            movePromise(id);
             ErrorCaptureStackTrace(err, async_op_8);
             return PromiseReject(err);
           }
+          nextPromiseId = (id + 1) & 0xffffffff;
           let promise = PromisePrototypeThen(
             setPromise(id),
             unwrapOpError(eventLoopTick),
@@ -546,21 +462,19 @@ for (let i = 0; i < 10; i++) {
           return promise;
         };
         break;
-
       case 9:
         fn = function async_op_9(a, b, c, d, e, f, g, h, i) {
-          const id = (nextPromiseId = (nextPromiseId + 1) & 0xffffffff);
+          const id = nextPromiseId;
           try {
             const maybeResult = originalOp(id, a, b, c, d, e, f, g, h, i);
             if (maybeResult !== undefined) {
-              movePromise(id);
-              return unwrapOpResultNewPromise(id, maybeResult, async_op_9);
+              return PromiseResolve(maybeResult);
             }
           } catch (err) {
-            movePromise(id);
             ErrorCaptureStackTrace(err, async_op_9);
             return PromiseReject(err);
           }
+          nextPromiseId = (id + 1) & 0xffffffff;
           let promise = PromisePrototypeThen(
             setPromise(id),
             unwrapOpError(eventLoopTick),
@@ -570,6 +484,7 @@ for (let i = 0; i < 10; i++) {
           return promise;
         };
         break;
+      /* END TEMPLATE */
 
       default:
         throw new Error(
@@ -586,30 +501,32 @@ for (let i = 0; i < 10; i++) {
     return (ops[opName] = fn);
   }
 
-  function opAsync(name, ...args) {
-    const id = (nextPromiseId = (nextPromiseId + 1) & 0xffffffff);
+  /* BEGIN TEMPLATE opAsync */
+  /* DO NOT MODIFY: use rebuild_async_stubs.js to regenerate */
+  function opAsync(opName, ...args) {
+    const id = nextPromiseId;
     try {
-      const maybeResult = asyncOps[name](id, ...new SafeArrayIterator(args));
+      const maybeResult = asyncOps[opName](id, ...new SafeArrayIterator(args));
       if (maybeResult !== undefined) {
-        movePromise(id);
-        return unwrapOpResultNewPromise(id, maybeResult, opAsync);
+        return PromiseResolve(maybeResult);
       }
     } catch (err) {
-      movePromise(id);
-      if (!ReflectHas(asyncOps, name)) {
-        return PromiseReject(new TypeError(`${name} is not a registered op`));
+      if (!ReflectHas(asyncOps, opName)) {
+        return PromiseReject(new TypeError(`${opName} is not a registered op`));
       }
       ErrorCaptureStackTrace(err, opAsync);
       return PromiseReject(err);
     }
+    nextPromiseId = (id + 1) & 0xffffffff;
     let promise = PromisePrototypeThen(
       setPromise(id),
       unwrapOpError(eventLoopTick),
     );
-    promise = handleOpCallTracing(name, id, promise);
+    promise = handleOpCallTracing(opName, id, promise);
     promise[promiseIdSymbol] = id;
     return promise;
   }
+  /* END TEMPLATE */
 
   function handleOpCallTracing(opName, promiseId, p) {
     if (opCallTracingEnabled) {
diff --git a/core/benches/ops/async.rs b/core/benches/ops/async.rs
index ad4c418..4f06e75 100644
--- a/core/benches/ops/async.rs
+++ b/core/benches/ops/async.rs
@@ -210,6 +210,17 @@ fn bench_op_async_void_deferred_return(b: &mut Bencher) {
   );
 }
 
+/// Tests the overhead of opAsync.
+fn bench_op_async_void_indirect(b: &mut Bencher) {
+  bench_op(
+    b,
+    BENCH_COUNT,
+    "op_async_void",
+    0,
+    "accum += await opAsync('op_async_void');",
+  );
+}
+
 macro_rules! bench_void {
   ($bench:ident, $op:ident) => {
     fn $bench(b: &mut Bencher) {
@@ -254,6 +265,7 @@ benchmark_group!(
   bench_op_async_yield_lazy_nofast,
   bench_op_async_yield_deferred,
   bench_op_async_yield_deferred_nofast,
+  bench_op_async_void_indirect,
   bench_op_async_void,
   bench_op_async_void_lazy,
   bench_op_async_void_lazy_nofast,
diff --git a/core/benches/ops/async_harness.js b/core/benches/ops/async_harness.js
index daf1ce5..d70669f 100644
--- a/core/benches/ops/async_harness.js
+++ b/core/benches/ops/async_harness.js
@@ -9,6 +9,7 @@ async function run() {
   const LARGE_STRING_UTF8_1000 = "\u1000".repeat(1000);
   const BUFFER = new Uint8Array(1024);
   const ARRAYBUFFER = new ArrayBuffer(1024);
+  const opAsync = Deno.core.opAsync;
   const { __OP__: op } = Deno.core.ensureFastOps();
   const { op_make_external } = Deno.core.ensureFastOps();
   const EXTERNAL = op_make_external();
diff --git a/core/lib.rs b/core/lib.rs
index dadefd2..b147020 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -192,6 +192,8 @@ macro_rules! located_script_name {
 
 #[cfg(test)]
 mod tests {
+  use std::process::{Command, Stdio};
+
   use super::*;
 
   #[test]
@@ -211,4 +213,25 @@ mod tests {
   fn test_v8_version() {
     assert!(v8_version().len() > 3);
   }
+
+  // If the deno command is available, we ensure the async stubs are correctly rebuilt.
+  #[test]
+  fn test_rebuild_async_stubs() {
+    // Check for deno first
+    if let Err(e) = Command::new("deno")
+      .arg("--version")
+      .stderr(Stdio::null())
+      .stdout(Stdio::null())
+      .status()
+    {
+      eprintln!("Ignoring test because we couldn't find deno: {e:?}");
+    }
+    let status = Command::new("deno")
+      .args(["run", "-A", "rebuild_async_stubs.js", "--check"])
+      .stderr(Stdio::null())
+      .stdout(Stdio::null())
+      .status()
+      .unwrap();
+    assert!(status.success(), "Async stubs were not updated, or 'rebuild_async_stubs.js' failed for some other reason");
+  }
 }
diff --git a/core/rebuild_async_stubs.js b/core/rebuild_async_stubs.js
new file mode 100755
index 0000000..dc1fa5e
--- /dev/null
+++ b/core/rebuild_async_stubs.js
@@ -0,0 +1,97 @@
+#!/usr/bin/env deno run --allow-read --allow-write
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+const doNotModify =
+  "/* DO NOT MODIFY: use rebuild_async_stubs.js to regenerate */\n";
+
+// The template function we build opAsync and op_async_N functions from
+function __TEMPLATE__(__ARGS_PARAM__) {
+  const id = nextPromiseId;
+  try {
+    const maybeResult = __OP__(__ARGS__);
+    if (maybeResult !== undefined) {
+      return PromiseResolve(maybeResult);
+    }
+  } catch (err) {
+    __ERR__;
+    ErrorCaptureStackTrace(err, __TEMPLATE__);
+    return PromiseReject(err);
+  }
+  nextPromiseId = (id + 1) & 0xffffffff;
+  let promise = PromisePrototypeThen(
+    setPromise(id),
+    unwrapOpError(eventLoopTick),
+  );
+  promise = handleOpCallTracing(opName, id, promise);
+  promise[promiseIdSymbol] = id;
+  return promise;
+}
+
+const coreJsPath = new URL("01_core.js", import.meta.url);
+const coreJs = Deno.readTextFileSync(coreJsPath);
+
+const corePristine = coreJs.replaceAll(
+  /\/\* BEGIN TEMPLATE ([^ ]+) \*\/.*?\/\* END TEMPLATE \*\//smg,
+  "TEMPLATE-$1",
+);
+const templateString = __TEMPLATE__.toString();
+let asyncStubCases = "/* BEGIN TEMPLATE setUpAsyncStub */\n";
+asyncStubCases += doNotModify;
+const vars = "abcdefghijklm";
+for (let i = 0; i < 10; i++) {
+  let args = "id";
+  for (let j = 0; j < i; j++) {
+    args += `, ${vars[j]}`;
+  }
+  const name = `async_op_${i}`;
+  // Replace the name and args, and add a two-space indent
+  const func = `fn = ${templateString}`
+    .replaceAll(/__TEMPLATE__/g, name)
+    .replaceAll(/__ARGS__/g, args)
+    .replaceAll(/__ARGS_PARAM__/g, args.replace(/id(, )?/, ""))
+    .replaceAll(/__OP__/g, "originalOp")
+    .replaceAll(/[\s]*__ERR__;/g, "")
+    .replaceAll(/^/gm, "  ");
+  asyncStubCases += `
+case ${i}:
+${func};
+  break;
+  `.trim() + "\n";
+}
+asyncStubCases += "/* END TEMPLATE */";
+
+const opAsync = "/* BEGIN TEMPLATE opAsync */\n" + doNotModify +
+  templateString
+    .replaceAll(/__TEMPLATE__/g, "opAsync")
+    .replaceAll(/__ARGS_PARAM__/g, "opName, ...args")
+    .replaceAll(/__ARGS__/g, "id, ...new SafeArrayIterator(args)")
+    .replaceAll(/__OP__/g, "asyncOps[opName]")
+    .replaceAll(
+      /__ERR__;/g,
+      "if (!ReflectHas(asyncOps, opName)) {\n      return PromiseReject(new TypeError(`${opName} is not a registered op`));\n    }",
+    ) +
+  "\n/* END TEMPLATE */";
+
+const asyncStubIndent =
+  corePristine.match(/^([\t ]+)(?=TEMPLATE-setUpAsyncStub)/m)[0];
+const opAsyncIndent = corePristine.match(/^([\t ]+)(?=TEMPLATE-opAsync)/m)[0];
+
+const coreOutput = corePristine
+  .replace(
+    /[\t ]+TEMPLATE-setUpAsyncStub/,
+    asyncStubCases.replaceAll(/^/gm, asyncStubIndent),
+  )
+  .replace(/[\t ]+TEMPLATE-opAsync/, opAsync.replaceAll(/^/gm, opAsyncIndent));
+
+if (Deno.args[0] === "--check") {
+  if (coreOutput !== coreJs) {
+    Deno.writeTextFileSync("/tmp/mismatch.txt", coreOutput);
+    throw new Error(
+      "Mismatch between pristine and updated source (wrote mismatch to /tmp/mismatch.txt)",
+    );
+  } else {
+    console.log("✅ Templated sections would not change");
+  }
+} else {
+  Deno.writeTextFileSync(coreJsPath, coreOutput);
+}


Test patch:
diff --git a/core/runtime/tests/ops.rs b/core/runtime/tests/ops.rs
index 6e4205c..f9fe2a2 100644
--- a/core/runtime/tests/ops.rs
+++ b/core/runtime/tests/ops.rs
@@ -15,6 +15,7 @@ use std::cell::RefCell;
 use std::rc::Rc;
 use std::sync::atomic::Ordering;
 use std::time::Duration;
+use tokio::sync::Barrier;
 use url::Url;
 
 #[tokio::test]
@@ -353,6 +354,40 @@ fn ops_in_js_have_proper_names() {
   runtime.execute_script_static("test", src).unwrap();
 }
 
+/// Dipatch more promises than the ring can hold, but wait for them all to queue up first.
+#[tokio::test]
+async fn test_dispatch_many_ops() {
+  #[op2(async)]
+  async fn op_wait(state: Rc<RefCell<OpState>>) {
+    let barrier: Rc<Barrier> = state.borrow().borrow::<Rc<Barrier>>().clone();
+    barrier.wait().await;
+  }
+
+  deno_core::extension!(test_ext,
+    ops = [op_wait],
+    options = { count: Barrier },
+    state = |state, options| {
+      state.put(Rc::new(options.count));
+    }
+  );
+
+  let mut runtime = JsRuntime::new(RuntimeOptions {
+    extensions: vec![test_ext::init_ops(Barrier::new(5000))],
+    ..Default::default()
+  });
+
+  let src = r#"
+  const { op_wait } = Deno.core.ensureFastOps();
+  const promises = [];
+  for (let i = 0; i < 5000; i++) {
+    promises.push(op_wait());
+  }
+  Promise.all(promises);
+  "#;
+  let promise = runtime.execute_script_static("test", src).unwrap();
+  runtime.resolve_value(promise).await.unwrap();
+}
+
 #[tokio::test]
 async fn test_ref_unref_ops() {
   let (mut runtime, _dispatch_count) = setup(Mode::AsyncDeferred);
@@ -422,23 +457,6 @@ fn test_dispatch() {
   assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
 }
 
-#[test]
-fn test_op_async_promise_id() {
-  let (mut runtime, _dispatch_count) = setup(Mode::Async);
-  runtime
-    .execute_script_static(
-      "filename.js",
-      r#"
-
-      const p = Deno.core.opAsync("op_test", 42);
-      if (p[Symbol.for("Deno.core.internalPromiseId")] == undefined) {
-        throw new Error("missing id on returned promise");
-      }
-      "#,
-    )
-    .unwrap();
-}
-
 #[test]
 fn test_dispatch_no_zero_copy_buf() {
   let (mut runtime, dispatch_count) = setup(Mode::AsyncZeroCopy(false));