mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
perf(core): async op pseudo-codegen and performance work (#18887)
Performance: ``` async_ops.js: 760k -> 1030k (!) async_ops_deferred.js: 730k -> 770k Deno.serve bench: 118k -> 124k WS test w/ third_party/prebuilt/mac/load_test 100 localhost 8000 0 0: unchanged Startup time: approx 0.5ms slower (13.7 -> 14.2ms) ```
This commit is contained in:
parent
9c8ebce3dc
commit
bb1f5e4262
45 changed files with 737 additions and 237 deletions
|
@ -17,4 +17,6 @@ async function bench(fun) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const core = Deno[Deno.internal].core;
|
const core = Deno[Deno.internal].core;
|
||||||
bench(() => core.opAsync("op_void_async"));
|
const ops = core.ops;
|
||||||
|
const opVoidAsync = ops.op_void_async;
|
||||||
|
bench(() => opVoidAsync());
|
||||||
|
|
|
@ -17,4 +17,6 @@ async function bench(fun) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const core = Deno[Deno.internal].core;
|
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());
|
||||||
|
|
|
@ -80,12 +80,14 @@ Deno.test(function metricsForOpCrates() {
|
||||||
// Test that op_names == Objects.keys(Deno[Deno.internal].core.ops)
|
// Test that op_names == Objects.keys(Deno[Deno.internal].core.ops)
|
||||||
// since building the per-op metrics depends on op_names being complete
|
// since building the per-op metrics depends on op_names being complete
|
||||||
Deno.test(function opNamesMatch() {
|
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(
|
assertEquals(
|
||||||
// @ts-ignore: Deno[Deno.internal].core allowed
|
// @ts-ignore: Deno[Deno.internal].core allowed
|
||||||
Deno[Deno.internal].core.opNames().sort(),
|
Deno[Deno.internal].core.opNames().sort(),
|
||||||
// @ts-ignore: Deno[Deno.internal].core allowed
|
ops.sort().filter((name) => name !== "asyncOpsInfo"),
|
||||||
Object.keys(Deno[Deno.internal].core.ops).sort().filter((name) =>
|
|
||||||
name !== "asyncOpsInfo"
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
// 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";
|
import { assert, assertStringIncludes, unreachable } from "./test_util.ts";
|
||||||
|
|
||||||
Deno.test(async function sendAsyncStackTrace() {
|
Deno.test(async function sendAsyncStackTrace() {
|
||||||
const buf = new Uint8Array(10);
|
|
||||||
const rid = 10;
|
|
||||||
try {
|
try {
|
||||||
await Deno.read(rid, buf);
|
await core.ops.op_error_async();
|
||||||
unreachable();
|
unreachable();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
assert(error instanceof Error);
|
assert(error instanceof Error);
|
||||||
const s = error.stack?.toString();
|
const s = error.stack?.toString();
|
||||||
assert(s);
|
assert(s);
|
||||||
console.log(s);
|
|
||||||
assertStringIncludes(s, "opcall_test.ts");
|
assertStringIncludes(s, "opcall_test.ts");
|
||||||
assertStringIncludes(s, "read");
|
assertStringIncludes(s, "sendAsyncStackTrace");
|
||||||
assert(
|
assert(
|
||||||
!s.includes("ext:core"),
|
!s.includes("ext:core"),
|
||||||
"opcall stack traces should NOT include ext:core internals such as unwrapOpResult",
|
"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.
|
// @ts-ignore This is not publicly typed namespace, but it's there for sure.
|
||||||
const core = Deno[Deno.internal].core;
|
const core = Deno[Deno.internal].core;
|
||||||
|
|
||||||
|
|
2
cli/tsc/compiler.d.ts
vendored
2
cli/tsc/compiler.d.ts
vendored
|
@ -46,6 +46,8 @@ declare global {
|
||||||
encode(value: string): Uint8Array;
|
encode(value: string): Uint8Array;
|
||||||
// deno-lint-ignore no-explicit-any
|
// deno-lint-ignore no-explicit-any
|
||||||
ops: Record<string, (...args: unknown[]) => 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;
|
print(msg: string, stderr: boolean): void;
|
||||||
registerErrorClass(
|
registerErrorClass(
|
||||||
name: string,
|
name: string,
|
||||||
|
|
469
core/01_core.js
469
core/01_core.js
|
@ -16,11 +16,15 @@
|
||||||
ObjectAssign,
|
ObjectAssign,
|
||||||
ObjectFreeze,
|
ObjectFreeze,
|
||||||
ObjectFromEntries,
|
ObjectFromEntries,
|
||||||
|
ObjectKeys,
|
||||||
Promise,
|
Promise,
|
||||||
|
PromiseReject,
|
||||||
|
PromiseResolve,
|
||||||
PromisePrototypeThen,
|
PromisePrototypeThen,
|
||||||
RangeError,
|
RangeError,
|
||||||
ReferenceError,
|
ReferenceError,
|
||||||
ReflectHas,
|
ReflectHas,
|
||||||
|
ReflectApply,
|
||||||
SafeArrayIterator,
|
SafeArrayIterator,
|
||||||
SafeMap,
|
SafeMap,
|
||||||
SafePromisePrototypeFinally,
|
SafePromisePrototypeFinally,
|
||||||
|
@ -32,7 +36,7 @@
|
||||||
TypeError,
|
TypeError,
|
||||||
URIError,
|
URIError,
|
||||||
} = window.__bootstrap.primordials;
|
} = window.__bootstrap.primordials;
|
||||||
const { ops } = window.Deno.core;
|
const { ops, asyncOps } = window.Deno.core;
|
||||||
|
|
||||||
const build = {
|
const build = {
|
||||||
target: "unknown",
|
target: "unknown",
|
||||||
|
@ -85,6 +89,17 @@
|
||||||
return opCallTracingEnabled;
|
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) {
|
function setPromise(promiseId) {
|
||||||
const idx = promiseId % RING_SIZE;
|
const idx = promiseId % RING_SIZE;
|
||||||
// Move old promise from ring to map
|
// Move old promise from ring to map
|
||||||
|
@ -208,7 +223,29 @@
|
||||||
return error;
|
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
|
// .$err_class_name is a special key that should only exist on errors
|
||||||
if (res?.$err_class_name) {
|
if (res?.$err_class_name) {
|
||||||
const className = res.$err_class_name;
|
const className = res.$err_class_name;
|
||||||
|
@ -221,59 +258,359 @@
|
||||||
err.code = res.code;
|
err.code = res.code;
|
||||||
}
|
}
|
||||||
// Strip unwrapOpResult() and errorBuilder() calls from stack trace
|
// Strip unwrapOpResult() and errorBuilder() calls from stack trace
|
||||||
ErrorCaptureStackTrace(err, unwrapOpResult);
|
ErrorCaptureStackTrace(err, hideFunction);
|
||||||
throw err;
|
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) {
|
function opAsync2(name, arg0, arg1) {
|
||||||
const id = nextPromiseId++;
|
const id = nextPromiseId++;
|
||||||
let promise = PromisePrototypeThen(setPromise(id), unwrapOpResult);
|
|
||||||
let maybeResult;
|
|
||||||
try {
|
try {
|
||||||
maybeResult = ops[name](id, arg0, arg1);
|
const maybeResult = asyncOps[name](id, arg0, arg1);
|
||||||
} catch (err) {
|
if (maybeResult !== undefined) {
|
||||||
// Cleanup the just-created promise
|
movePromise(id);
|
||||||
getPromise(id);
|
return unwrapOpResultNewPromise(id, maybeResult, opAsync2);
|
||||||
if (!ReflectHas(ops, name)) {
|
|
||||||
throw new TypeError(`${name} is not a registered op`);
|
|
||||||
}
|
}
|
||||||
// Rethrow the error
|
} catch (err) {
|
||||||
throw err;
|
movePromise(id);
|
||||||
|
if (!ReflectHas(asyncOps, name)) {
|
||||||
|
return PromiseReject(new TypeError(`${name} is not a registered op`));
|
||||||
|
}
|
||||||
|
ErrorCaptureStackTrace(err, opAsync2);
|
||||||
|
return PromiseReject(err);
|
||||||
}
|
}
|
||||||
|
let promise = PromisePrototypeThen(
|
||||||
|
setPromise(id),
|
||||||
|
unwrapOpError(eventLoopTick),
|
||||||
|
);
|
||||||
promise = handleOpCallTracing(name, id, promise);
|
promise = handleOpCallTracing(name, id, promise);
|
||||||
promise[promiseIdSymbol] = id;
|
promise[promiseIdSymbol] = id;
|
||||||
if (typeof maybeResult !== "undefined") {
|
|
||||||
const promise = getPromise(id);
|
|
||||||
promise.resolve(maybeResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
function opAsync(name, ...args) {
|
function opAsync(name, ...args) {
|
||||||
const id = nextPromiseId++;
|
const id = nextPromiseId++;
|
||||||
let promise = PromisePrototypeThen(setPromise(id), unwrapOpResult);
|
|
||||||
let maybeResult;
|
|
||||||
try {
|
try {
|
||||||
maybeResult = ops[name](id, ...new SafeArrayIterator(args));
|
const maybeResult = asyncOps[name](id, ...new SafeArrayIterator(args));
|
||||||
} catch (err) {
|
if (maybeResult !== undefined) {
|
||||||
// Cleanup the just-created promise
|
movePromise(id);
|
||||||
getPromise(id);
|
return unwrapOpResultNewPromise(id, maybeResult, opAsync);
|
||||||
if (!ReflectHas(ops, name)) {
|
|
||||||
throw new TypeError(`${name} is not a registered op`);
|
|
||||||
}
|
}
|
||||||
// Rethrow the error
|
} catch (err) {
|
||||||
throw err;
|
movePromise(id);
|
||||||
|
if (!ReflectHas(asyncOps, name)) {
|
||||||
|
return PromiseReject(new TypeError(`${name} is not a registered op`));
|
||||||
|
}
|
||||||
|
ErrorCaptureStackTrace(err, opAsync);
|
||||||
|
return PromiseReject(err);
|
||||||
}
|
}
|
||||||
|
let promise = PromisePrototypeThen(
|
||||||
|
setPromise(id),
|
||||||
|
unwrapOpError(eventLoopTick),
|
||||||
|
);
|
||||||
promise = handleOpCallTracing(name, id, promise);
|
promise = handleOpCallTracing(name, id, promise);
|
||||||
promise[promiseIdSymbol] = id;
|
promise[promiseIdSymbol] = id;
|
||||||
if (typeof maybeResult !== "undefined") {
|
|
||||||
const promise = getPromise(id);
|
|
||||||
promise.resolve(maybeResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
return promise;
|
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
|
// Extra Deno.core.* exports
|
||||||
const core = ObjectAssign(globalThis.Deno.core, {
|
const core = ObjectAssign(globalThis.Deno.core, {
|
||||||
|
asyncStub,
|
||||||
|
generateAsyncOpHandler,
|
||||||
opAsync,
|
opAsync,
|
||||||
opAsync2,
|
opAsync2,
|
||||||
resources,
|
resources,
|
||||||
|
@ -460,15 +841,15 @@
|
||||||
unrefOp,
|
unrefOp,
|
||||||
setReportExceptionCallback,
|
setReportExceptionCallback,
|
||||||
setPromiseHooks,
|
setPromiseHooks,
|
||||||
close: (rid) => ops.op_close(rid),
|
close,
|
||||||
tryClose: (rid) => ops.op_try_close(rid),
|
tryClose,
|
||||||
read: opAsync.bind(null, "op_read"),
|
read,
|
||||||
readAll: opAsync.bind(null, "op_read_all"),
|
readAll,
|
||||||
write: opAsync.bind(null, "op_write"),
|
write,
|
||||||
writeAll: opAsync.bind(null, "op_write_all"),
|
writeAll,
|
||||||
readSync: (rid, buffer) => ops.op_read_sync(rid, buffer),
|
readSync,
|
||||||
writeSync: (rid, buffer) => ops.op_write_sync(rid, buffer),
|
writeSync,
|
||||||
shutdown: opAsync.bind(null, "op_shutdown"),
|
shutdown,
|
||||||
print: (msg, isErr) => ops.op_print(msg, isErr),
|
print: (msg, isErr) => ops.op_print(msg, isErr),
|
||||||
setMacrotaskCallback,
|
setMacrotaskCallback,
|
||||||
setNextTickCallback,
|
setNextTickCallback,
|
||||||
|
|
49
core/bindings.js
Normal file
49
core/bindings.js
Normal file
|
@ -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;
|
||||||
|
};
|
210
core/bindings.rs
210
core/bindings.rs
|
@ -1,9 +1,9 @@
|
||||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use log::debug;
|
||||||
|
use std::fmt::Write;
|
||||||
use std::option::Option;
|
use std::option::Option;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
use log::debug;
|
|
||||||
use v8::MapFnTo;
|
use v8::MapFnTo;
|
||||||
|
|
||||||
use crate::error::is_instance_of_error;
|
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>(
|
pub(crate) fn initialize_context<'s>(
|
||||||
scope: &mut v8::HandleScope<'s, ()>,
|
scope: &mut v8::HandleScope<'s, ()>,
|
||||||
op_ctxs: &[OpCtx],
|
op_ctxs: &[OpCtx],
|
||||||
|
@ -108,135 +125,92 @@ pub(crate) fn initialize_context<'s>(
|
||||||
|
|
||||||
let scope = &mut v8::ContextScope::new(scope, context);
|
let scope = &mut v8::ContextScope::new(scope, context);
|
||||||
|
|
||||||
let deno_str =
|
let mut codegen = String::with_capacity(op_ctxs.len() * 200);
|
||||||
v8::String::new_external_onebyte_static(scope, b"Deno").unwrap();
|
codegen.push_str(include_str!("bindings.js"));
|
||||||
let core_str =
|
_ = writeln!(
|
||||||
v8::String::new_external_onebyte_static(scope, b"core").unwrap();
|
codegen,
|
||||||
let ops_str = v8::String::new_external_onebyte_static(scope, b"ops").unwrap();
|
"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 ops_obj = if snapshot_options.loaded() {
|
let script = v8::String::new_from_one_byte(
|
||||||
// Snapshot already registered `Deno.core.ops` but
|
scope,
|
||||||
// extensions may provide ops that aren't part of the snapshot.
|
codegen.as_bytes(),
|
||||||
// Grab the Deno.core.ops object & init it
|
v8::NewStringType::Normal,
|
||||||
let deno_obj: v8::Local<v8::Object> = global
|
)
|
||||||
.get(scope, deno_str.into())
|
.unwrap();
|
||||||
.unwrap()
|
let script = v8::Script::compile(scope, script, None).unwrap();
|
||||||
.try_into()
|
script.run(scope);
|
||||||
.unwrap();
|
|
||||||
let core_obj: v8::Local<v8::Object> = deno_obj
|
let deno = get(scope, global, b"Deno", "Deno");
|
||||||
.get(scope, core_str.into())
|
let op_fn: v8::Local<v8::Function> =
|
||||||
.unwrap()
|
get(scope, deno, b"__op__", "Deno.__op__");
|
||||||
.try_into()
|
let recv = v8::undefined(scope);
|
||||||
.unwrap();
|
let op_fns = v8::Array::new(scope, op_ctxs.len() as i32);
|
||||||
let ops_obj: v8::Local<v8::Object> = core_obj
|
for op_ctx in op_ctxs {
|
||||||
.get(scope, ops_str.into())
|
let op_fn = op_ctx_function(scope, op_ctx);
|
||||||
.expect("Deno.core.ops to exist")
|
op_fns.set_index(scope, op_ctx.id as u32, op_fn.into());
|
||||||
.try_into()
|
}
|
||||||
.unwrap();
|
if snapshot_options.loaded() {
|
||||||
ops_obj
|
op_fn.call(scope, recv.into(), &[op_fns.into()]);
|
||||||
} else {
|
} 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());
|
|
||||||
|
|
||||||
// Bind functions to Deno.core.*
|
// 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
|
// Bind v8 console object to Deno.core.console
|
||||||
let extra_binding_obj = context.get_extras_binding_object(scope);
|
let extra_binding_obj = context.get_extras_binding_object(scope);
|
||||||
let console_str =
|
let console_obj: v8::Local<v8::Object> = get(
|
||||||
v8::String::new_external_onebyte_static(scope, b"console").unwrap();
|
scope,
|
||||||
let console_obj = extra_binding_obj.get(scope, console_str.into()).unwrap();
|
extra_binding_obj,
|
||||||
core_obj.set(scope, console_str.into(), console_obj);
|
b"console",
|
||||||
|
"ExtrasBindingObject.console",
|
||||||
|
);
|
||||||
|
|
||||||
// Bind functions to Deno.core.ops.*
|
op_fn.call(
|
||||||
let ops_obj = v8::Object::new(scope);
|
scope,
|
||||||
core_obj.set(scope, ops_str.into(), ops_obj.into());
|
recv.into(),
|
||||||
ops_obj
|
&[op_fns.into(), call_console_fn.into(), console_obj.into()],
|
||||||
};
|
);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context
|
context
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_func(
|
fn op_ctx_function<'s>(
|
||||||
scope: &mut v8::HandleScope<'_>,
|
scope: &mut v8::HandleScope<'s>,
|
||||||
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,
|
op_ctx: &OpCtx,
|
||||||
) {
|
) -> v8::Local<'s, v8::Function> {
|
||||||
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>,
|
|
||||||
op_ctx: &OpCtx,
|
|
||||||
) {
|
|
||||||
let op_ctx_ptr = op_ctx as *const OpCtx as *const c_void;
|
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 external = v8::External::new(scope, op_ctx_ptr as *mut c_void);
|
||||||
let builder = v8::FunctionTemplate::builder_raw(op_ctx.decl.v8_fn_ptr)
|
let builder: v8::FunctionBuilder<v8::FunctionTemplate> =
|
||||||
.data(external.into());
|
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 {
|
let templ = if let Some(fast_function) = &op_ctx.decl.fast_fn {
|
||||||
builder.build_fast(
|
builder.build_fast(
|
||||||
|
@ -249,9 +223,7 @@ fn add_op_to_deno_core_ops(
|
||||||
} else {
|
} else {
|
||||||
builder.build(scope)
|
builder.build(scope)
|
||||||
};
|
};
|
||||||
let val = templ.get_function(scope).unwrap();
|
templ.get_function(scope).unwrap()
|
||||||
val.set_name(key);
|
|
||||||
obj.set(scope, key.into(), val.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn wasm_async_resolve_promise_callback(
|
pub extern "C" fn wasm_async_resolve_promise_callback(
|
||||||
|
|
|
@ -73,6 +73,7 @@ pub struct OpDecl {
|
||||||
pub is_unstable: bool,
|
pub is_unstable: bool,
|
||||||
pub is_v8: bool,
|
pub is_v8: bool,
|
||||||
pub force_registration: bool,
|
pub force_registration: bool,
|
||||||
|
pub arg_count: u8,
|
||||||
pub fast_fn: Option<FastFunction>,
|
pub fast_fn: Option<FastFunction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
8
core/lib.deno_core.d.ts
vendored
8
core/lib.deno_core.d.ts
vendored
|
@ -23,10 +23,16 @@ declare namespace Deno {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of all registered ops, in the form of a map that maps op
|
* 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>;
|
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
|
* Retrieve a list of all open resources, in the form of a map that maps
|
||||||
* resource id to the resource name.
|
* resource id to the resource name.
|
||||||
|
|
|
@ -27,9 +27,12 @@ crate::extension!(
|
||||||
op_wasm_streaming_feed,
|
op_wasm_streaming_feed,
|
||||||
op_wasm_streaming_set_url,
|
op_wasm_streaming_set_url,
|
||||||
op_void_sync,
|
op_void_sync,
|
||||||
|
op_error_async,
|
||||||
|
op_error_async_deferred,
|
||||||
op_void_async,
|
op_void_async,
|
||||||
op_void_async_deferred,
|
op_void_async_deferred,
|
||||||
op_add,
|
op_add,
|
||||||
|
op_add_async,
|
||||||
// TODO(@AaronO): track IO metrics for builtin streams
|
// TODO(@AaronO): track IO metrics for builtin streams
|
||||||
op_read,
|
op_read,
|
||||||
op_read_all,
|
op_read_all,
|
||||||
|
@ -96,12 +99,27 @@ fn op_add(a: i32, b: i32) -> i32 {
|
||||||
a + b
|
a + b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[op]
|
||||||
|
pub async fn op_add_async(a: i32, b: i32) -> i32 {
|
||||||
|
a + b
|
||||||
|
}
|
||||||
|
|
||||||
#[op(fast)]
|
#[op(fast)]
|
||||||
pub fn op_void_sync() {}
|
pub fn op_void_sync() {}
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
pub async fn op_void_async() {}
|
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)]
|
#[op(deferred)]
|
||||||
pub async fn op_void_async_deferred() {}
|
pub async fn op_void_async_deferred() {}
|
||||||
|
|
||||||
|
|
|
@ -3737,21 +3737,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]
|
#[test]
|
||||||
fn test_v8_platform() {
|
fn test_v8_platform() {
|
||||||
let options = RuntimeOptions {
|
let options = RuntimeOptions {
|
||||||
|
@ -4721,21 +4706,6 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", {
|
||||||
.is_ok());
|
.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]
|
#[tokio::test]
|
||||||
async fn cant_load_internal_module_when_snapshot_is_loaded_and_not_snapshotting(
|
async fn cant_load_internal_module_when_snapshot_is_loaded_and_not_snapshotting(
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||||
|
// deno-lint-ignore-file camelcase
|
||||||
const core = globalThis.Deno.core;
|
const core = globalThis.Deno.core;
|
||||||
const primordials = globalThis.__bootstrap.primordials;
|
const primordials = globalThis.__bootstrap.primordials;
|
||||||
const internals = globalThis.__bootstrap.internals;
|
const internals = globalThis.__bootstrap.internals;
|
||||||
|
@ -46,6 +47,39 @@ const {
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
} = primordials;
|
} = 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");
|
const _upgraded = Symbol("_upgraded");
|
||||||
|
|
||||||
function internalServerError() {
|
function internalServerError() {
|
||||||
|
@ -143,7 +177,7 @@ class InnerRequest {
|
||||||
|
|
||||||
this.#upgraded = () => {};
|
this.#upgraded = () => {};
|
||||||
|
|
||||||
const upgradeRid = core.ops.op_upgrade_raw(slabId);
|
const upgradeRid = op_upgrade_raw(slabId);
|
||||||
|
|
||||||
const conn = new TcpConn(
|
const conn = new TcpConn(
|
||||||
upgradeRid,
|
upgradeRid,
|
||||||
|
@ -174,12 +208,11 @@ class InnerRequest {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
// Returns the connection and extra bytes, which we can pass directly to op_ws_server_create
|
// Returns the connection and extra bytes, which we can pass directly to op_ws_server_create
|
||||||
const upgrade = await core.opAsync2(
|
const upgrade = await op_upgrade(
|
||||||
"op_upgrade",
|
|
||||||
slabId,
|
slabId,
|
||||||
response.headerList,
|
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
|
// We have to wait for the go-ahead signal
|
||||||
await goAhead;
|
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
|
// 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.
|
// 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];
|
const path = this.#methodAndUri[2];
|
||||||
|
@ -249,7 +282,7 @@ class InnerRequest {
|
||||||
if (this.#slabId === undefined) {
|
if (this.#slabId === undefined) {
|
||||||
throw new TypeError("request closed");
|
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 {
|
return {
|
||||||
transport: "tcp",
|
transport: "tcp",
|
||||||
|
@ -263,7 +296,7 @@ class InnerRequest {
|
||||||
if (this.#slabId === undefined) {
|
if (this.#slabId === undefined) {
|
||||||
throw new TypeError("request closed");
|
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];
|
return this.#methodAndUri[0];
|
||||||
}
|
}
|
||||||
|
@ -281,7 +314,7 @@ class InnerRequest {
|
||||||
this.#body = null;
|
this.#body = null;
|
||||||
return 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));
|
this.#body = new InnerBody(readableStreamForRid(this.#streamRid, false));
|
||||||
return this.#body;
|
return this.#body;
|
||||||
}
|
}
|
||||||
|
@ -290,7 +323,7 @@ class InnerRequest {
|
||||||
if (this.#slabId === undefined) {
|
if (this.#slabId === undefined) {
|
||||||
throw new TypeError("request closed");
|
throw new TypeError("request closed");
|
||||||
}
|
}
|
||||||
return core.ops.op_get_request_headers(this.#slabId);
|
return op_get_request_headers(this.#slabId);
|
||||||
}
|
}
|
||||||
|
|
||||||
get slabId() {
|
get slabId() {
|
||||||
|
@ -331,12 +364,12 @@ function fastSyncResponseOrStream(req, respBody) {
|
||||||
const body = stream.body;
|
const body = stream.body;
|
||||||
|
|
||||||
if (ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, body)) {
|
if (ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, body)) {
|
||||||
core.ops.op_set_response_body_bytes(req, body);
|
op_set_response_body_bytes(req, body);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof body === "string") {
|
if (typeof body === "string") {
|
||||||
core.ops.op_set_response_body_text(req, body);
|
op_set_response_body_text(req, body);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,7 +379,7 @@ function fastSyncResponseOrStream(req, respBody) {
|
||||||
}
|
}
|
||||||
const resourceBacking = getReadableStreamResourceBacking(stream);
|
const resourceBacking = getReadableStreamResourceBacking(stream);
|
||||||
if (resourceBacking) {
|
if (resourceBacking) {
|
||||||
core.ops.op_set_response_body_resource(
|
op_set_response_body_resource(
|
||||||
req,
|
req,
|
||||||
resourceBacking.rid,
|
resourceBacking.rid,
|
||||||
resourceBacking.autoClose,
|
resourceBacking.autoClose,
|
||||||
|
@ -382,9 +415,9 @@ async function asyncResponse(responseBodies, req, status, stream) {
|
||||||
// and we race it.
|
// and we race it.
|
||||||
let timeoutPromise;
|
let timeoutPromise;
|
||||||
timeout = setTimeout(() => {
|
timeout = setTimeout(() => {
|
||||||
responseRid = core.ops.op_set_response_body_stream(req);
|
responseRid = op_set_response_body_stream(req);
|
||||||
SetPrototypeAdd(responseBodies, responseRid);
|
SetPrototypeAdd(responseBodies, responseRid);
|
||||||
core.ops.op_set_promise_complete(req, status);
|
op_set_promise_complete(req, status);
|
||||||
timeoutPromise = core.writeAll(responseRid, value1);
|
timeoutPromise = core.writeAll(responseRid, value1);
|
||||||
}, 250);
|
}, 250);
|
||||||
const { value: value2, done: done2 } = await reader.read();
|
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
|
// Reader will be closed by finally block
|
||||||
// No response stream
|
// No response stream
|
||||||
closed = true;
|
closed = true;
|
||||||
core.ops.op_set_response_body_bytes(req, value1);
|
op_set_response_body_bytes(req, value1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
responseRid = core.ops.op_set_response_body_stream(req);
|
responseRid = op_set_response_body_stream(req);
|
||||||
SetPrototypeAdd(responseBodies, responseRid);
|
SetPrototypeAdd(responseBodies, responseRid);
|
||||||
core.ops.op_set_promise_complete(req, status);
|
op_set_promise_complete(req, status);
|
||||||
// Write our first packet
|
// Write our first packet
|
||||||
await core.writeAll(responseRid, value1);
|
await core.writeAll(responseRid, value1);
|
||||||
}
|
}
|
||||||
|
@ -447,7 +480,7 @@ async function asyncResponse(responseBodies, req, status, stream) {
|
||||||
core.tryClose(responseRid);
|
core.tryClose(responseRid);
|
||||||
SetPrototypeDelete(responseBodies, responseRid);
|
SetPrototypeDelete(responseBodies, responseRid);
|
||||||
} else {
|
} 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;
|
const headers = inner.headerList;
|
||||||
if (headers && headers.length > 0) {
|
if (headers && headers.length > 0) {
|
||||||
if (headers.length == 1) {
|
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 {
|
} 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
|
// Handle the stream asynchronously
|
||||||
await asyncResponse(responseBodies, req, status, stream);
|
await asyncResponse(responseBodies, req, status, stream);
|
||||||
} else {
|
} else {
|
||||||
core.ops.op_set_promise_complete(req, status);
|
op_set_promise_complete(req, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
innerRequest?.close();
|
innerRequest?.close();
|
||||||
|
@ -591,13 +624,13 @@ async function serve(arg1, arg2) {
|
||||||
listenOpts.alpnProtocols = ["h2", "http/1.1"];
|
listenOpts.alpnProtocols = ["h2", "http/1.1"];
|
||||||
const listener = Deno.listenTls(listenOpts);
|
const listener = Deno.listenTls(listenOpts);
|
||||||
listenOpts.port = listener.addr.port;
|
listenOpts.port = listener.addr.port;
|
||||||
context.initialize(core.ops.op_serve_http(
|
context.initialize(op_serve_http(
|
||||||
listener.rid,
|
listener.rid,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
const listener = Deno.listen(listenOpts);
|
const listener = Deno.listen(listenOpts);
|
||||||
listenOpts.port = listener.addr.port;
|
listenOpts.port = listener.addr.port;
|
||||||
context.initialize(core.ops.op_serve_http(
|
context.initialize(op_serve_http(
|
||||||
listener.rid,
|
listener.rid,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -624,7 +657,7 @@ async function serve(arg1, arg2) {
|
||||||
const rid = context.serverRid;
|
const rid = context.serverRid;
|
||||||
let req;
|
let req;
|
||||||
try {
|
try {
|
||||||
req = await core.opAsync2("op_http_wait", rid);
|
req = await op_http_wait(rid);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error)) {
|
if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error)) {
|
||||||
break;
|
break;
|
||||||
|
|
24
ops/lib.rs
24
ops/lib.rs
|
@ -144,6 +144,8 @@ impl Op {
|
||||||
is_unstable: #is_unstable,
|
is_unstable: #is_unstable,
|
||||||
is_v8: #is_v8,
|
is_v8: #is_v8,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
// TODO(mmastrac)
|
||||||
|
arg_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,8 +160,8 @@ impl Op {
|
||||||
|
|
||||||
let has_fallible_fast_call = active && optimizer.returns_result;
|
let has_fallible_fast_call = active && optimizer.returns_result;
|
||||||
|
|
||||||
let v8_body = if is_async {
|
let (v8_body, arg_count) = if is_async {
|
||||||
let deferred = attrs.deferred;
|
let deferred: bool = attrs.deferred;
|
||||||
codegen_v8_async(
|
codegen_v8_async(
|
||||||
&core,
|
&core,
|
||||||
&item,
|
&item,
|
||||||
|
@ -205,6 +207,7 @@ impl Op {
|
||||||
is_unstable: #is_unstable,
|
is_unstable: #is_unstable,
|
||||||
is_v8: #is_v8,
|
is_v8: #is_v8,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: #arg_count as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +244,7 @@ fn codegen_v8_async(
|
||||||
margs: Attributes,
|
margs: Attributes,
|
||||||
asyncness: bool,
|
asyncness: bool,
|
||||||
deferred: bool,
|
deferred: bool,
|
||||||
) -> TokenStream2 {
|
) -> (TokenStream2, usize) {
|
||||||
let Attributes { is_v8, .. } = margs;
|
let Attributes { is_v8, .. } = margs;
|
||||||
let special_args = f
|
let special_args = f
|
||||||
.sig
|
.sig
|
||||||
|
@ -309,7 +312,7 @@ fn codegen_v8_async(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
let token_stream = quote! {
|
||||||
use #core::futures::FutureExt;
|
use #core::futures::FutureExt;
|
||||||
// SAFETY: #core guarantees args.data() is a v8 External pointing to an OpCtx for the isolates lifetime
|
// SAFETY: #core guarantees args.data() is a v8 External pointing to an OpCtx for the isolates lifetime
|
||||||
let ctx = unsafe {
|
let ctx = unsafe {
|
||||||
|
@ -336,7 +339,10 @@ fn codegen_v8_async(
|
||||||
if let Some(response) = maybe_response {
|
if let Some(response) = maybe_response {
|
||||||
rv.set(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> {
|
fn scope_arg(arg: &FnArg) -> Option<TokenStream2> {
|
||||||
|
@ -373,7 +379,7 @@ fn codegen_v8_sync(
|
||||||
f: &syn::ItemFn,
|
f: &syn::ItemFn,
|
||||||
margs: Attributes,
|
margs: Attributes,
|
||||||
has_fallible_fast_call: bool,
|
has_fallible_fast_call: bool,
|
||||||
) -> TokenStream2 {
|
) -> (TokenStream2, usize) {
|
||||||
let Attributes { is_v8, .. } = margs;
|
let Attributes { is_v8, .. } = margs;
|
||||||
let special_args = f
|
let special_args = f
|
||||||
.sig
|
.sig
|
||||||
|
@ -404,7 +410,7 @@ fn codegen_v8_sync(
|
||||||
quote! {}
|
quote! {}
|
||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
let token_stream = quote! {
|
||||||
// SAFETY: #core guarantees args.data() is a v8 External pointing to an OpCtx for the isolates lifetime
|
// SAFETY: #core guarantees args.data() is a v8 External pointing to an OpCtx for the isolates lifetime
|
||||||
let ctx = unsafe {
|
let ctx = unsafe {
|
||||||
&*(#core::v8::Local::<#core::v8::External>::cast(args.data()).value()
|
&*(#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);
|
op_state.tracker.track_sync(ctx.id);
|
||||||
|
|
||||||
#ret
|
#ret
|
||||||
}
|
};
|
||||||
|
|
||||||
|
(token_stream, f.sig.inputs.len() - rust_i0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (full declarations, idents, v8 argument count)
|
/// (full declarations, idents, v8 argument count)
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_void_async {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_async_result {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 2usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_fallback {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_cow_str {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_f64_buf {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -31,6 +31,7 @@ impl op_sync_serialize_object_with_numbers_as_keys {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -31,6 +31,7 @@ impl send_stdin {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 2usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -31,6 +31,7 @@ impl send_stdin {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 2usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -31,6 +31,7 @@ impl op_blob_revoke_object_url {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_ffi_ptr_value {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 2usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -31,6 +31,7 @@ impl op_print {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 2usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_set_exit_code {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl foo {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 2usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -47,6 +47,7 @@ impl op_foo {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 0usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl foo {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 2usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_listen {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 0usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -47,6 +47,7 @@ impl op_now {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_add_4 {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 4usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -31,6 +31,7 @@ impl op_try_close {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_string_length {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -31,6 +31,7 @@ impl op_read_sync {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 2usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -52,6 +52,7 @@ impl op_ffi_ptr_of {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 2usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_is_proxy {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_string_length {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -31,6 +31,7 @@ impl op_string_length {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -31,6 +31,7 @@ impl op_bench_now {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 0usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_import_spki_x25519 {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 2usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_unit_result {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 0usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_set_nodelay {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 2usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_unit {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 0usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl op_wasm {
|
||||||
is_unstable: false,
|
is_unstable: false,
|
||||||
is_v8: false,
|
is_v8: false,
|
||||||
force_registration: false,
|
force_registration: false,
|
||||||
|
arg_count: 1usize as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
Loading…
Reference in a new issue