From dcf391ffed3850f9026d88b146e156375c4619d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Mon, 1 May 2023 17:40:00 +0200 Subject: [PATCH] refactor: migrate async ops to generated wrappers (#18937) Migrates some of existing async ops to generated wrappers introduced in https://github.com/denoland/deno/pull/18887. As a result "core.opAsync2" was removed. I will follow up with more PRs that migrate all the async ops to generated wrappers. --- core/01_core.js | 26 --------- .../http_bench_json_ops.js | 32 +++++------ core/runtime.rs | 4 +- ext/fs/30_fs.js | 25 +++++++-- ext/http/00_serve.js | 2 +- ext/http/01_http.js | 6 ++- ext/node/polyfills/internal/crypto/random.ts | 19 +++++-- ext/web/02_timers.js | 6 ++- ext/websocket/01_websocket.js | 53 ++++++++++--------- ext/websocket/02_websocketstream.js | 35 +++++++----- 10 files changed, 109 insertions(+), 99 deletions(-) diff --git a/core/01_core.js b/core/01_core.js index 72cbe31f71..403a04297a 100644 --- a/core/01_core.js +++ b/core/01_core.js @@ -564,31 +564,6 @@ for (let i = 0; i < 10; i++) { return (ops[opName] = fn); } - function opAsync2(name, arg0, arg1) { - const id = nextPromiseId++; - try { - const maybeResult = asyncOps[name](id, arg0, arg1); - if (maybeResult !== undefined) { - movePromise(id); - return unwrapOpResultNewPromise(id, maybeResult, opAsync2); - } - } catch (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[promiseIdSymbol] = id; - return promise; - } - function opAsync(name, ...args) { const id = nextPromiseId++; try { @@ -823,7 +798,6 @@ for (let i = 0; i < 10; i++) { asyncStub, generateAsyncOpHandler, opAsync, - opAsync2, resources, metrics, registerErrorBuilder, diff --git a/core/examples/http_bench_json_ops/http_bench_json_ops.js b/core/examples/http_bench_json_ops/http_bench_json_ops.js index 0c3b5be13e..beb6c90e45 100644 --- a/core/examples/http_bench_json_ops/http_bench_json_ops.js +++ b/core/examples/http_bench_json_ops/http_bench_json_ops.js @@ -3,7 +3,16 @@ // then write this fixed 'responseBuf'. The point of this benchmark is to // exercise the event loop in a simple yet semi-realistic way. -const { ops, opAsync, opAsync2 } = Deno.core; +// deno-lint-ignore-file camelcase + +const { op_listen } = Deno.core.ops; +const { + op_accept, + op_read_socket, +} = core.generateAsyncOpHandler( + "op_accept", + "op_read_socket", +); const requestBuf = new Uint8Array(64 * 1024); const responseBuf = new Uint8Array( @@ -12,24 +21,10 @@ const responseBuf = new Uint8Array( .map((c) => c.charCodeAt(0)), ); -/** Listens on 0.0.0.0:4570, returns rid. */ -function listen() { - return ops.op_listen(); -} - -/** Accepts a connection, returns rid. */ -function accept(serverRid) { - return opAsync("op_accept", serverRid); -} - -function read(serverRid, buf) { - return opAsync2("op_read_socket", serverRid, buf); -} - async function serve(rid) { try { while (true) { - await read(rid, requestBuf); + await op_read_socket(rid, requestBuf); if (!ops.op_try_write(rid, responseBuf)) { await Deno.core.writeAll(rid, responseBuf); } @@ -41,11 +36,12 @@ async function serve(rid) { } async function main() { - const listenerRid = listen(); + /** Listens on 0.0.0.0:4570, returns rid. */ + const listenerRid = op_listen(); Deno.core.print(`http_bench_ops listening on http://127.0.0.1:4570/\n`); while (true) { - const rid = await accept(listenerRid); + const rid = await op_accept(listenerRid); serve(rid); } } diff --git a/core/runtime.rs b/core/runtime.rs index e6c365e420..46256b8d8e 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -2765,9 +2765,9 @@ pub mod tests { .execute_script_static( "filename.js", r#" - + const { op_test } = Deno.core.generateAsyncOpHandler("op_test"); let zero_copy_a = new Uint8Array([0]); - Deno.core.opAsync2("op_test", null, zero_copy_a); + op_test(null, zero_copy_a); "#, ) .unwrap(); diff --git a/ext/fs/30_fs.js b/ext/fs/30_fs.js index 8766d32fff..70cfcee6ef 100644 --- a/ext/fs/30_fs.js +++ b/ext/fs/30_fs.js @@ -1,7 +1,22 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// deno-lint-ignore-file camelcase + const core = globalThis.Deno.core; const ops = core.ops; +const { + op_chmod_async, + op_ftruncate_async, + op_truncate_async, + op_link_async, + op_flock_async, +} = Deno.core.generateAsyncOpHandler( + "op_chmod_async", + "op_ftruncate_async", + "op_truncate_async", + "op_link_async", + "op_flock_async", +); const primordials = globalThis.__bootstrap.primordials; const { ArrayPrototypeFilter, @@ -34,7 +49,7 @@ function chmodSync(path, mode) { } async function chmod(path, mode) { - await core.opAsync2("op_chmod_async", pathFromURL(path), mode); + await op_chmod_async(pathFromURL(path), mode); } function chownSync( @@ -347,7 +362,7 @@ function ftruncateSync(rid, len) { } async function ftruncate(rid, len) { - await core.opAsync2("op_ftruncate_async", rid, coerceLen(len)); + await op_ftruncate_async(rid, coerceLen(len)); } function truncateSync(path, len) { @@ -355,7 +370,7 @@ function truncateSync(path, len) { } async function truncate(path, len) { - await core.opAsync2("op_truncate_async", path, coerceLen(len)); + await op_truncate_async(path, coerceLen(len)); } function umask(mask) { @@ -367,7 +382,7 @@ function linkSync(oldpath, newpath) { } async function link(oldpath, newpath) { - await core.opAsync2("op_link_async", oldpath, newpath); + await op_link_async(oldpath, newpath); } function toUnixTimeFromEpoch(value) { @@ -497,7 +512,7 @@ function flockSync(rid, exclusive) { } async function flock(rid, exclusive) { - await core.opAsync2("op_flock_async", rid, exclusive === true); + await op_flock_async(rid, exclusive === true); } function funlockSync(rid) { diff --git a/ext/http/00_serve.js b/ext/http/00_serve.js index 6aed08bddb..b18c26e800 100644 --- a/ext/http/00_serve.js +++ b/ext/http/00_serve.js @@ -64,7 +64,7 @@ const { op_set_response_headers, op_upgrade_raw, op_ws_server_create, -} = Deno.core.generateAsyncOpHandler( +} = core.generateAsyncOpHandler( "op_http_wait", "op_upgrade", "op_get_request_headers", diff --git a/ext/http/01_http.js b/ext/http/01_http.js index f41a2beed6..92fd8e2858 100644 --- a/ext/http/01_http.js +++ b/ext/http/01_http.js @@ -1,8 +1,12 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +// deno-lint-ignore-file camelcase + const core = globalThis.Deno.core; const internals = globalThis.__bootstrap.internals; const primordials = globalThis.__bootstrap.primordials; const { BadResourcePrototype, InterruptedPrototype, ops } = core; +const { op_http_write } = Deno.core.generateAsyncOpHandler("op_http_write"); import * as webidl from "ext:deno_webidl/00_webidl.js"; import { InnerBody } from "ext:deno_fetch/22_body.js"; import { Event, setEventTargetData } from "ext:deno_web/02_event.js"; @@ -321,7 +325,7 @@ function createRespondWith( break; } try { - await core.opAsync2("op_http_write", streamRid, value); + await op_http_write(streamRid, value); } catch (error) { const connError = httpConn[connErrorSymbol]; if ( diff --git a/ext/node/polyfills/internal/crypto/random.ts b/ext/node/polyfills/internal/crypto/random.ts index 32256b13bf..4890e158ad 100644 --- a/ext/node/polyfills/internal/crypto/random.ts +++ b/ext/node/polyfills/internal/crypto/random.ts @@ -1,6 +1,8 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. +// deno-lint-ignore-file camelcase + import { notImplemented } from "ext:deno_node/_utils.ts"; import randomBytes from "ext:deno_node/internal/crypto/_randomBytes.ts"; import randomFill, { @@ -31,6 +33,15 @@ export { default as randomInt } from "ext:deno_node/internal/crypto/_randomInt.t const { core } = globalThis.__bootstrap; const { ops } = core; +const { + op_node_gen_prime_async, + op_node_check_prime_bytes_async, + op_node_check_prime_async, +} = Deno.core.generateAsyncOpHandler( + "op_node_gen_prime_async", + "op_node_check_prime_bytes_async", + "op_node_check_prime_async", +); export type LargeNumberLike = | ArrayBufferView @@ -79,9 +90,9 @@ export function checkPrime( validateInt32(checks, "options.checks", 0); - let op = "op_node_check_prime_bytes_async"; + let op = op_node_check_prime_bytes_async; if (typeof candidate === "bigint") { - op = "op_node_check_prime_async"; + op = op_node_check_prime_async; } else if (!isAnyArrayBuffer(candidate) && !isArrayBufferView(candidate)) { throw new ERR_INVALID_ARG_TYPE( "candidate", @@ -96,7 +107,7 @@ export function checkPrime( ); } - core.opAsync2(op, candidate, checks).then( + op(candidate, checks).then( (result) => { callback?.(null, result); }, @@ -160,7 +171,7 @@ export function generatePrime( const { bigint, } = validateRandomPrimeJob(size, options); - core.opAsync2("op_node_gen_prime_async", size).then((prime: Uint8Array) => + op_node_gen_prime_async(size).then((prime: Uint8Array) => bigint ? arrayBufferToUnsignedBigInt(prime.buffer) : prime.buffer ).then((prime: ArrayBuffer | bigint) => { callback?.(null, prime); diff --git a/ext/web/02_timers.js b/ext/web/02_timers.js index 78cf06e445..cfd85a0553 100644 --- a/ext/web/02_timers.js +++ b/ext/web/02_timers.js @@ -1,5 +1,7 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// deno-lint-ignore-file camelcase + const core = globalThis.Deno.core; const ops = core.ops; const primordials = globalThis.__bootstrap.primordials; @@ -13,7 +15,6 @@ const { MapPrototypeSet, Uint8Array, Uint32Array, - // deno-lint-ignore camelcase NumberPOSITIVE_INFINITY, PromisePrototypeThen, SafeArrayIterator, @@ -26,6 +27,7 @@ const { import * as webidl from "ext:deno_webidl/00_webidl.js"; import { reportException } from "ext:deno_web/02_event.js"; import { assert } from "ext:deno_web/00_infra.js"; +const { op_sleep } = core.generateAsyncOpHandler("op_sleep"); const hrU8 = new Uint8Array(8); const hr = new Uint32Array(TypedArrayPrototypeGetBuffer(hrU8)); @@ -216,7 +218,7 @@ const scheduledTimers = { head: null, tail: null }; */ function runAfterTimeout(cb, millis, timerInfo) { const cancelRid = timerInfo.cancelRid; - const sleepPromise = core.opAsync2("op_sleep", millis, cancelRid); + const sleepPromise = op_sleep(millis, cancelRid); timerInfo.promiseId = sleepPromise[SymbolFor("Deno.core.internalPromiseId")]; if (!timerInfo.isRef) { core.unrefOp(timerInfo.promiseId); diff --git a/ext/websocket/01_websocket.js b/ext/websocket/01_websocket.js index dab34a0236..f7dd516ff0 100644 --- a/ext/websocket/01_websocket.js +++ b/ext/websocket/01_websocket.js @@ -1,12 +1,9 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// deno-lint-ignore-file camelcase /// const core = globalThis.Deno.core; -const { opAsync, opAsync2 } = core; -// deno-lint-ignore camelcase -const op_ws_check_permission_and_cancel_handle = - core.ops.op_ws_check_permission_and_cancel_handle; import { URL } from "ext:deno_url/00_url.js"; import * as webidl from "ext:deno_webidl/00_webidl.js"; import { HTTP_TOKEN_CODE_POINT_RE } from "ext:deno_web/00_infra.js"; @@ -51,6 +48,23 @@ const { TypedArrayPrototypeGetByteLength, TypedArrayPrototypeGetSymbolToStringTag, } = primordials; +const op_ws_check_permission_and_cancel_handle = + core.ops.op_ws_check_permission_and_cancel_handle; +const { + op_ws_create, + op_ws_close, + op_ws_send_binary, + op_ws_send_text, + op_ws_next_event, + op_ws_send_ping, +} = core.generateAsyncOpHandler( + "op_ws_create", + "op_ws_close", + "op_ws_send_binary", + "op_ws_send_text", + "op_ws_next_event", + "op_ws_send_ping", +); webidl.converters["sequence or DOMString"] = ( V, @@ -252,8 +266,7 @@ class WebSocket extends EventTarget { } PromisePrototypeThen( - opAsync( - "op_ws_create", + op_ws_create( "new WebSocket()", wsURL.href, ArrayPrototypeJoin(protocols, ", "), @@ -265,7 +278,7 @@ class WebSocket extends EventTarget { if (this[_readyState] === CLOSING) { PromisePrototypeThen( - opAsync("op_ws_close", this[_rid]), + op_ws_close(this[_rid]), () => { this[_readyState] = CLOSED; @@ -318,8 +331,7 @@ class WebSocket extends EventTarget { const sendTypedArray = (view, byteLength) => { this[_bufferedAmount] += byteLength; PromisePrototypeThen( - opAsync2( - "op_ws_send_binary", + op_ws_send_binary( this[_rid], view, ), @@ -353,8 +365,7 @@ class WebSocket extends EventTarget { const d = core.encode(string); this[_bufferedAmount] += TypedArrayPrototypeGetByteLength(d); PromisePrototypeThen( - opAsync2( - "op_ws_send_text", + op_ws_send_text( this[_rid], string, ), @@ -407,8 +418,7 @@ class WebSocket extends EventTarget { this[_readyState] = CLOSING; PromisePrototypeCatch( - opAsync( - "op_ws_close", + op_ws_close( this[_rid], code, reason, @@ -432,10 +442,7 @@ class WebSocket extends EventTarget { async [_eventLoop]() { while (this[_readyState] !== CLOSED) { - const { 0: kind, 1: value } = await opAsync2( - "op_ws_next_event", - this[_rid], - ); + const { 0: kind, 1: value } = await op_ws_next_event(this[_rid]); switch (kind) { case 0: { @@ -495,8 +502,7 @@ class WebSocket extends EventTarget { if (prevState === OPEN) { try { - await opAsync( - "op_ws_close", + await op_ws_close( this[_rid], code, value, @@ -524,17 +530,12 @@ class WebSocket extends EventTarget { clearTimeout(this[_idleTimeoutTimeout]); this[_idleTimeoutTimeout] = setTimeout(async () => { if (this[_readyState] === OPEN) { - await opAsync("op_ws_send_ping", this[_rid]); + await op_ws_send_ping(this[_rid]); this[_idleTimeoutTimeout] = setTimeout(async () => { if (this[_readyState] === OPEN) { this[_readyState] = CLOSING; const reason = "No response from ping frame."; - await opAsync( - "op_ws_close", - this[_rid], - 1001, - reason, - ); + await op_ws_close(this[_rid], 1001, reason); this[_readyState] = CLOSED; const errEvent = new ErrorEvent("error", { diff --git a/ext/websocket/02_websocketstream.js b/ext/websocket/02_websocketstream.js index 06f4b50d96..2c5df262ac 100644 --- a/ext/websocket/02_websocketstream.js +++ b/ext/websocket/02_websocketstream.js @@ -1,5 +1,6 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// deno-lint-ignore-file camelcase /// const core = globalThis.Deno.core; @@ -32,6 +33,19 @@ const { TypedArrayPrototypeGetByteLength, Uint8ArrayPrototype, } = primordials; +const { + op_ws_send_text, + op_ws_send_binary, + op_ws_next_event, + op_ws_create, + op_ws_close, +} = core.generateAsyncOpHandler( + "op_ws_send_text", + "op_ws_send_binary", + "op_ws_next_event", + "op_ws_create", + "op_ws_close", +); webidl.converters.WebSocketStreamOptions = webidl.createDictionaryConverter( "WebSocketStreamOptions", @@ -153,8 +167,7 @@ class WebSocketStream { }; options.signal?.[add](abort); PromisePrototypeThen( - core.opAsync( - "op_ws_create", + op_ws_create( "new WebSocketStream()", this[_url], options.protocols ? ArrayPrototypeJoin(options.protocols, ", ") : "", @@ -165,15 +178,12 @@ class WebSocketStream { options.signal?.[remove](abort); if (this[_earlyClose]) { PromisePrototypeThen( - core.opAsync("op_ws_close", create.rid), + op_ws_close(create.rid), () => { PromisePrototypeThen( (async () => { while (true) { - const { 0: kind } = await core.opAsync( - "op_ws_next_event", - create.rid, - ); + const { 0: kind } = await op_ws_next_event(create.rid); if (kind > 5) { /* close */ @@ -206,11 +216,11 @@ class WebSocketStream { const writable = new WritableStream({ write: async (chunk) => { if (typeof chunk === "string") { - await core.opAsync2("op_ws_send_text", this[_rid], chunk); + await op_ws_send_text(this[_rid], chunk); } else if ( ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, chunk) ) { - await core.opAsync2("op_ws_send_binary", this[_rid], chunk); + await op_ws_send_binary(this[_rid], chunk); } else { throw new TypeError( "A chunk may only be either a string or an Uint8Array", @@ -235,10 +245,7 @@ class WebSocketStream { }, }); const pull = async (controller) => { - const { 0: kind, 1: value } = await core.opAsync2( - "op_ws_next_event", - this[_rid], - ); + const { 0: kind, 1: value } = await op_ws_next_event(this[_rid]); switch (kind) { case 0: @@ -402,7 +409,7 @@ class WebSocketStream { this[_earlyClose] = true; } else if (this[_closed].state === "pending") { PromisePrototypeThen( - core.opAsync("op_ws_close", this[_rid], code, closeInfo.reason), + op_ws_close(this[_rid], code, closeInfo.reason), () => { setTimeout(() => { this[_closeSent].resolve(DateNow());