summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/bench/async_ops.js4
-rw-r--r--cli/bench/async_ops_deferred.js4
-rw-r--r--cli/tests/unit/metrics_test.ts10
-rw-r--r--cli/tests/unit/opcall_test.ts33
-rw-r--r--cli/tsc/compiler.d.ts2
-rw-r--r--core/01_core.js465
-rw-r--r--core/bindings.js49
-rw-r--r--core/bindings.rs212
-rw-r--r--core/extensions.rs1
-rw-r--r--core/lib.deno_core.d.ts8
-rw-r--r--core/ops_builtin.rs18
-rw-r--r--core/runtime.rs30
-rw-r--r--ext/http/00_serve.js81
-rw-r--r--ops/lib.rs24
-rw-r--r--ops/optimizer_tests/async_nop.out1
-rw-r--r--ops/optimizer_tests/async_result.out1
-rw-r--r--ops/optimizer_tests/callback_options.out1
-rw-r--r--ops/optimizer_tests/cow_str.out1
-rw-r--r--ops/optimizer_tests/f64_slice.out1
-rw-r--r--ops/optimizer_tests/incompatible_1.out1
-rw-r--r--ops/optimizer_tests/issue16934.out1
-rw-r--r--ops/optimizer_tests/issue16934_fast.out1
-rw-r--r--ops/optimizer_tests/op_blob_revoke_object_url.out1
-rw-r--r--ops/optimizer_tests/op_ffi_ptr_value.out1
-rw-r--r--ops/optimizer_tests/op_print.out1
-rw-r--r--ops/optimizer_tests/op_state.out1
-rw-r--r--ops/optimizer_tests/op_state_basic1.out1
-rw-r--r--ops/optimizer_tests/op_state_generics.out1
-rw-r--r--ops/optimizer_tests/op_state_result.out1
-rw-r--r--ops/optimizer_tests/op_state_warning.out1
-rw-r--r--ops/optimizer_tests/op_state_with_transforms.out1
-rw-r--r--ops/optimizer_tests/opstate_with_arity.out1
-rw-r--r--ops/optimizer_tests/option_arg.out1
-rw-r--r--ops/optimizer_tests/owned_string.out1
-rw-r--r--ops/optimizer_tests/param_mut_binding_warning.out1
-rw-r--r--ops/optimizer_tests/raw_ptr.out1
-rw-r--r--ops/optimizer_tests/serde_v8_value.out1
-rw-r--r--ops/optimizer_tests/strings.out1
-rw-r--r--ops/optimizer_tests/strings_result.out1
-rw-r--r--ops/optimizer_tests/u64_result.out1
-rw-r--r--ops/optimizer_tests/uint8array.out1
-rw-r--r--ops/optimizer_tests/unit_result.out1
-rw-r--r--ops/optimizer_tests/unit_result2.out1
-rw-r--r--ops/optimizer_tests/unit_ret.out1
-rw-r--r--ops/optimizer_tests/wasm_op.out1
45 files changed, 736 insertions, 236 deletions
diff --git a/cli/bench/async_ops.js b/cli/bench/async_ops.js
index fc04942be..f6c1465d2 100644
--- a/cli/bench/async_ops.js
+++ b/cli/bench/async_ops.js
@@ -17,4 +17,6 @@ async function bench(fun) {
}
const core = Deno[Deno.internal].core;
-bench(() => core.opAsync("op_void_async"));
+const ops = core.ops;
+const opVoidAsync = ops.op_void_async;
+bench(() => opVoidAsync());
diff --git a/cli/bench/async_ops_deferred.js b/cli/bench/async_ops_deferred.js
index 7a816cf95..2751ad226 100644
--- a/cli/bench/async_ops_deferred.js
+++ b/cli/bench/async_ops_deferred.js
@@ -17,4 +17,6 @@ async function bench(fun) {
}
const core = Deno[Deno.internal].core;
-bench(() => core.opAsync("op_void_async_deferred"));
+const ops = core.ops;
+const opVoidAsyncDeferred = ops.op_void_async_deferred;
+bench(() => opVoidAsyncDeferred());
diff --git a/cli/tests/unit/metrics_test.ts b/cli/tests/unit/metrics_test.ts
index df2f1b2be..5fdfebc85 100644
--- a/cli/tests/unit/metrics_test.ts
+++ b/cli/tests/unit/metrics_test.ts
@@ -80,12 +80,14 @@ Deno.test(function metricsForOpCrates() {
// Test that op_names == Objects.keys(Deno[Deno.internal].core.ops)
// since building the per-op metrics depends on op_names being complete
Deno.test(function opNamesMatch() {
+ // @ts-ignore: Deno[Deno.internal].core allowed
+ const ops = Object.keys(Deno[Deno.internal].core.ops);
+ // @ts-ignore: Deno[Deno.internal].core allowed
+ ops.concat(Object.keys(Deno[Deno.internal].core.asyncOps));
+
assertEquals(
// @ts-ignore: Deno[Deno.internal].core allowed
Deno[Deno.internal].core.opNames().sort(),
- // @ts-ignore: Deno[Deno.internal].core allowed
- Object.keys(Deno[Deno.internal].core.ops).sort().filter((name) =>
- name !== "asyncOpsInfo"
- ),
+ ops.sort().filter((name) => name !== "asyncOpsInfo"),
);
});
diff --git a/cli/tests/unit/opcall_test.ts b/cli/tests/unit/opcall_test.ts
index 8985c9780..3b37f8c09 100644
--- a/cli/tests/unit/opcall_test.ts
+++ b/cli/tests/unit/opcall_test.ts
@@ -1,20 +1,18 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import { assertEquals } from "https://deno.land/std@v0.42.0/testing/asserts.ts";
import { assert, assertStringIncludes, unreachable } from "./test_util.ts";
Deno.test(async function sendAsyncStackTrace() {
- const buf = new Uint8Array(10);
- const rid = 10;
try {
- await Deno.read(rid, buf);
+ await core.ops.op_error_async();
unreachable();
} catch (error) {
assert(error instanceof Error);
const s = error.stack?.toString();
assert(s);
- console.log(s);
assertStringIncludes(s, "opcall_test.ts");
- assertStringIncludes(s, "read");
+ assertStringIncludes(s, "sendAsyncStackTrace");
assert(
!s.includes("ext:core"),
"opcall stack traces should NOT include ext:core internals such as unwrapOpResult",
@@ -22,6 +20,31 @@ Deno.test(async function sendAsyncStackTrace() {
}
});
+Deno.test(async function sendAsyncStackTraceDeferred() {
+ try {
+ await core.ops.op_error_async_deferred();
+ unreachable();
+ } catch (error) {
+ assert(error instanceof Error);
+ const s = error.stack?.toString();
+ assert(s);
+ assertStringIncludes(s, "opcall_test.ts");
+ assertStringIncludes(s, "sendAsyncStackTraceDeferred");
+ assert(
+ !s.includes("ext:core"),
+ "opcall stack traces should NOT include ext:core internals such as unwrapOpResult",
+ );
+ }
+});
+
+Deno.test(function syncAdd() {
+ assertEquals(30, core.ops.op_add(10, 20));
+});
+
+Deno.test(async function asyncAdd() {
+ assertEquals(30, await core.ops.op_add_async(10, 20));
+});
+
// @ts-ignore This is not publicly typed namespace, but it's there for sure.
const core = Deno[Deno.internal].core;
diff --git a/cli/tsc/compiler.d.ts b/cli/tsc/compiler.d.ts
index b59f6dca8..66c094697 100644
--- a/cli/tsc/compiler.d.ts
+++ b/cli/tsc/compiler.d.ts
@@ -46,6 +46,8 @@ declare global {
encode(value: string): Uint8Array;
// deno-lint-ignore no-explicit-any
ops: Record<string, (...args: unknown[]) => any>;
+ // deno-lint-ignore no-explicit-any
+ asyncOps: Record<string, (...args: unknown[]) => any>;
print(msg: string, stderr: boolean): void;
registerErrorClass(
name: string,
diff --git a/core/01_core.js b/core/01_core.js
index a8bdeb2a8..3972dec33 100644
--- a/core/01_core.js
+++ b/core/01_core.js
@@ -16,11 +16,15 @@
ObjectAssign,
ObjectFreeze,
ObjectFromEntries,
+ ObjectKeys,
Promise,
+ PromiseReject,
+ PromiseResolve,
PromisePrototypeThen,
RangeError,
ReferenceError,
ReflectHas,
+ ReflectApply,
SafeArrayIterator,
SafeMap,
SafePromisePrototypeFinally,
@@ -32,7 +36,7 @@
TypeError,
URIError,
} = window.__bootstrap.primordials;
- const { ops } = window.Deno.core;
+ const { ops, asyncOps } = window.Deno.core;
const build = {
target: "unknown",
@@ -85,6 +89,17 @@
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
@@ -208,7 +223,29 @@
return error;
}
- function unwrapOpResult(res) {
+ function unwrapOpError(hideFunction) {
+ return (res) => {
+ // .$err_class_name is a special key that should only exist on errors
+ const className = res?.$err_class_name;
+ if (!className) {
+ return res;
+ }
+
+ 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);
+ throw err;
+ };
+ }
+
+ 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;
@@ -221,59 +258,359 @@
err.code = res.code;
}
// Strip unwrapOpResult() and errorBuilder() calls from stack trace
- ErrorCaptureStackTrace(err, unwrapOpResult);
- throw err;
+ ErrorCaptureStackTrace(err, hideFunction);
+ return PromiseReject(err);
}
- return res;
+ 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++;
+ 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);
+ return ReflectApply(ops[opName], undefined, args);
+ }
+
+ function setUpAsyncStub(opName) {
+ const originalOp = asyncOps[opName];
+ let fn;
+ // The body of this switch statement can be generated using the script above.
+ switch (originalOp.length - 1) {
+ case 0:
+ fn = function async_op_0() {
+ const id = nextPromiseId++;
+ try {
+ const maybeResult = originalOp(id);
+ if (maybeResult !== undefined) {
+ movePromise(id);
+ return unwrapOpResultNewPromise(id, maybeResult, async_op_0);
+ }
+ } catch (err) {
+ movePromise(id);
+ ErrorCaptureStackTrace(err, async_op_0);
+ return PromiseReject(err);
+ }
+ let promise = PromisePrototypeThen(
+ setPromise(id),
+ unwrapOpError(eventLoopTick),
+ );
+ promise = handleOpCallTracing(opName, id, promise);
+ promise[promiseIdSymbol] = id;
+ return promise;
+ };
+ break;
+
+ case 1:
+ fn = function async_op_1(a) {
+ const id = nextPromiseId++;
+ try {
+ const maybeResult = originalOp(id, a);
+ if (maybeResult !== undefined) {
+ movePromise(id);
+ return unwrapOpResultNewPromise(id, maybeResult, async_op_1);
+ }
+ } catch (err) {
+ movePromise(id);
+ ErrorCaptureStackTrace(err, async_op_1);
+ return PromiseReject(err);
+ }
+ let promise = PromisePrototypeThen(
+ setPromise(id),
+ unwrapOpError(eventLoopTick),
+ );
+ promise = handleOpCallTracing(opName, id, promise);
+ promise[promiseIdSymbol] = id;
+ return promise;
+ };
+ break;
+
+ case 2:
+ fn = function async_op_2(a, b) {
+ const id = nextPromiseId++;
+ try {
+ const maybeResult = originalOp(id, a, b);
+ if (maybeResult !== undefined) {
+ movePromise(id);
+ return unwrapOpResultNewPromise(id, maybeResult, async_op_2);
+ }
+ } catch (err) {
+ movePromise(id);
+ ErrorCaptureStackTrace(err, async_op_2);
+ return PromiseReject(err);
+ }
+ let promise = PromisePrototypeThen(
+ setPromise(id),
+ unwrapOpError(eventLoopTick),
+ );
+ promise = handleOpCallTracing(opName, id, promise);
+ promise[promiseIdSymbol] = id;
+ return promise;
+ };
+ break;
+
+ case 3:
+ fn = function async_op_3(a, b, c) {
+ const id = nextPromiseId++;
+ try {
+ const maybeResult = originalOp(id, a, b, c);
+ if (maybeResult !== undefined) {
+ movePromise(id);
+ return unwrapOpResultNewPromise(id, maybeResult, async_op_3);
+ }
+ } catch (err) {
+ movePromise(id);
+ ErrorCaptureStackTrace(err, async_op_3);
+ return PromiseReject(err);
+ }
+ let promise = PromisePrototypeThen(
+ setPromise(id),
+ unwrapOpError(eventLoopTick),
+ );
+ promise = handleOpCallTracing(opName, id, promise);
+ promise[promiseIdSymbol] = id;
+ return promise;
+ };
+ break;
+
+ case 4:
+ fn = function async_op_4(a, b, c, d) {
+ const id = nextPromiseId++;
+ try {
+ const maybeResult = originalOp(id, a, b, c, d);
+ if (maybeResult !== undefined) {
+ movePromise(id);
+ return unwrapOpResultNewPromise(id, maybeResult, async_op_4);
+ }
+ } catch (err) {
+ movePromise(id);
+ ErrorCaptureStackTrace(err, async_op_4);
+ return PromiseReject(err);
+ }
+ let promise = PromisePrototypeThen(
+ setPromise(id),
+ unwrapOpError(eventLoopTick),
+ );
+ promise = handleOpCallTracing(opName, id, promise);
+ promise[promiseIdSymbol] = id;
+ return promise;
+ };
+ break;
+
+ case 5:
+ fn = function async_op_5(a, b, c, d, e) {
+ 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);
+ }
+ } catch (err) {
+ movePromise(id);
+ ErrorCaptureStackTrace(err, async_op_5);
+ return PromiseReject(err);
+ }
+ let promise = PromisePrototypeThen(
+ setPromise(id),
+ unwrapOpError(eventLoopTick),
+ );
+ promise = handleOpCallTracing(opName, id, promise);
+ promise[promiseIdSymbol] = id;
+ return promise;
+ };
+ break;
+
+ case 6:
+ fn = function async_op_6(a, b, c, d, e, f) {
+ 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);
+ }
+ } catch (err) {
+ movePromise(id);
+ ErrorCaptureStackTrace(err, async_op_6);
+ return PromiseReject(err);
+ }
+ let promise = PromisePrototypeThen(
+ setPromise(id),
+ unwrapOpError(eventLoopTick),
+ );
+ promise = handleOpCallTracing(opName, id, promise);
+ promise[promiseIdSymbol] = id;
+ return promise;
+ };
+ break;
+
+ case 7:
+ fn = function async_op_7(a, b, c, d, e, f, g) {
+ 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);
+ }
+ } catch (err) {
+ movePromise(id);
+ ErrorCaptureStackTrace(err, async_op_7);
+ return PromiseReject(err);
+ }
+ let promise = PromisePrototypeThen(
+ setPromise(id),
+ unwrapOpError(eventLoopTick),
+ );
+ promise = handleOpCallTracing(opName, id, promise);
+ promise[promiseIdSymbol] = id;
+ return promise;
+ };
+ break;
+
+ case 8:
+ fn = function async_op_8(a, b, c, d, e, f, g, h) {
+ 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);
+ }
+ } catch (err) {
+ movePromise(id);
+ ErrorCaptureStackTrace(err, async_op_8);
+ return PromiseReject(err);
+ }
+ let promise = PromisePrototypeThen(
+ setPromise(id),
+ unwrapOpError(eventLoopTick),
+ );
+ promise = handleOpCallTracing(opName, id, promise);
+ promise[promiseIdSymbol] = id;
+ return promise;
+ };
+ break;
+
+ case 9:
+ fn = function async_op_9(a, b, c, d, e, f, g, h, i) {
+ 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);
+ }
+ } catch (err) {
+ movePromise(id);
+ ErrorCaptureStackTrace(err, async_op_9);
+ return PromiseReject(err);
+ }
+ let promise = PromisePrototypeThen(
+ setPromise(id),
+ unwrapOpError(eventLoopTick),
+ );
+ promise = handleOpCallTracing(opName, id, promise);
+ promise[promiseIdSymbol] = id;
+ return promise;
+ };
+ break;
+
+ default:
+ throw new Error(
+ `Too many arguments for async op codegen (length of ${opName} was ${
+ originalOp.length - 1
+ })`,
+ );
+ }
+ return (ops[opName] = fn);
}
function opAsync2(name, arg0, arg1) {
const id = nextPromiseId++;
- let promise = PromisePrototypeThen(setPromise(id), unwrapOpResult);
- let maybeResult;
try {
- maybeResult = ops[name](id, arg0, arg1);
+ const maybeResult = asyncOps[name](id, arg0, arg1);
+ if (maybeResult !== undefined) {
+ movePromise(id);
+ return unwrapOpResultNewPromise(id, maybeResult, opAsync2);
+ }
} catch (err) {
- // Cleanup the just-created promise
- getPromise(id);
- if (!ReflectHas(ops, name)) {
- throw new TypeError(`${name} is not a registered op`);
+ movePromise(id);
+ if (!ReflectHas(asyncOps, name)) {
+ return PromiseReject(new TypeError(`${name} is not a registered op`));
}
- // Rethrow the error
- throw err;
+ ErrorCaptureStackTrace(err, opAsync2);
+ return PromiseReject(err);
}
+ let promise = PromisePrototypeThen(
+ setPromise(id),
+ unwrapOpError(eventLoopTick),
+ );
promise = handleOpCallTracing(name, id, promise);
promise[promiseIdSymbol] = id;
- if (typeof maybeResult !== "undefined") {
- const promise = getPromise(id);
- promise.resolve(maybeResult);
- }
-
return promise;
}
function opAsync(name, ...args) {
const id = nextPromiseId++;
- let promise = PromisePrototypeThen(setPromise(id), unwrapOpResult);
- let maybeResult;
try {
- maybeResult = ops[name](id, ...new SafeArrayIterator(args));
+ const maybeResult = asyncOps[name](id, ...new SafeArrayIterator(args));
+ if (maybeResult !== undefined) {
+ movePromise(id);
+ return unwrapOpResultNewPromise(id, maybeResult, opAsync);
+ }
} catch (err) {
- // Cleanup the just-created promise
- getPromise(id);
- if (!ReflectHas(ops, name)) {
- throw new TypeError(`${name} is not a registered op`);
+ movePromise(id);
+ if (!ReflectHas(asyncOps, name)) {
+ return PromiseReject(new TypeError(`${name} is not a registered op`));
}
- // Rethrow the error
- throw err;
+ ErrorCaptureStackTrace(err, opAsync);
+ return PromiseReject(err);
}
+ let promise = PromisePrototypeThen(
+ setPromise(id),
+ unwrapOpError(eventLoopTick),
+ );
promise = handleOpCallTracing(name, id, promise);
promise[promiseIdSymbol] = id;
- if (typeof maybeResult !== "undefined") {
- const promise = getPromise(id);
- promise.resolve(maybeResult);
- }
-
return promise;
}
@@ -439,8 +776,52 @@
);
}
+ // Eagerly initialize ops for snapshot purposes
+ for (const opName of new SafeArrayIterator(ObjectKeys(asyncOps))) {
+ setUpAsyncStub(opName);
+ }
+
+ function generateAsyncOpHandler(/* opNames... */) {
+ const fastOps = {};
+ for (const opName of new SafeArrayIterator(arguments)) {
+ if (ops[opName] === undefined) {
+ throw new Error(`Unknown or disabled op '${opName}'`);
+ }
+ if (asyncOps[opName] !== undefined) {
+ fastOps[opName] = setUpAsyncStub(opName);
+ } else {
+ fastOps[opName] = ops[opName];
+ }
+ }
+ return fastOps;
+ }
+
+ const {
+ op_close: close,
+ op_try_close: tryClose,
+ op_read: read,
+ op_read_all: readAll,
+ op_write: write,
+ op_write_all: writeAll,
+ op_read_sync: readSync,
+ op_write_sync: writeSync,
+ op_shutdown: shutdown,
+ } = generateAsyncOpHandler(
+ "op_close",
+ "op_try_close",
+ "op_read",
+ "op_read_all",
+ "op_write",
+ "op_write_all",
+ "op_read_sync",
+ "op_write_sync",
+ "op_shutdown",
+ );
+
// Extra Deno.core.* exports
const core = ObjectAssign(globalThis.Deno.core, {
+ asyncStub,
+ generateAsyncOpHandler,
opAsync,
opAsync2,
resources,
@@ -460,15 +841,15 @@
unrefOp,
setReportExceptionCallback,
setPromiseHooks,
- close: (rid) => ops.op_close(rid),
- tryClose: (rid) => ops.op_try_close(rid),
- read: opAsync.bind(null, "op_read"),
- readAll: opAsync.bind(null, "op_read_all"),
- write: opAsync.bind(null, "op_write"),
- writeAll: opAsync.bind(null, "op_write_all"),
- readSync: (rid, buffer) => ops.op_read_sync(rid, buffer),
- writeSync: (rid, buffer) => ops.op_write_sync(rid, buffer),
- shutdown: opAsync.bind(null, "op_shutdown"),
+ close,
+ tryClose,
+ read,
+ readAll,
+ write,
+ writeAll,
+ readSync,
+ writeSync,
+ shutdown,
print: (msg, isErr) => ops.op_print(msg, isErr),
setMacrotaskCallback,
setNextTickCallback,
diff --git a/core/bindings.js b/core/bindings.js
new file mode 100644
index 000000000..c7d7af30c
--- /dev/null
+++ b/core/bindings.js
@@ -0,0 +1,49 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+if (!globalThis.Deno) {
+ globalThis.Deno = {
+ core: {
+ ops: {},
+ asyncOps: {},
+ },
+ };
+}
+
+Deno.__op__console = function (callConsole, console) {
+ Deno.core.callConsole = callConsole;
+ Deno.core.console = console;
+};
+
+Deno.__op__registerOp = function (isAsync, op, opName) {
+ const core = Deno.core;
+ if (isAsync) {
+ if (core.ops[opName] !== undefined) {
+ return;
+ }
+ core.asyncOps[opName] = op;
+ core.ops[opName] = function (...args) {
+ if (this !== core.ops) {
+ // deno-lint-ignore prefer-primordials
+ throw new Error(
+ "An async stub cannot be separated from Deno.core.ops. Use ???",
+ );
+ }
+ return core.asyncStub(opName, args);
+ };
+ } else {
+ core.ops[opName] = op;
+ }
+};
+
+Deno.__op__unregisterOp = function (isAsync, opName) {
+ if (isAsync) {
+ delete Deno.core.asyncOps[opName];
+ }
+ delete Deno.core.ops[opName];
+};
+
+Deno.__op__cleanup = function () {
+ delete Deno.__op__console;
+ delete Deno.__op__registerOp;
+ delete Deno.__op__unregisterOp;
+ delete Deno.__op__cleanup;
+};
diff --git a/core/bindings.rs b/core/bindings.rs
index 95e78b6cd..2d9c91461 100644
--- a/core/bindings.rs
+++ b/core/bindings.rs
@@ -1,9 +1,9 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+use log::debug;
+use std::fmt::Write;
use std::option::Option;
use std::os::raw::c_void;
-
-use log::debug;
use v8::MapFnTo;
use crate::error::is_instance_of_error;
@@ -98,6 +98,23 @@ pub fn module_origin<'a>(
)
}
+fn get<'s, T>(
+ scope: &mut v8::HandleScope<'s>,
+ from: v8::Local<v8::Object>,
+ key: &'static [u8],
+ path: &'static str,
+) -> T
+where
+ v8::Local<'s, v8::Value>: TryInto<T>,
+{
+ let key = v8::String::new_external_onebyte_static(scope, key).unwrap();
+ from
+ .get(scope, key.into())
+ .unwrap_or_else(|| panic!("{path} exists"))
+ .try_into()
+ .unwrap_or_else(|_| panic!("unable to convert"))
+}
+
pub(crate) fn initialize_context<'s>(
scope: &mut v8::HandleScope<'s, ()>,
op_ctxs: &[OpCtx],
@@ -108,135 +125,92 @@ pub(crate) fn initialize_context<'s>(
let scope = &mut v8::ContextScope::new(scope, context);
- let deno_str =
- v8::String::new_external_onebyte_static(scope, b"Deno").unwrap();
- let core_str =
- v8::String::new_external_onebyte_static(scope, b"core").unwrap();
- let ops_str = v8::String::new_external_onebyte_static(scope, b"ops").unwrap();
-
- let ops_obj = if snapshot_options.loaded() {
- // Snapshot already registered `Deno.core.ops` but
- // extensions may provide ops that aren't part of the snapshot.
- // Grab the Deno.core.ops object & init it
- let deno_obj: v8::Local<v8::Object> = global
- .get(scope, deno_str.into())
- .unwrap()
- .try_into()
- .unwrap();
- let core_obj: v8::Local<v8::Object> = deno_obj
- .get(scope, core_str.into())
- .unwrap()
- .try_into()
- .unwrap();
- let ops_obj: v8::Local<v8::Object> = core_obj
- .get(scope, ops_str.into())
- .expect("Deno.core.ops to exist")
- .try_into()
- .unwrap();
- ops_obj
- } else {
- // globalThis.Deno = { core: { } };
- let deno_obj = v8::Object::new(scope);
- global.set(scope, deno_str.into(), deno_obj.into());
-
- let core_obj = v8::Object::new(scope);
- deno_obj.set(scope, core_str.into(), core_obj.into());
+ let mut codegen = String::with_capacity(op_ctxs.len() * 200);
+ codegen.push_str(include_str!("bindings.js"));
+ _ = writeln!(
+ codegen,
+ "Deno.__op__ = function(opFns, callConsole, console) {{"
+ );
+ if !snapshot_options.loaded() {
+ _ = writeln!(codegen, "Deno.__op__console(callConsole, console);");
+ }
+ for op_ctx in op_ctxs {
+ if op_ctx.decl.enabled {
+ // If we're loading from a snapshot, we can skip registration for most ops
+ if matches!(snapshot_options, SnapshotOptions::Load)
+ && !op_ctx.decl.force_registration
+ {
+ continue;
+ }
+ _ = writeln!(
+ codegen,
+ "Deno.__op__registerOp({}, opFns[{}], \"{}\");",
+ op_ctx.decl.is_async, op_ctx.id, op_ctx.decl.name
+ );
+ } else {
+ _ = writeln!(
+ codegen,
+ "Deno.__op__unregisterOp({}, \"{}\");",
+ op_ctx.decl.is_async, op_ctx.decl.name
+ );
+ }
+ }
+ codegen.push_str("Deno.__op__cleanup();");
+ _ = writeln!(codegen, "}}");
+ let script = v8::String::new_from_one_byte(
+ scope,
+ codegen.as_bytes(),
+ v8::NewStringType::Normal,
+ )
+ .unwrap();
+ let script = v8::Script::compile(scope, script, None).unwrap();
+ script.run(scope);
+
+ let deno = get(scope, global, b"Deno", "Deno");
+ let op_fn: v8::Local<v8::Function> =
+ get(scope, deno, b"__op__", "Deno.__op__");
+ let recv = v8::undefined(scope);
+ let op_fns = v8::Array::new(scope, op_ctxs.len() as i32);
+ for op_ctx in op_ctxs {
+ let op_fn = op_ctx_function(scope, op_ctx);
+ op_fns.set_index(scope, op_ctx.id as u32, op_fn.into());
+ }
+ if snapshot_options.loaded() {
+ op_fn.call(scope, recv.into(), &[op_fns.into()]);
+ } else {
// Bind functions to Deno.core.*
- set_func(scope, core_obj, "callConsole", call_console);
+ let call_console_fn = v8::Function::new(scope, call_console).unwrap();
// Bind v8 console object to Deno.core.console
let extra_binding_obj = context.get_extras_binding_object(scope);
- let console_str =
- v8::String::new_external_onebyte_static(scope, b"console").unwrap();
- let console_obj = extra_binding_obj.get(scope, console_str.into()).unwrap();
- core_obj.set(scope, console_str.into(), console_obj);
-
- // Bind functions to Deno.core.ops.*
- let ops_obj = v8::Object::new(scope);
- core_obj.set(scope, ops_str.into(), ops_obj.into());
- ops_obj
- };
+ let console_obj: v8::Local<v8::Object> = get(
+ scope,
+ extra_binding_obj,
+ b"console",
+ "ExtrasBindingObject.console",
+ );
- if matches!(snapshot_options, SnapshotOptions::Load) {
- // Only register ops that have `force_registration` flag set to true,
- // the remaining ones should already be in the snapshot. Ignore ops that
- // are disabled.
- for op_ctx in op_ctxs {
- if op_ctx.decl.enabled {
- if op_ctx.decl.force_registration {
- add_op_to_deno_core_ops(scope, ops_obj, op_ctx);
- }
- } else {
- delete_op_from_deno_core_ops(scope, ops_obj, op_ctx)
- }
- }
- } else if matches!(snapshot_options, SnapshotOptions::CreateFromExisting) {
- // Register all enabled ops, probing for which ones are already registered.
- for op_ctx in op_ctxs {
- let key = v8::String::new_external_onebyte_static(
- scope,
- op_ctx.decl.name.as_bytes(),
- )
- .unwrap();
-
- if op_ctx.decl.enabled {
- if ops_obj.get(scope, key.into()).is_some() {
- continue;
- }
- add_op_to_deno_core_ops(scope, ops_obj, op_ctx);
- } else {
- delete_op_from_deno_core_ops(scope, ops_obj, op_ctx)
- }
- }
- } else {
- // In other cases register all ops enabled unconditionally.
- for op_ctx in op_ctxs {
- if op_ctx.decl.enabled {
- add_op_to_deno_core_ops(scope, ops_obj, op_ctx);
- }
- }
+ op_fn.call(
+ scope,
+ recv.into(),
+ &[op_fns.into(), call_console_fn.into(), console_obj.into()],
+ );
}
context
}
-fn set_func(
- scope: &mut v8::HandleScope<'_>,
- obj: v8::Local<v8::Object>,
- name: &'static str,
- callback: impl v8::MapFnTo<v8::FunctionCallback>,
-) {
- let key =
- v8::String::new_external_onebyte_static(scope, name.as_bytes()).unwrap();
- let val = v8::Function::new(scope, callback).unwrap();
- val.set_name(key);
- obj.set(scope, key.into(), val.into());
-}
-
-fn delete_op_from_deno_core_ops(
- scope: &mut v8::HandleScope<'_>,
- obj: v8::Local<v8::Object>,
- op_ctx: &OpCtx,
-) {
- let key =
- v8::String::new_external_onebyte_static(scope, op_ctx.decl.name.as_bytes())
- .unwrap();
- obj.delete(scope, key.into());
-}
-
-fn add_op_to_deno_core_ops(
- scope: &mut v8::HandleScope<'_>,
- obj: v8::Local<v8::Object>,
+fn op_ctx_function<'s>(
+ scope: &mut v8::HandleScope<'s>,
op_ctx: &OpCtx,
-) {
+) -> v8::Local<'s, v8::Function> {
let op_ctx_ptr = op_ctx as *const OpCtx as *const c_void;
- let key =
- v8::String::new_external_onebyte_static(scope, op_ctx.decl.name.as_bytes())
- .unwrap();
let external = v8::External::new(scope, op_ctx_ptr as *mut c_void);
- let builder = v8::FunctionTemplate::builder_raw(op_ctx.decl.v8_fn_ptr)
- .data(external.into());
+ let builder: v8::FunctionBuilder<v8::FunctionTemplate> =
+ v8::FunctionTemplate::builder_raw(op_ctx.decl.v8_fn_ptr)
+ .data(external.into())
+ .length(op_ctx.decl.arg_count as i32);
let templ = if let Some(fast_function) = &op_ctx.decl.fast_fn {
builder.build_fast(
@@ -249,9 +223,7 @@ fn add_op_to_deno_core_ops(
} else {
builder.build(scope)
};
- let val = templ.get_function(scope).unwrap();
- val.set_name(key);
- obj.set(scope, key.into(), val.into());
+ templ.get_function(scope).unwrap()
}
pub extern "C" fn wasm_async_resolve_promise_callback(
diff --git a/core/extensions.rs b/core/extensions.rs
index a0f99c92b..a8b52eb3b 100644
--- a/core/extensions.rs
+++ b/core/extensions.rs
@@ -73,6 +73,7 @@ pub struct OpDecl {
pub is_unstable: bool,
pub is_v8: bool,
pub force_registration: bool,
+ pub arg_count: u8,
pub fast_fn: Option<FastFunction>,
}
diff --git a/core/lib.deno_core.d.ts b/core/lib.deno_core.d.ts
index 7f3ea2a19..fc7865829 100644
--- a/core/lib.deno_core.d.ts
+++ b/core/lib.deno_core.d.ts
@@ -23,11 +23,17 @@ declare namespace Deno {
/**
* List of all registered ops, in the form of a map that maps op
- * name to internal numerical op id.
+ * name to function.
*/
const ops: Record<string, (...args: unknown[]) => any>;
/**
+ * List of all registered async ops, in the form of a map that maps op
+ * name to function.
+ */
+ const asyncOps: Record<string, (...args: unknown[]) => any>;
+
+ /**
* Retrieve a list of all open resources, in the form of a map that maps
* resource id to the resource name.
*/
diff --git a/core/ops_builtin.rs b/core/ops_builtin.rs
index 0c071a918..70f478acd 100644
--- a/core/ops_builtin.rs
+++ b/core/ops_builtin.rs
@@ -27,9 +27,12 @@ crate::extension!(
op_wasm_streaming_feed,
op_wasm_streaming_set_url,
op_void_sync,
+ op_error_async,
+ op_error_async_deferred,
op_void_async,
op_void_async_deferred,
op_add,
+ op_add_async,
// TODO(@AaronO): track IO metrics for builtin streams
op_read,
op_read_all,
@@ -96,12 +99,27 @@ fn op_add(a: i32, b: i32) -> i32 {
a + b
}
+#[op]
+pub async fn op_add_async(a: i32, b: i32) -> i32 {
+ a + b
+}
+
#[op(fast)]
pub fn op_void_sync() {}
#[op]
pub async fn op_void_async() {}
+#[op]
+pub async fn op_error_async() -> Result<(), Error> {
+ Err(Error::msg("error"))
+}
+
+#[op(deferred)]
+pub async fn op_error_async_deferred() -> Result<(), Error> {
+ Err(Error::msg("error"))
+}
+
#[op(deferred)]
pub async fn op_void_async_deferred() {}
diff --git a/core/runtime.rs b/core/runtime.rs
index d88ddccac..e6c365e42 100644
--- a/core/runtime.rs
+++ b/core/runtime.rs
@@ -3738,21 +3738,6 @@ assertEquals(1, notify_return_value);
}
#[test]
- fn test_core_js_stack_frame() {
- let mut runtime = JsRuntime::new(RuntimeOptions::default());
- // Call non-existent op so we get error from `core.js`
- let error = runtime
- .execute_script_static(
- "core_js_stack_frame.js",
- "Deno.core.opAsync('non_existent');",
- )
- .unwrap_err();
- let error_string = error.to_string();
- // Test that the script specifier is a URL: `ext:<repo-relative path>`.
- assert!(error_string.contains("ext:core/01_core.js"));
- }
-
- #[test]
fn test_v8_platform() {
let options = RuntimeOptions {
v8_platform: Some(v8::new_default_platform(0, false).make_shared()),
@@ -4721,21 +4706,6 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", {
.is_ok());
}
- #[test]
- fn test_non_existent_async_op_error() {
- // Verify that "resizable ArrayBuffer" is disabled
- let mut runtime = JsRuntime::new(Default::default());
- let err = runtime
- .execute_script_static(
- "test_rab.js",
- r#"Deno.core.opAsync("this_op_doesnt_exist");"#,
- )
- .unwrap_err();
- assert!(err
- .to_string()
- .contains("this_op_doesnt_exist is not a registered op"));
- }
-
#[tokio::test]
async fn cant_load_internal_module_when_snapshot_is_loaded_and_not_snapshotting(
) {
diff --git a/ext/http/00_serve.js b/ext/http/00_serve.js
index 0b2c60538..33742e122 100644
--- a/ext/http/00_serve.js
+++ b/ext/http/00_serve.js
@@ -1,4 +1,5 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// deno-lint-ignore-file camelcase
const core = globalThis.Deno.core;
const primordials = globalThis.__bootstrap.primordials;
const internals = globalThis.__bootstrap.internals;
@@ -46,6 +47,39 @@ const {
Uint8Array,
} = primordials;
+const {
+ op_http_wait,
+ op_upgrade,
+ op_get_request_headers,
+ op_get_request_method_and_url,
+ op_read_request_body,
+ op_serve_http,
+ op_set_promise_complete,
+ op_set_response_body_bytes,
+ op_set_response_body_resource,
+ op_set_response_body_stream,
+ op_set_response_body_text,
+ op_set_response_header,
+ op_set_response_headers,
+ op_upgrade_raw,
+ op_ws_server_create,
+} = Deno.core.generateAsyncOpHandler(
+ "op_http_wait",
+ "op_upgrade",
+ "op_get_request_headers",
+ "op_get_request_method_and_url",
+ "op_read_request_body",
+ "op_serve_http",
+ "op_set_promise_complete",
+ "op_set_response_body_bytes",
+ "op_set_response_body_resource",
+ "op_set_response_body_stream",
+ "op_set_response_body_text",
+ "op_set_response_header",
+ "op_set_response_headers",
+ "op_upgrade_raw",
+ "op_ws_server_create",
+);
const _upgraded = Symbol("_upgraded");
function internalServerError() {
@@ -143,7 +177,7 @@ class InnerRequest {
this.#upgraded = () => {};
- const upgradeRid = core.ops.op_upgrade_raw(slabId);
+ const upgradeRid = op_upgrade_raw(slabId);
const conn = new TcpConn(
upgradeRid,
@@ -174,12 +208,11 @@ class InnerRequest {
(async () => {
try {
// Returns the connection and extra bytes, which we can pass directly to op_ws_server_create
- const upgrade = await core.opAsync2(
- "op_upgrade",
+ const upgrade = await op_upgrade(
slabId,
response.headerList,
);
- const wsRid = core.ops.op_ws_server_create(upgrade[0], upgrade[1]);
+ const wsRid = op_ws_server_create(upgrade[0], upgrade[1]);
// We have to wait for the go-ahead signal
await goAhead;
@@ -214,7 +247,7 @@ class InnerRequest {
}
// TODO(mmastrac): This is quite slow as we're serializing a large number of values. We may want to consider
// splitting this up into multiple ops.
- this.#methodAndUri = core.ops.op_get_request_method_and_url(this.#slabId);
+ this.#methodAndUri = op_get_request_method_and_url(this.#slabId);
}
const path = this.#methodAndUri[2];
@@ -249,7 +282,7 @@ class InnerRequest {
if (this.#slabId === undefined) {
throw new TypeError("request closed");
}
- this.#methodAndUri = core.ops.op_get_request_method_and_url(this.#slabId);
+ this.#methodAndUri = op_get_request_method_and_url(this.#slabId);
}
return {
transport: "tcp",
@@ -263,7 +296,7 @@ class InnerRequest {
if (this.#slabId === undefined) {
throw new TypeError("request closed");
}
- this.#methodAndUri = core.ops.op_get_request_method_and_url(this.#slabId);
+ this.#methodAndUri = op_get_request_method_and_url(this.#slabId);
}
return this.#methodAndUri[0];
}
@@ -281,7 +314,7 @@ class InnerRequest {
this.#body = null;
return null;
}
- this.#streamRid = core.ops.op_read_request_body(this.#slabId);
+ this.#streamRid = op_read_request_body(this.#slabId);
this.#body = new InnerBody(readableStreamForRid(this.#streamRid, false));
return this.#body;
}
@@ -290,7 +323,7 @@ class InnerRequest {
if (this.#slabId === undefined) {
throw new TypeError("request closed");
}
- return core.ops.op_get_request_headers(this.#slabId);
+ return op_get_request_headers(this.#slabId);
}
get slabId() {
@@ -331,12 +364,12 @@ function fastSyncResponseOrStream(req, respBody) {
const body = stream.body;
if (ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, body)) {
- core.ops.op_set_response_body_bytes(req, body);
+ op_set_response_body_bytes(req, body);
return null;
}
if (typeof body === "string") {
- core.ops.op_set_response_body_text(req, body);
+ op_set_response_body_text(req, body);
return null;
}
@@ -346,7 +379,7 @@ function fastSyncResponseOrStream(req, respBody) {
}
const resourceBacking = getReadableStreamResourceBacking(stream);
if (resourceBacking) {
- core.ops.op_set_response_body_resource(
+ op_set_response_body_resource(
req,
resourceBacking.rid,
resourceBacking.autoClose,
@@ -382,9 +415,9 @@ async function asyncResponse(responseBodies, req, status, stream) {
// and we race it.
let timeoutPromise;
timeout = setTimeout(() => {
- responseRid = core.ops.op_set_response_body_stream(req);
+ responseRid = op_set_response_body_stream(req);
SetPrototypeAdd(responseBodies, responseRid);
- core.ops.op_set_promise_complete(req, status);
+ op_set_promise_complete(req, status);
timeoutPromise = core.writeAll(responseRid, value1);
}, 250);
const { value: value2, done: done2 } = await reader.read();
@@ -409,13 +442,13 @@ async function asyncResponse(responseBodies, req, status, stream) {
// Reader will be closed by finally block
// No response stream
closed = true;
- core.ops.op_set_response_body_bytes(req, value1);
+ op_set_response_body_bytes(req, value1);
return;
}
- responseRid = core.ops.op_set_response_body_stream(req);
+ responseRid = op_set_response_body_stream(req);
SetPrototypeAdd(responseBodies, responseRid);
- core.ops.op_set_promise_complete(req, status);
+ op_set_promise_complete(req, status);
// Write our first packet
await core.writeAll(responseRid, value1);
}
@@ -447,7 +480,7 @@ async function asyncResponse(responseBodies, req, status, stream) {
core.tryClose(responseRid);
SetPrototypeDelete(responseBodies, responseRid);
} else {
- core.ops.op_set_promise_complete(req, status);
+ op_set_promise_complete(req, status);
}
}
}
@@ -511,9 +544,9 @@ function mapToCallback(responseBodies, context, signal, callback, onError) {
const headers = inner.headerList;
if (headers && headers.length > 0) {
if (headers.length == 1) {
- core.ops.op_set_response_header(req, headers[0][0], headers[0][1]);
+ op_set_response_header(req, headers[0][0], headers[0][1]);
} else {
- core.ops.op_set_response_headers(req, headers);
+ op_set_response_headers(req, headers);
}
}
@@ -523,7 +556,7 @@ function mapToCallback(responseBodies, context, signal, callback, onError) {
// Handle the stream asynchronously
await asyncResponse(responseBodies, req, status, stream);
} else {
- core.ops.op_set_promise_complete(req, status);
+ op_set_promise_complete(req, status);
}
innerRequest?.close();
@@ -591,13 +624,13 @@ async function serve(arg1, arg2) {
listenOpts.alpnProtocols = ["h2", "http/1.1"];
const listener = Deno.listenTls(listenOpts);
listenOpts.port = listener.addr.port;
- context.initialize(core.ops.op_serve_http(
+ context.initialize(op_serve_http(
listener.rid,
));
} else {
const listener = Deno.listen(listenOpts);
listenOpts.port = listener.addr.port;
- context.initialize(core.ops.op_serve_http(
+ context.initialize(op_serve_http(
listener.rid,
));
}
@@ -624,7 +657,7 @@ async function serve(arg1, arg2) {
const rid = context.serverRid;
let req;
try {
- req = await core.opAsync2("op_http_wait", rid);
+ req = await op_http_wait(rid);
} catch (error) {
if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error)) {
break;
diff --git a/ops/lib.rs b/ops/lib.rs
index 5a192537f..d4fa0bb82 100644
--- a/ops/lib.rs
+++ b/ops/lib.rs
@@ -144,6 +144,8 @@ impl Op {
is_unstable: #is_unstable,
is_v8: #is_v8,
force_registration: false,
+ // TODO(mmastrac)
+ arg_count: 0,
}
}
@@ -158,8 +160,8 @@ impl Op {
let has_fallible_fast_call = active && optimizer.returns_result;
- let v8_body = if is_async {
- let deferred = attrs.deferred;
+ let (v8_body, arg_count) = if is_async {
+ let deferred: bool = attrs.deferred;
codegen_v8_async(
&core,
&item,
@@ -205,6 +207,7 @@ impl Op {
is_unstable: #is_unstable,
is_v8: #is_v8,
force_registration: false,
+ arg_count: #arg_count as u8,
}
}
@@ -241,7 +244,7 @@ fn codegen_v8_async(
margs: Attributes,
asyncness: bool,
deferred: bool,
-) -> TokenStream2 {
+) -> (TokenStream2, usize) {
let Attributes { is_v8, .. } = margs;
let special_args = f
.sig
@@ -309,7 +312,7 @@ fn codegen_v8_async(
}
};
- quote! {
+ let token_stream = quote! {
use #core::futures::FutureExt;
// SAFETY: #core guarantees args.data() is a v8 External pointing to an OpCtx for the isolates lifetime
let ctx = unsafe {
@@ -336,7 +339,10 @@ fn codegen_v8_async(
if let Some(response) = maybe_response {
rv.set(response);
}
- }
+ };
+
+ // +1 arg for the promise ID
+ (token_stream, 1 + f.sig.inputs.len() - rust_i0)
}
fn scope_arg(arg: &FnArg) -> Option<TokenStream2> {
@@ -373,7 +379,7 @@ fn codegen_v8_sync(
f: &syn::ItemFn,
margs: Attributes,
has_fallible_fast_call: bool,
-) -> TokenStream2 {
+) -> (TokenStream2, usize) {
let Attributes { is_v8, .. } = margs;
let special_args = f
.sig
@@ -404,7 +410,7 @@ fn codegen_v8_sync(
quote! {}
};
- quote! {
+ let token_stream = quote! {
// SAFETY: #core guarantees args.data() is a v8 External pointing to an OpCtx for the isolates lifetime
let ctx = unsafe {
&*(#core::v8::Local::<#core::v8::External>::cast(args.data()).value()
@@ -421,7 +427,9 @@ fn codegen_v8_sync(
op_state.tracker.track_sync(ctx.id);
#ret
- }
+ };
+
+ (token_stream, f.sig.inputs.len() - rust_i0)
}
/// (full declarations, idents, v8 argument count)
diff --git a/ops/optimizer_tests/async_nop.out b/ops/optimizer_tests/async_nop.out
index d26733825..3765e611a 100644
--- a/ops/optimizer_tests/async_nop.out
+++ b/ops/optimizer_tests/async_nop.out
@@ -41,6 +41,7 @@ impl op_void_async {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/async_result.out b/ops/optimizer_tests/async_result.out
index 4494bf22a..ca6d13c2e 100644
--- a/ops/optimizer_tests/async_result.out
+++ b/ops/optimizer_tests/async_result.out
@@ -41,6 +41,7 @@ impl op_async_result {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 2usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/callback_options.out b/ops/optimizer_tests/callback_options.out
index e892e0118..656124a80 100644
--- a/ops/optimizer_tests/callback_options.out
+++ b/ops/optimizer_tests/callback_options.out
@@ -41,6 +41,7 @@ impl op_fallback {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/cow_str.out b/ops/optimizer_tests/cow_str.out
index dc909da81..ebb2108a2 100644
--- a/ops/optimizer_tests/cow_str.out
+++ b/ops/optimizer_tests/cow_str.out
@@ -41,6 +41,7 @@ impl op_cow_str {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/f64_slice.out b/ops/optimizer_tests/f64_slice.out
index 3e8ef07d8..811aee288 100644
--- a/ops/optimizer_tests/f64_slice.out
+++ b/ops/optimizer_tests/f64_slice.out
@@ -41,6 +41,7 @@ impl op_f64_buf {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/incompatible_1.out b/ops/optimizer_tests/incompatible_1.out
index 5104fb5e4..59eb600bc 100644
--- a/ops/optimizer_tests/incompatible_1.out
+++ b/ops/optimizer_tests/incompatible_1.out
@@ -31,6 +31,7 @@ impl op_sync_serialize_object_with_numbers_as_keys {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/issue16934.out b/ops/optimizer_tests/issue16934.out
index e92510038..35bd38339 100644
--- a/ops/optimizer_tests/issue16934.out
+++ b/ops/optimizer_tests/issue16934.out
@@ -31,6 +31,7 @@ impl send_stdin {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 2usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/issue16934_fast.out b/ops/optimizer_tests/issue16934_fast.out
index 2a16d1b62..1291f9cab 100644
--- a/ops/optimizer_tests/issue16934_fast.out
+++ b/ops/optimizer_tests/issue16934_fast.out
@@ -31,6 +31,7 @@ impl send_stdin {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 2usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/op_blob_revoke_object_url.out b/ops/optimizer_tests/op_blob_revoke_object_url.out
index 4eda69224..1a10a2b0a 100644
--- a/ops/optimizer_tests/op_blob_revoke_object_url.out
+++ b/ops/optimizer_tests/op_blob_revoke_object_url.out
@@ -31,6 +31,7 @@ impl op_blob_revoke_object_url {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/op_ffi_ptr_value.out b/ops/optimizer_tests/op_ffi_ptr_value.out
index 3fee00cff..f3da0dfce 100644
--- a/ops/optimizer_tests/op_ffi_ptr_value.out
+++ b/ops/optimizer_tests/op_ffi_ptr_value.out
@@ -41,6 +41,7 @@ impl op_ffi_ptr_value {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 2usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/op_print.out b/ops/optimizer_tests/op_print.out
index 7bf5457d7..e0fecd6b2 100644
--- a/ops/optimizer_tests/op_print.out
+++ b/ops/optimizer_tests/op_print.out
@@ -31,6 +31,7 @@ impl op_print {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 2usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/op_state.out b/ops/optimizer_tests/op_state.out
index cebb1e25c..300dd6fc2 100644
--- a/ops/optimizer_tests/op_state.out
+++ b/ops/optimizer_tests/op_state.out
@@ -41,6 +41,7 @@ impl op_set_exit_code {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/op_state_basic1.out b/ops/optimizer_tests/op_state_basic1.out
index d8278daca..2452e886c 100644
--- a/ops/optimizer_tests/op_state_basic1.out
+++ b/ops/optimizer_tests/op_state_basic1.out
@@ -41,6 +41,7 @@ impl foo {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 2usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/op_state_generics.out b/ops/optimizer_tests/op_state_generics.out
index 631a2142f..3faaa4bf1 100644
--- a/ops/optimizer_tests/op_state_generics.out
+++ b/ops/optimizer_tests/op_state_generics.out
@@ -47,6 +47,7 @@ impl op_foo {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 0usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/op_state_result.out b/ops/optimizer_tests/op_state_result.out
index d03ffd5a6..137eeeac0 100644
--- a/ops/optimizer_tests/op_state_result.out
+++ b/ops/optimizer_tests/op_state_result.out
@@ -41,6 +41,7 @@ impl foo {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 2usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/op_state_warning.out b/ops/optimizer_tests/op_state_warning.out
index 5548dc134..ce677f0fa 100644
--- a/ops/optimizer_tests/op_state_warning.out
+++ b/ops/optimizer_tests/op_state_warning.out
@@ -41,6 +41,7 @@ impl op_listen {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 0usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/op_state_with_transforms.out b/ops/optimizer_tests/op_state_with_transforms.out
index ad4e5335a..4347f63e4 100644
--- a/ops/optimizer_tests/op_state_with_transforms.out
+++ b/ops/optimizer_tests/op_state_with_transforms.out
@@ -47,6 +47,7 @@ impl op_now {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/opstate_with_arity.out b/ops/optimizer_tests/opstate_with_arity.out
index 037774c25..a1ae08127 100644
--- a/ops/optimizer_tests/opstate_with_arity.out
+++ b/ops/optimizer_tests/opstate_with_arity.out
@@ -41,6 +41,7 @@ impl op_add_4 {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 4usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/option_arg.out b/ops/optimizer_tests/option_arg.out
index 39d47562b..adfc8da19 100644
--- a/ops/optimizer_tests/option_arg.out
+++ b/ops/optimizer_tests/option_arg.out
@@ -31,6 +31,7 @@ impl op_try_close {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/owned_string.out b/ops/optimizer_tests/owned_string.out
index f8b195b2f..d8c0842ac 100644
--- a/ops/optimizer_tests/owned_string.out
+++ b/ops/optimizer_tests/owned_string.out
@@ -41,6 +41,7 @@ impl op_string_length {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/param_mut_binding_warning.out b/ops/optimizer_tests/param_mut_binding_warning.out
index 98dc6b2b9..e99606b37 100644
--- a/ops/optimizer_tests/param_mut_binding_warning.out
+++ b/ops/optimizer_tests/param_mut_binding_warning.out
@@ -31,6 +31,7 @@ impl op_read_sync {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 2usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/raw_ptr.out b/ops/optimizer_tests/raw_ptr.out
index 678ce5015..3eefb5e7f 100644
--- a/ops/optimizer_tests/raw_ptr.out
+++ b/ops/optimizer_tests/raw_ptr.out
@@ -52,6 +52,7 @@ impl op_ffi_ptr_of {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 2usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/serde_v8_value.out b/ops/optimizer_tests/serde_v8_value.out
index d0f8dacdf..867d89e43 100644
--- a/ops/optimizer_tests/serde_v8_value.out
+++ b/ops/optimizer_tests/serde_v8_value.out
@@ -41,6 +41,7 @@ impl op_is_proxy {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/strings.out b/ops/optimizer_tests/strings.out
index 3238bfc42..523736d70 100644
--- a/ops/optimizer_tests/strings.out
+++ b/ops/optimizer_tests/strings.out
@@ -41,6 +41,7 @@ impl op_string_length {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/strings_result.out b/ops/optimizer_tests/strings_result.out
index 8b2e2acef..aae8b356b 100644
--- a/ops/optimizer_tests/strings_result.out
+++ b/ops/optimizer_tests/strings_result.out
@@ -31,6 +31,7 @@ impl op_string_length {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/u64_result.out b/ops/optimizer_tests/u64_result.out
index 02d25686a..a0d746512 100644
--- a/ops/optimizer_tests/u64_result.out
+++ b/ops/optimizer_tests/u64_result.out
@@ -31,6 +31,7 @@ impl op_bench_now {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 0usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/uint8array.out b/ops/optimizer_tests/uint8array.out
index 93fa40e1f..124f2ac57 100644
--- a/ops/optimizer_tests/uint8array.out
+++ b/ops/optimizer_tests/uint8array.out
@@ -41,6 +41,7 @@ impl op_import_spki_x25519 {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 2usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/unit_result.out b/ops/optimizer_tests/unit_result.out
index 354a2e3b9..9a46ee087 100644
--- a/ops/optimizer_tests/unit_result.out
+++ b/ops/optimizer_tests/unit_result.out
@@ -41,6 +41,7 @@ impl op_unit_result {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 0usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/unit_result2.out b/ops/optimizer_tests/unit_result2.out
index 721229121..c2e6708a0 100644
--- a/ops/optimizer_tests/unit_result2.out
+++ b/ops/optimizer_tests/unit_result2.out
@@ -41,6 +41,7 @@ impl op_set_nodelay {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 2usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/unit_ret.out b/ops/optimizer_tests/unit_ret.out
index 7d0f63dc8..538674068 100644
--- a/ops/optimizer_tests/unit_ret.out
+++ b/ops/optimizer_tests/unit_ret.out
@@ -41,6 +41,7 @@ impl op_unit {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 0usize as u8,
}
}
#[inline]
diff --git a/ops/optimizer_tests/wasm_op.out b/ops/optimizer_tests/wasm_op.out
index 0196f4548..cc8e3b847 100644
--- a/ops/optimizer_tests/wasm_op.out
+++ b/ops/optimizer_tests/wasm_op.out
@@ -41,6 +41,7 @@ impl op_wasm {
is_unstable: false,
is_v8: false,
force_registration: false,
+ arg_count: 1usize as u8,
}
}
#[inline]