This commit is contained in:
Kenta Moriuchi 2025-09-18 16:57:50 +02:00 committed by GitHub
commit f9a07a80ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 3073 additions and 1748 deletions

View file

@ -278,7 +278,8 @@ class Request {
if (signal === false) {
const signal = newSignal();
this[_signalCache] = signal;
signal[signalAbort](
signalAbort(
signal,
new DOMException(MESSAGE_REQUEST_CANCELLED, "AbortError"),
);
return signal;
@ -289,7 +290,8 @@ class Request {
const signal = newSignal();
this[_signalCache] = signal;
this[_request].onCancel?.(() => {
signal[signalAbort](
signalAbort(
signal,
new DOMException(MESSAGE_REQUEST_CANCELLED, "AbortError"),
);
});
@ -615,7 +617,8 @@ const MESSAGE_REQUEST_CANCELLED = "The request has been cancelled.";
function abortRequest(request) {
if (request[_signalCache] !== undefined) {
request[_signal][signalAbort](
signalAbort(
request[_signal],
new DOMException(MESSAGE_REQUEST_CANCELLED, "AbortError"),
);
} else {

View file

@ -57,7 +57,10 @@ import {
redirectStatus,
toInnerResponse,
} from "ext:deno_fetch/23_response.js";
import * as abortSignal from "ext:deno_web/03_abort_signal.js";
import {
addSignalAlgorithm,
removeSignalAlgorithm,
} from "ext:deno_web/03_abort_signal.js";
import {
builtinTracer,
ContextManager,
@ -107,7 +110,7 @@ function createResponseBodyStream(responseBodyRid, terminator) {
}
// TODO(lucacasonato): clean up registration
terminator[abortSignal.add](onAbort);
addSignalAlgorithm(terminator, onAbort);
return readable;
}
@ -125,7 +128,7 @@ async function mainFetch(req, recursive, terminator) {
}
const body = new InnerBody(req.blobUrlEntry.stream());
terminator[abortSignal.add](() => body.error(terminator.reason));
addSignalAlgorithm(terminator, () => body.error(terminator.reason));
processUrlList(req.urlList, req.urlListProcessed);
return {
@ -186,7 +189,7 @@ async function mainFetch(req, recursive, terminator) {
core.tryClose(cancelHandleRid);
}
}
terminator[abortSignal.add](onAbort);
addSignalAlgorithm(terminator, onAbort);
let resp;
try {
resp = await opFetchSend(requestRid);
@ -403,13 +406,13 @@ function fetch(input, init = { __proto__: null }) {
// 9.
let locallyAborted = false;
// 10.
function onabort() {
function onAbort() {
locallyAborted = true;
reject(
abortFetch(request, responseObject, requestObject.signal.reason),
);
}
requestObject.signal[abortSignal.add](onabort);
addSignalAlgorithm(requestObject, onAbort);
if (!requestObject.headers.has("Accept")) {
ArrayPrototypePush(request.headerList, ["Accept", "*/*"]);
@ -435,7 +438,7 @@ function fetch(input, init = { __proto__: null }) {
requestObject.signal.reason,
),
);
requestObject.signal[abortSignal.remove](onabort);
removeSignalAlgorithm(requestObject, onAbort);
return;
}
// 12.3.
@ -444,7 +447,7 @@ function fetch(input, init = { __proto__: null }) {
"Fetch failed: " + (response.error ?? "unknown error"),
);
reject(err);
requestObject.signal[abortSignal.remove](onabort);
removeSignalAlgorithm(requestObject, onAbort);
return;
}
responseObject = fromInnerResponse(response, "immutable");
@ -454,12 +457,12 @@ function fetch(input, init = { __proto__: null }) {
}
resolve(responseObject);
requestObject.signal[abortSignal.remove](onabort);
removeSignalAlgorithm(requestObject, onAbort);
},
),
(err) => {
reject(err);
requestObject.signal[abortSignal.remove](onabort);
removeSignalAlgorithm(requestObject, onAbort);
},
);
});

View file

@ -92,7 +92,10 @@ const {
} = primordials;
import { read, readSync, write, writeSync } from "ext:deno_io/12_io.js";
import * as abortSignal from "ext:deno_web/03_abort_signal.js";
import {
addSignalAlgorithm,
removeSignalAlgorithm,
} from "ext:deno_web/03_abort_signal.js";
import {
readableStreamForRid,
ReadableStreamPrototype,
@ -747,7 +750,7 @@ async function readFile(path, options) {
options.signal.throwIfAborted();
cancelRid = createCancelHandle();
abortHandler = () => core.tryClose(cancelRid);
options.signal[abortSignal.add](abortHandler);
addSignalAlgorithm(options.signal, abortHandler);
}
try {
@ -758,7 +761,7 @@ async function readFile(path, options) {
return read;
} finally {
if (options?.signal) {
options.signal[abortSignal.remove](abortHandler);
removeSignalAlgorithm(options.signal, abortHandler);
// always throw the abort error when aborted
options.signal.throwIfAborted();
@ -777,7 +780,7 @@ async function readTextFile(path, options) {
options.signal.throwIfAborted();
cancelRid = createCancelHandle();
abortHandler = () => core.tryClose(cancelRid);
options.signal[abortSignal.add](abortHandler);
addSignalAlgorithm(options.signal, abortHandler);
}
try {
@ -788,7 +791,7 @@ async function readTextFile(path, options) {
return read;
} finally {
if (options?.signal) {
options.signal[abortSignal.remove](abortHandler);
removeSignalAlgorithm(options.signal, abortHandler);
// always throw the abort error when aborted
options.signal.throwIfAborted();
@ -823,7 +826,7 @@ async function writeFile(
options.signal.throwIfAborted();
cancelRid = createCancelHandle();
abortHandler = () => core.tryClose(cancelRid);
options.signal[abortSignal.add](abortHandler);
addSignalAlgorithm(options.signal, abortHandler);
}
try {
if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, data)) {
@ -851,7 +854,7 @@ async function writeFile(
}
} finally {
if (options.signal) {
options.signal[abortSignal.remove](abortHandler);
removeSignalAlgorithm(options.signal, abortHandler);
// always throw the abort error when aborted
options.signal.throwIfAborted();

View file

@ -64,7 +64,10 @@ import {
readableStreamForRidUnrefableUnref,
writableStreamForRid,
} from "ext:deno_web/06_streams.js";
import * as abortSignal from "ext:deno_web/03_abort_signal.js";
import {
addSignalAlgorithm,
removeSignalAlgorithm,
} from "ext:deno_web/03_abort_signal.js";
import { SymbolDispose } from "ext:deno_web/00_infra.js";
async function write(rid, data) {
@ -78,7 +81,7 @@ async function resolveDns(query, recordType, options) {
options.signal.throwIfAborted();
cancelRid = createCancelHandle();
abortHandler = () => core.tryClose(cancelRid);
options.signal[abortSignal.add](abortHandler);
addSignalAlgorithm(options.signal, abortHandler);
}
try {
@ -91,7 +94,7 @@ async function resolveDns(query, recordType, options) {
return ArrayPrototypeMap(res, (recordWithTtl) => recordWithTtl.data);
} finally {
if (options?.signal) {
options.signal[abortSignal.remove](abortHandler);
removeSignalAlgorithm(options.signal, abortHandler);
// always throw the abort error when aborted
options.signal.throwIfAborted();
@ -692,7 +695,7 @@ async function connect(args) {
args.signal.throwIfAborted();
cancelRid = createCancelHandle();
abortHandler = () => core.tryClose(cancelRid);
args.signal[abortSignal.add](abortHandler);
addSignalAlgorithm(args.signal, abortHandler);
}
const port = validatePort(args.port);
@ -712,7 +715,7 @@ async function connect(args) {
return new TcpConn(rid, remoteAddr, localAddr);
} finally {
if (args?.signal) {
args.signal[abortSignal.remove](abortHandler);
removeSignalAlgorithm(args.signal, abortHandler);
args.signal.throwIfAborted();
}
}

View file

@ -72,10 +72,7 @@ import {
} from "ext:deno_node/internal/validators.mjs";
import { spliceOne } from "ext:deno_node/_utils.ts";
import { nextTick } from "ext:deno_node/_process/process.ts";
import {
eventTargetData,
kResistStopImmediatePropagation,
} from "ext:deno_web/02_event.js";
import { getListeners } from "ext:deno_web/02_event.js";
export { addAbortListener } from "./internal/events/abort_listener.mjs";
@ -867,9 +864,7 @@ export function getEventListeners(emitterOrTarget, type) {
return emitterOrTarget.listeners(type);
}
if (emitterOrTarget instanceof EventTarget) {
return emitterOrTarget[eventTargetData]?.listeners?.[type]?.map((
listener,
) => listener.callback) || [];
return getListeners(emitterOrTarget, type);
}
throw new ERR_INVALID_ARG_TYPE(
"emitter",
@ -934,7 +929,7 @@ export async function once(emitter, name, options = kEmptyObject) {
signal,
"abort",
abortListener,
{ once: true, [kResistStopImmediatePropagation]: true },
{ once: true, [SymbolFor("Deno.stopImmediatePropagation")]: true },
);
}
});

View file

@ -4,7 +4,10 @@
import { primordials } from "ext:core/mod.js";
const { queueMicrotask } = primordials;
import { SymbolDispose } from "ext:deno_web/00_infra.js";
import * as abortSignal from "ext:deno_web/03_abort_signal.js";
import {
addSignalAlgorithm,
removeSignalAlgorithm,
} from "ext:deno_web/03_abort_signal.js";
import { validateAbortSignal, validateFunction } from "../validators.mjs";
import { codes } from "../errors.ts";
const { ERR_INVALID_ARG_TYPE } = codes;
@ -29,9 +32,9 @@ function addAbortListener(signal, listener) {
removeEventListener?.();
listener({ target: signal });
};
signal[abortSignal.add](handler);
addSignalAlgorithm(signal, handler);
removeEventListener = () => {
signal[abortSignal.remove](handler);
removeSignalAlgorithm(signal, handler);
};
}
return {

View file

@ -50,7 +50,7 @@ import {
validateString,
} from "ext:deno_node/internal/validators.mjs";
import { parseArgs } from "ext:deno_node/internal/util/parse_args/parse_args.js";
import * as abortSignal from "ext:deno_web/03_abort_signal.js";
import { addSignalAlgorithm } from "ext:deno_web/03_abort_signal.js";
import { ERR_INVALID_ARG_TYPE } from "ext:deno_node/internal/errors.ts";
export {
@ -246,7 +246,7 @@ export async function aborted(
return PromiseResolve();
}
const abortPromise = PromiseWithResolvers();
signal[abortSignal.add](abortPromise.resolve);
addSignalAlgorithm(signal, abortPromise.resolve);
return abortPromise.promise;
}

View file

@ -32,7 +32,10 @@ import {
SymbolAsyncDispose,
} from "ext:deno_web/00_infra.js";
import { packageData } from "ext:deno_fetch/22_body.js";
import * as abortSignal from "ext:deno_web/03_abort_signal.js";
import {
addSignalAlgorithm,
removeSignalAlgorithm,
} from "ext:deno_web/03_abort_signal.js";
import {
ReadableStream,
readableStreamCollectIntoUint8Array,
@ -314,11 +317,15 @@ class ChildProcess {
// Ignore the error for https://github.com/denoland/deno/issues/27112
}
};
signal?.[abortSignal.add](onAbort);
if (signal != null) {
addSignalAlgorithm(signal, onAbort);
}
const waitPromise = op_spawn_wait(this.#rid);
this.#waitPromise = waitPromise;
this.#status = PromisePrototypeThen(waitPromise, (res) => {
signal?.[abortSignal.remove](onAbort);
if (signal != null) {
removeSignalAlgorithm(signal, onAbort);
}
this.#waitComplete = true;
return res;
});

File diff suppressed because it is too large Load diff

View file

@ -6,107 +6,40 @@
import { core, primordials } from "ext:core/mod.js";
const {
ArrayPrototypeEvery,
ArrayPrototypePush,
FunctionPrototypeApply,
ObjectPrototypeIsPrototypeOf,
SafeSet,
SafeSetIterator,
SafeWeakRef,
SafeWeakSet,
SetPrototypeAdd,
SetPrototypeDelete,
ObjectDefineProperties,
ObjectDefineProperty,
Symbol,
SymbolFor,
TypeError,
WeakRefPrototypeDeref,
WeakSetPrototypeAdd,
WeakSetPrototypeHas,
} = primordials;
import {
AbortController,
AbortSignal,
op_event_add_abort_algorithm,
op_event_create_abort_signal,
op_event_create_dependent_abort_signal,
op_event_get_dependent_signals,
op_event_get_source_signals,
op_event_remove_abort_algorithm,
op_event_signal_abort,
} from "ext:core/ops";
import * as webidl from "ext:deno_webidl/00_webidl.js";
import { assert } from "./00_infra.js";
import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
import { DOMException } from "./01_dom_exception.js";
import {
defineEventHandler,
Event,
EventTarget,
listenerCount,
setIsTrusted,
getListenerCount,
} from "./02_event.js";
import { clearTimeout, refTimer, unrefTimer } from "./02_timers.js";
// Since WeakSet is not a iterable, WeakRefSet class is provided to store and
// iterate objects.
// To create an AsyncIterable using GeneratorFunction in the internal code,
// there are many primordial considerations, so we simply implement the
// toArray method.
class WeakRefSet {
#weakSet = new SafeWeakSet();
#refs = [];
add(value) {
if (WeakSetPrototypeHas(this.#weakSet, value)) {
return;
}
WeakSetPrototypeAdd(this.#weakSet, value);
ArrayPrototypePush(this.#refs, new SafeWeakRef(value));
}
has(value) {
return WeakSetPrototypeHas(this.#weakSet, value);
}
toArray() {
const ret = [];
for (let i = 0; i < this.#refs.length; ++i) {
const value = WeakRefPrototypeDeref(this.#refs[i]);
if (value !== undefined) {
ArrayPrototypePush(ret, value);
}
}
return ret;
}
}
const add = Symbol("[[add]]");
const signalAbort = Symbol("[[signalAbort]]");
const remove = Symbol("[[remove]]");
const runAbortSteps = Symbol("[[runAbortSteps]]");
const abortReason = Symbol("[[abortReason]]");
const abortAlgos = Symbol("[[abortAlgos]]");
const dependent = Symbol("[[dependent]]");
const sourceSignals = Symbol("[[sourceSignals]]");
const dependentSignals = Symbol("[[dependentSignals]]");
const signal = Symbol("[[signal]]");
const timerId = Symbol("[[timerId]]");
const illegalConstructorKey = Symbol("illegalConstructorKey");
class AbortSignal extends EventTarget {
[abortReason] = undefined;
[abortAlgos] = null;
[dependent] = false;
[sourceSignals] = null;
[dependentSignals] = null;
[timerId] = null;
[webidl.brand] = webidl.brand;
static any(signals) {
const prefix = "Failed to execute 'AbortSignal.any'";
webidl.requiredArguments(arguments.length, 1, prefix);
return createDependentAbortSignal(signals, prefix);
}
static abort(reason = undefined) {
if (reason !== undefined) {
reason = webidl.converters.any(reason);
}
const signal = new AbortSignal(illegalConstructorKey);
signal[signalAbort](reason);
return signal;
}
static timeout(millis) {
ObjectDefineProperty(AbortSignal, "timeout", {
__proto__: null,
value: function timeout(millis) {
const prefix = "Failed to execute 'AbortSignal.timeout'";
webidl.requiredArguments(arguments.length, 1, prefix);
millis = webidl.converters["unsigned long long"](
@ -118,7 +51,7 @@ class AbortSignal extends EventTarget {
},
);
const signal = new AbortSignal(illegalConstructorKey);
const signal = op_event_create_abort_signal();
signal[timerId] = core.queueSystemTimer(
undefined,
false,
@ -126,197 +59,129 @@ class AbortSignal extends EventTarget {
() => {
clearTimeout(signal[timerId]);
signal[timerId] = null;
signal[signalAbort](
op_event_signal_abort(
signal,
new DOMException("Signal timed out.", "TimeoutError"),
);
},
);
unrefTimer(signal[timerId]);
return signal;
}
},
configurable: true,
enumerable: true,
writable: true,
});
[add](algorithm) {
if (this.aborted) {
return;
}
this[abortAlgos] ??= new SafeSet();
SetPrototypeAdd(this[abortAlgos], algorithm);
}
const addEventListener_ = EventTarget.prototype.addEventListener;
const removeEventListener_ = EventTarget.prototype.removeEventListener;
[signalAbort](
reason = new DOMException("The signal has been aborted", "AbortError"),
) {
if (this.aborted) {
return;
}
this[abortReason] = reason;
const dependentSignalsToAbort = [];
if (this[dependentSignals] !== null) {
const dependentSignalArray = this[dependentSignals].toArray();
for (let i = 0; i < dependentSignalArray.length; ++i) {
const dependentSignal = dependentSignalArray[i];
if (dependentSignal[abortReason] === undefined) {
dependentSignal[abortReason] = this[abortReason];
ArrayPrototypePush(dependentSignalsToAbort, dependentSignal);
}
}
}
this[runAbortSteps]();
if (dependentSignalsToAbort.length !== 0) {
for (let i = 0; i < dependentSignalsToAbort.length; ++i) {
const dependentSignal = dependentSignalsToAbort[i];
dependentSignal[runAbortSteps]();
}
}
}
[runAbortSteps]() {
const algos = this[abortAlgos];
this[abortAlgos] = null;
if (algos !== null) {
for (const algorithm of new SafeSetIterator(algos)) {
algorithm();
}
}
if (listenerCount(this, "abort") > 0) {
const event = new Event("abort");
setIsTrusted(event, true);
super.dispatchEvent(event);
}
}
[remove](algorithm) {
this[abortAlgos] && SetPrototypeDelete(this[abortAlgos], algorithm);
}
constructor(key = null) {
if (key !== illegalConstructorKey) {
throw new TypeError("Illegal constructor");
}
super();
}
get aborted() {
webidl.assertBranded(this, AbortSignalPrototype);
return this[abortReason] !== undefined;
}
get reason() {
webidl.assertBranded(this, AbortSignalPrototype);
return this[abortReason];
}
throwIfAborted() {
webidl.assertBranded(this, AbortSignalPrototype);
if (this[abortReason] !== undefined) {
throw this[abortReason];
}
}
// `addEventListener` and `removeEventListener` have to be overridden in
// order to have the timer block the event loop while there are listeners.
// `[add]` and `[remove]` don't ref and unref the timer because they can
// only be used by Deno internals, which use it to essentially cancel async
// ops which would block the event loop.
addEventListener() {
FunctionPrototypeApply(super.addEventListener, this, arguments);
if (listenerCount(this, "abort") > 0) {
if (this[timerId] !== null) {
refTimer(this[timerId]);
} else if (this[sourceSignals] !== null) {
const sourceSignalArray = this[sourceSignals].toArray();
for (let i = 0; i < sourceSignalArray.length; ++i) {
const sourceSignal = sourceSignalArray[i];
if (sourceSignal[timerId] !== null) {
refTimer(sourceSignal[timerId]);
}
}
}
}
}
removeEventListener() {
FunctionPrototypeApply(super.removeEventListener, this, arguments);
if (listenerCount(this, "abort") === 0) {
if (this[timerId] !== null) {
unrefTimer(this[timerId]);
} else if (this[sourceSignals] !== null) {
const sourceSignalArray = this[sourceSignals].toArray();
for (let i = 0; i < sourceSignalArray.length; ++i) {
const sourceSignal = sourceSignalArray[i];
if (sourceSignal[timerId] !== null) {
// Check that all dependent signals of the timer signal do not have listeners
if (
ArrayPrototypeEvery(
sourceSignal[dependentSignals].toArray(),
(dependentSignal) =>
dependentSignal === this ||
listenerCount(dependentSignal, "abort") === 0,
)
) {
unrefTimer(sourceSignal[timerId]);
// `addEventListener` and `removeEventListener` have to be overridden in
// order to have the timer block the event loop while there are listeners.
// `[add]` and `[remove]` don't ref and unref the timer because they can
// only be used by Deno internals, which use it to essentially cancel async
// ops which would block the event loop.
ObjectDefineProperties(AbortSignal.prototype, {
addEventListener: {
__proto__: null,
value: function addEventListener() {
FunctionPrototypeApply(addEventListener_, this, arguments);
if (getListenerCount(this, "abort") > 0) {
if (this[timerId] !== null) {
refTimer(this[timerId]);
} else {
const sourceSignals = op_event_get_source_signals(this);
for (let i = 0; i < sourceSignals.length; ++i) {
const sourceSignal = sourceSignals[i];
if (sourceSignal[timerId] !== null) {
refTimer(sourceSignal[timerId]);
}
}
}
}
}
}
},
configurable: true,
enumerable: true,
writable: true,
},
removeEventListener: {
__proto__: null,
value: function removeEventListener() {
FunctionPrototypeApply(removeEventListener_, this, arguments);
if (getListenerCount(this, "abort") === 0) {
if (this[timerId] !== null) {
unrefTimer(this[timerId]);
} else {
const sourceSignals = op_event_get_source_signals(this);
for (let i = 0; i < sourceSignals.length; ++i) {
const sourceSignal = sourceSignals[i];
if (sourceSignal[timerId] !== null) {
// Check that all dependent signals of the timer signal do not have listeners
if (
ArrayPrototypeEvery(
op_event_get_dependent_signals(sourceSignal),
(dependentSignal) =>
dependentSignal === this ||
getListenerCount(dependentSignal, "abort") === 0,
)
) {
unrefTimer(sourceSignal[timerId]);
}
}
}
}
}
},
configurable: true,
enumerable: true,
writable: true,
},
[SymbolFor("Deno.privateCustomInspect")]: {
__proto__: null,
value(inspect, inspectOptions) {
return inspect(
createFilteredInspectProxy({
object: this,
evaluate: ObjectPrototypeIsPrototypeOf(AbortSignalPrototype, this),
keys: [
"aborted",
"reason",
"onabort",
],
}),
inspectOptions,
);
},
},
});
[SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
return inspect(
createFilteredInspectProxy({
object: this,
evaluate: ObjectPrototypeIsPrototypeOf(AbortSignalPrototype, this),
keys: [
"aborted",
"reason",
"onabort",
],
}),
inspectOptions,
);
}
}
defineEventHandler(AbortSignal.prototype, "abort");
webidl.configureInterface(AbortSignal);
const AbortSignalPrototype = AbortSignal.prototype;
class AbortController {
[signal] = new AbortSignal(illegalConstructorKey);
constructor() {
this[webidl.brand] = webidl.brand;
}
get signal() {
webidl.assertBranded(this, AbortControllerPrototype);
return this[signal];
}
abort(reason) {
webidl.assertBranded(this, AbortControllerPrototype);
this[signal][signalAbort](reason);
}
[SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
return inspect(
createFilteredInspectProxy({
object: this,
evaluate: ObjectPrototypeIsPrototypeOf(AbortControllerPrototype, this),
keys: [
"signal",
],
}),
inspectOptions,
);
}
}
ObjectDefineProperty(
AbortController.prototype,
SymbolFor("Deno.privateCustomInspect"),
{
__proto__: null,
value(inspect, inspectOptions) {
return inspect(
createFilteredInspectProxy({
object: this,
evaluate: ObjectPrototypeIsPrototypeOf(
AbortControllerPrototype,
this,
),
keys: [
"signal",
],
}),
inspectOptions,
);
},
},
);
webidl.configureInterface(AbortController);
const AbortControllerPrototype = AbortController.prototype;
@ -329,61 +194,54 @@ webidl.converters["sequence<AbortSignal>"] = webidl.createSequenceConverter(
webidl.converters.AbortSignal,
);
/**
* @returns {AbortSignal}
*/
function newSignal() {
return new AbortSignal(illegalConstructorKey);
return op_event_create_abort_signal();
}
/**
* @param {AbortSignal[]} signals
* @param {string} prefix
* @returns {AbortSignal}
*/
function createDependentAbortSignal(signals, prefix) {
signals = webidl.converters["sequence<AbortSignal>"](
signals,
prefix,
"Argument 1",
);
return op_event_create_dependent_abort_signal(signals, prefix);
}
const resultSignal = new AbortSignal(illegalConstructorKey);
for (let i = 0; i < signals.length; ++i) {
const signal = signals[i];
if (signal[abortReason] !== undefined) {
resultSignal[abortReason] = signal[abortReason];
return resultSignal;
}
}
/**
* @param {AbortSignal} signal
* @param {() => void} algorithm
*/
function addSignalAlgorithm(signal, algorithm) {
op_event_add_abort_algorithm(signal, algorithm);
}
resultSignal[dependent] = true;
resultSignal[sourceSignals] = new WeakRefSet();
for (let i = 0; i < signals.length; ++i) {
const signal = signals[i];
if (!signal[dependent]) {
signal[dependentSignals] ??= new WeakRefSet();
resultSignal[sourceSignals].add(signal);
signal[dependentSignals].add(resultSignal);
} else {
const sourceSignalArray = signal[sourceSignals].toArray();
for (let j = 0; j < sourceSignalArray.length; ++j) {
const sourceSignal = sourceSignalArray[j];
assert(sourceSignal[abortReason] === undefined);
assert(!sourceSignal[dependent]);
/**
* @param {AbortSignal} signal
* @param {() => void} algorithm
*/
function removeSignalAlgorithm(signal, algorithm) {
op_event_remove_abort_algorithm(signal, algorithm);
}
if (resultSignal[sourceSignals].has(sourceSignal)) {
continue;
}
resultSignal[sourceSignals].add(sourceSignal);
sourceSignal[dependentSignals].add(resultSignal);
}
}
}
return resultSignal;
/**
* @param {AbortSignal} signal
* @param {any} reason
*/
function signalAbort(signal, reason) {
op_event_signal_abort(signal, reason);
}
export {
AbortController,
AbortSignal,
AbortSignalPrototype,
add,
addSignalAlgorithm,
createDependentAbortSignal,
newSignal,
remove,
removeSignalAlgorithm,
signalAbort,
timerId,
};

View file

@ -93,9 +93,9 @@ import * as webidl from "ext:deno_webidl/00_webidl.js";
import { structuredClone } from "./02_structured_clone.js";
import {
AbortSignalPrototype,
add,
addSignalAlgorithm,
newSignal,
remove,
removeSignalAlgorithm,
signalAbort,
} from "./03_abort_signal.js";
@ -2747,7 +2747,7 @@ function readableStreamPipeTo(
abortAlgorithm();
return promise.promise;
}
signal[add](abortAlgorithm);
addSignalAlgorithm(signal, abortAlgorithm);
}
function pipeLoop() {
@ -2949,7 +2949,7 @@ function readableStreamPipeTo(
readableStreamDefaultReaderRelease(reader);
if (signal !== undefined) {
signal[remove](abortAlgorithm);
removeSignalAlgorithm(signal, abortAlgorithm);
}
if (isError) {
promise.reject(error);
@ -4303,7 +4303,7 @@ function writableStreamAbort(stream, reason) {
if (state === "closed" || state === "errored") {
return PromiseResolve(undefined);
}
stream[_controller][_signal][signalAbort](reason);
signalAbort(stream[_controller][_signal], reason);
if (state === "closed" || state === "errored") {
return PromiseResolve(undefined);
}

View file

@ -34,6 +34,7 @@ const {
import * as webidl from "ext:deno_webidl/00_webidl.js";
import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
import {
createEventTargetBranded,
defineEventHandler,
EventTarget,
MessageEvent,
@ -111,7 +112,7 @@ export const unrefParentPort = Symbol("unrefParentPort");
* @returns {MessagePort}
*/
function createMessagePort(id) {
const port = webidl.createBranded(MessagePort);
const port = createEventTargetBranded(MessagePortPrototype);
port[core.hostObjectBrand] = core.hostObjectBrand;
setEventTargetData(port);
port[_id] = id;

View file

@ -7,6 +7,7 @@ const {
ArrayPrototypePush,
ObjectKeys,
ObjectPrototypeIsPrototypeOf,
ObjectSetPrototypeOf,
ReflectHas,
Symbol,
SymbolFor,
@ -19,7 +20,7 @@ const {
import * as webidl from "ext:deno_webidl/00_webidl.js";
import { structuredClone } from "./02_structured_clone.js";
import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
import { EventTarget } from "./02_event.js";
import { EventTarget, createEventTargetBranded } from "./02_event.js";
import { DOMException } from "./01_dom_exception.js";
const illegalConstructorKey = Symbol("illegalConstructorKey");
@ -298,6 +299,7 @@ class PerformanceMark extends PerformanceEntry {
}
webidl.configureInterface(PerformanceMark);
const PerformanceMarkPrototype = PerformanceMark.prototype;
class PerformanceMeasure extends PerformanceEntry {
[_detail] = null;
@ -360,14 +362,10 @@ class PerformanceMeasure extends PerformanceEntry {
}
webidl.configureInterface(PerformanceMeasure);
const PerformanceMeasurePrototype = PerformanceMeasure.prototype;
class Performance extends EventTarget {
constructor(key = null) {
if (key != illegalConstructorKey) {
webidl.illegalConstructor();
}
super();
this[webidl.brand] = webidl.brand;
class Performance {
constructor() {
webidl.illegalConstructor();
}
get timeOrigin() {
@ -600,6 +598,12 @@ class Performance extends EventTarget {
);
}
}
// Prevent the execution of the EventTarget constructor and make it possible
// to initialize during bootstrap.
ObjectSetPrototypeOf(Performance, EventTarget);
ObjectSetPrototypeOf(Performance.prototype, EventTarget.prototype);
webidl.configureInterface(Performance);
const PerformancePrototype = Performance.prototype;
@ -608,7 +612,7 @@ webidl.converters["Performance"] = webidl.createInterfaceConverter(
PerformancePrototype,
);
const performance = new Performance(illegalConstructorKey);
const performance = createEventTargetBranded(Performance.prototype);
export {
Performance,

2420
ext/web/event.rs Normal file

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,7 @@
mod blob;
mod compression;
mod event;
mod message_port;
mod stream_resource;
mod timers;
@ -36,6 +37,7 @@ use crate::blob::op_blob_read_part;
use crate::blob::op_blob_remove_part;
use crate::blob::op_blob_revoke_object_url;
use crate::blob::op_blob_slice_part;
use crate::event::ReportExceptionStackedCalls;
pub use crate::message_port::JsMessageData;
pub use crate::message_port::MessagePort;
pub use crate::message_port::Transferable;
@ -80,6 +82,22 @@ deno_core::extension!(deno_web,
compression::op_compression_new,
compression::op_compression_write,
compression::op_compression_finish,
event::op_event_dispatch,
event::op_event_get_target_listener_count,
event::op_event_get_target_listeners,
event::op_event_set_is_trusted,
event::op_event_set_target,
event::op_event_create_empty_event_target,
event::op_event_wrap_event_target,
event::op_event_report_error,
event::op_event_report_exception,
event::op_event_create_abort_signal,
event::op_event_create_dependent_abort_signal,
event::op_event_add_abort_algorithm,
event::op_event_remove_abort_algorithm,
event::op_event_signal_abort,
event::op_event_get_source_signals,
event::op_event_get_dependent_signals,
op_now<P>,
op_time_origin<P>,
op_defer,
@ -92,6 +110,18 @@ deno_core::extension!(deno_web,
stream_resource::op_readable_stream_resource_close,
stream_resource::op_readable_stream_resource_await_close,
],
objects = [
event::Event,
event::CustomEvent,
event::ErrorEvent,
event::PromiseRejectionEvent,
event::CloseEvent,
event::MessageEvent,
event::ProgressEvent,
event::EventTarget,
event::AbortSignal,
event::AbortController,
],
esm = [
"00_infra.js",
"01_dom_exception.js",
@ -122,6 +152,7 @@ deno_core::extension!(deno_web,
if let Some(location) = options.maybe_location {
state.put(Location(location));
}
state.put(ReportExceptionStackedCalls::default());
state.put(StartTime::default());
}
);

View file

@ -56,6 +56,7 @@ import { HTTP_TOKEN_CODE_POINT_RE } from "ext:deno_web/00_infra.js";
import { DOMException } from "ext:deno_web/01_dom_exception.js";
import { clearTimeout, setTimeout } from "ext:deno_web/02_timers.js";
import {
createEventTargetBranded,
CloseEvent,
defineEventHandler,
dispatch,
@ -742,7 +743,7 @@ webidl.configureInterface(WebSocket);
const WebSocketPrototype = WebSocket.prototype;
function createWebSocketBranded() {
const socket = webidl.createBranded(WebSocket);
const socket = createEventTargetBranded(WebSocketPrototype);
socket[_rid] = undefined;
socket[_role] = undefined;
socket[_readyState] = CONNECTING;

View file

@ -36,7 +36,10 @@ import * as webidl from "ext:deno_webidl/00_webidl.js";
import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
import { Deferred, writableStreamClose } from "ext:deno_web/06_streams.js";
import { DOMException } from "ext:deno_web/01_dom_exception.js";
import { add, remove } from "ext:deno_web/03_abort_signal.js";
import {
addSignalAlgorithm,
removeSignalAlgorithm,
} from "ext:deno_web/03_abort_signal.js";
import {
fillHeaders,
headerListFromHeaders,
@ -165,7 +168,9 @@ class WebSocketStream {
const abort = () => {
core.close(cancelRid);
};
options.signal?.[add](abort);
if (options.signal != null) {
addSignalAlgorithm(options.signal, abort);
}
PromisePrototypeThen(
op_ws_create(
"new WebSocketStream()",
@ -175,7 +180,9 @@ class WebSocketStream {
headerListFromHeaders(headers),
),
(create) => {
options.signal?.[remove](abort);
if (options.signal != null) {
removeSignalAlgorithm(options.signal, abort);
}
if (this[_earlyClose]) {
PromisePrototypeThen(
op_ws_close(create.rid),

View file

@ -719,6 +719,7 @@ function bootstrapMainRuntime(runtimeOptions, warmup = false) {
removeImportedOps();
performance.setTimeOrigin();
event.setEventTargetData(performance.performance);
globalThis_ = globalThis;
// Remove bootstrapping data from the global scope
@ -756,6 +757,7 @@ function bootstrapMainRuntime(runtimeOptions, warmup = false) {
core.wrapConsole(globalThis.console, core.v8Console);
}
event.setEventTargetData(globalThis);
event.defineEventHandler(globalThis, "error");
event.defineEventHandler(globalThis, "load");
event.defineEventHandler(globalThis, "beforeunload");
@ -852,6 +854,7 @@ function bootstrapWorkerRuntime(
closeOnIdle = runtimeOptions[14];
performance.setTimeOrigin();
event.setEventTargetData(performance.performance);
globalThis_ = globalThis;
// Remove bootstrapping data from the global scope
@ -884,6 +887,7 @@ function bootstrapWorkerRuntime(
core.wrapConsole(globalThis.console, core.v8Console);
event.setEventTargetData(globalThis);
event.defineEventHandler(globalThis, "message");
event.defineEventHandler(globalThis, "error", undefined, true);
@ -969,13 +973,8 @@ globalThis.bootstrap = {
dispatchProcessBeforeExitEvent,
};
event.setEventTargetData(globalThis);
event.saveGlobalThisReference(globalThis);
event.defineEventHandler(globalThis, "unhandledrejection");
// Nothing listens to this, but it warms up the code paths for event dispatch
(new event.EventTarget()).dispatchEvent(new Event("warmup"));
removeImportedOps();
// Run the warmup path through node and runtime/worker bootstrap functions

View file

@ -142,12 +142,12 @@ pub fn op_bootstrap_color_depth(state: &mut OpState) -> i32 {
}
#[op2(fast)]
pub fn op_bootstrap_no_color(_state: &mut OpState) -> bool {
pub fn op_bootstrap_no_color() -> bool {
!deno_terminal::colors::use_color()
}
#[op2(fast)]
pub fn op_bootstrap_stdout_no_color(_state: &mut OpState) -> bool {
pub fn op_bootstrap_stdout_no_color() -> bool {
if deno_terminal::colors::force_color() {
return false;
}
@ -156,7 +156,7 @@ pub fn op_bootstrap_stdout_no_color(_state: &mut OpState) -> bool {
}
#[op2(fast)]
pub fn op_bootstrap_stderr_no_color(_state: &mut OpState) -> bool {
pub fn op_bootstrap_stderr_no_color() -> bool {
if deno_terminal::colors::force_color() {
return false;
}