Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 27 additions & 12 deletions lib/internal/abort_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const {
ObjectAssign,
ObjectDefineProperties,
ObjectDefineProperty,
ObjectFreeze,
ObjectSetPrototypeOf,
PromiseResolve,
PromiseWithResolvers,
Expand Down Expand Up @@ -73,6 +74,15 @@ const {

let _MessageChannel;

// An object literal with __proto__: null and properties will be
// created as slow Dictionary properties. An object literal with
// __proto__: null and no properties is fast mode. An object
// literal with { __proto__: kNullProtoObject, ... } and
// properties will be fast mode. It's a V8 optimization quirk.
// To ensure that object literals are created in fast mode,
// use __proto__: kNullProtoObject.
const kNullProtoObject = ObjectFreeze({ __proto__: null });

const kDontThrowSymbol = Symbol('kDontThrowSymbol');

// Loading the MessageChannel and markTransferable have to be done lazily
Expand Down Expand Up @@ -295,7 +305,7 @@ class AbortSignal extends EventTarget {
*/
static abort(
reason = new DOMException('This operation was aborted', 'AbortError')) {
return new AbortSignal(kDontThrowSymbol, { aborted: true, reason });
return new AbortSignal(kDontThrowSymbol, { __proto__: kNullProtoObject, aborted: true, reason });
}

/**
Expand All @@ -320,10 +330,10 @@ class AbortSignal extends EventTarget {
static any(signals) {
const signalsArray = converters['sequence<AbortSignal>'](
signals,
{ __proto__: null, context: 'signals' },
{ __proto__: kNullProtoObject, context: 'signals' },
);

const resultSignal = new AbortSignal(kDontThrowSymbol, { composite: true });
const resultSignal = new AbortSignal(kDontThrowSymbol, { __proto__: kNullProtoObject, composite: true });
if (!signalsArray.length) {
return resultSignal;
}
Expand Down Expand Up @@ -423,7 +433,7 @@ class AbortSignal extends EventTarget {
if (aborted) {
const reason = this.reason;
return {
data: { aborted, reason },
data: { __proto__: kNullProtoObject, aborted, reason },
deserializeInfo: 'internal/abort_controller:ClonedAbortSignal',
};
}
Expand All @@ -434,10 +444,10 @@ class AbortSignal extends EventTarget {
this.addEventListener('abort', () => {
port1.postMessage(this.reason);
port1.close();
}, { once: true });
}, { __proto__: kNullProtoObject, once: true });

return {
data: { port: port2 },
data: { __proto__: kNullProtoObject, port: port2 },
deserializeInfo: 'internal/abort_controller:ClonedAbortSignal',
};
}
Expand Down Expand Up @@ -477,16 +487,20 @@ class AbortSignal extends EventTarget {
converters['sequence<AbortSignal>'] = createSequenceConverter(converters.AbortSignal);

function ClonedAbortSignal() {
return new AbortSignal(kDontThrowSymbol, { transferable: true });
return new AbortSignal(kDontThrowSymbol, { __proto__: kNullProtoObject, transferable: true });
}
ClonedAbortSignal.prototype[kDeserialize] = () => {};

ObjectDefineProperties(AbortSignal.prototype, {
aborted: kEnumerableProperty,
});

// TODO(@jasnell): the kNullProtoObject is a null-prototype object but it is
// not recognized as such by the esline rule, which will need to be updated
// to recognize this pattern.
// eslint-disable-next-line node-core/avoid-prototype-pollution
ObjectDefineProperty(AbortSignal.prototype, SymbolToStringTag, {
__proto__: null,
__proto__: kNullProtoObject,
Comment on lines +498 to +503

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given this is run only once (and I think even in the snapshot) and not ref'd anywhere, I'm not sure it's worth fighting against the lint rule

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not planning to fight against the lint rule. I'm in the process of updating the lint rule.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the fact that it's run only once when building the startup? Do you know if it's still has some noticeable perf effects, or is it more for consistency sake?

writable: false,
enumerable: false,
configurable: true,
Expand Down Expand Up @@ -588,7 +602,7 @@ class AbortController {

static [kMakeTransferable]() {
const controller = new AbortController();
controller.#signal = new AbortSignal(kDontThrowSymbol, { transferable: true });
controller.#signal = new AbortSignal(kDontThrowSymbol, { __proto__: kNullProtoObject, transferable: true });
return controller;
}
}
Expand Down Expand Up @@ -619,12 +633,12 @@ function transferableAbortController() {
* @returns {Promise<void>}
*/
async function aborted(signal, resource) {
converters.AbortSignal(signal, { __proto__: null, context: 'signal' });
converters.AbortSignal(signal, { __proto__: kNullProtoObject, context: 'signal' });
validateObject(resource, 'resource', kValidateObjectAllowObjects);
if (signal.aborted)
return PromiseResolve();
const abortPromise = PromiseWithResolvers();
const opts = { __proto__: null, [kWeakHandler]: resource, once: true, [kResistStopPropagation]: true };
const opts = { __proto__: kNullProtoObject, [kWeakHandler]: resource, once: true, [kResistStopPropagation]: true };
signal.addEventListener('abort', abortPromise.resolve, opts);
return abortPromise.promise;
}
Expand All @@ -634,8 +648,9 @@ ObjectDefineProperties(AbortController.prototype, {
abort: kEnumerableProperty,
});

// eslint-disable-next-line node-core/avoid-prototype-pollution
ObjectDefineProperty(AbortController.prototype, SymbolToStringTag, {
__proto__: null,
__proto__: kNullProtoObject,
Comment thread
jasnell marked this conversation as resolved.
writable: false,
enumerable: false,
configurable: true,
Expand Down
Loading