Skip to content

Commit

Permalink
lib: initialize instance members in class constructors
Browse files Browse the repository at this point in the history
Since V8 snapshot does not currently support instance member
initialization, initialize them in ordianry class constructors
for now so that these classes can be included in the snapshot.
This may be reverted once
https://bugs.chromium.org/p/v8/issues/detail?id=10704
is fixed and backported.

PR-URL: #32984
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
  • Loading branch information
joyeecheung committed Jul 18, 2020
1 parent f8bde7c commit b1c3909
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 53 deletions.
11 changes: 7 additions & 4 deletions lib/internal/abort_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,18 @@ function abortSignal(signal) {
signal.dispatchEvent(event);
}

// TODO(joyeecheung): V8 snapshot does not support instance member
// initializers for now:
// https://bugs.chromium.org/p/v8/issues/detail?id=10704
const kSignal = Symbol('signal');
class AbortController {
#signal = new AbortSignal();

constructor() {
this[kSignal] = new AbortSignal();
emitExperimentalWarning('AbortController');
}

get signal() { return this.#signal; }
abort() { abortSignal(this.#signal); }
get signal() { return this[kSignal]; }
abort() { abortSignal(this[kSignal]); }

[customInspectSymbol](depth, options) {
return customInspect(this, {
Expand Down
98 changes: 49 additions & 49 deletions lib/internal/event_target.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,32 +42,30 @@ function lazyNow() {
return perf_hooks.performance.now();
}

// TODO(joyeecheung): V8 snapshot does not support instance member
// initializers for now:
// https://bugs.chromium.org/p/v8/issues/detail?id=10704
const kType = Symbol('type');
const kDefaultPrevented = Symbol('defaultPrevented');
const kCancelable = Symbol('cancelable');
const kTimestamp = Symbol('timestamp');
const kBubbles = Symbol('bubbles');
const kComposed = Symbol('composed');
const kPropagationStopped = Symbol('propagationStopped');
class Event {
#type = undefined;
#defaultPrevented = false;
#cancelable = false;
#timestamp = lazyNow();

// None of these are currently used in the Node.js implementation
// of EventTarget because there is no concept of bubbling or
// composition. We preserve their values in Event but they are
// non-ops and do not carry any semantics in Node.js
#bubbles = false;
#composed = false;
#propagationStopped = false;


constructor(type, options) {
if (arguments.length === 0)
throw new ERR_MISSING_ARGS('type');
if (options != null)
validateObject(options, 'options');
const { cancelable, bubbles, composed } = { ...options };
this.#cancelable = !!cancelable;
this.#bubbles = !!bubbles;
this.#composed = !!composed;
this.#type = `${type}`;
this.#propagationStopped = false;
this[kCancelable] = !!cancelable;
this[kBubbles] = !!bubbles;
this[kComposed] = !!composed;
this[kType] = `${type}`;
this[kDefaultPrevented] = false;
this[kTimestamp] = lazyNow();
this[kPropagationStopped] = false;
// isTrusted is special (LegacyUnforgeable)
Object.defineProperty(this, 'isTrusted', {
get() { return false; },
Expand All @@ -87,10 +85,10 @@ class Event {
});

return `${name} ${inspect({
type: this.#type,
defaultPrevented: this.#defaultPrevented,
cancelable: this.#cancelable,
timeStamp: this.#timestamp,
type: this[kType],
defaultPrevented: this[kDefaultPrevented],
cancelable: this[kCancelable],
timeStamp: this[kTimestamp],
}, opts)}`;
}

Expand All @@ -99,20 +97,22 @@ class Event {
}

preventDefault() {
this.#defaultPrevented = true;
this[kDefaultPrevented] = true;
}

get target() { return this[kTarget]; }
get currentTarget() { return this[kTarget]; }
get srcElement() { return this[kTarget]; }

get type() { return this.#type; }
get type() { return this[kType]; }

get cancelable() { return this.#cancelable; }
get cancelable() { return this[kCancelable]; }

get defaultPrevented() { return this.#cancelable && this.#defaultPrevented; }
get defaultPrevented() {
return this[kCancelable] && this[kDefaultPrevented];
}

get timeStamp() { return this.#timestamp; }
get timeStamp() { return this[kTimestamp]; }


// The following are non-op and unused properties/methods from Web API Event.
Expand All @@ -121,19 +121,19 @@ class Event {

composedPath() { return this[kTarget] ? [this[kTarget]] : []; }
get returnValue() { return !this.defaultPrevented; }
get bubbles() { return this.#bubbles; }
get composed() { return this.#composed; }
get bubbles() { return this[kBubbles]; }
get composed() { return this[kComposed]; }
get eventPhase() {
return this[kTarget] ? Event.AT_TARGET : Event.NONE;
}
get cancelBubble() { return this.#propagationStopped; }
get cancelBubble() { return this[kPropagationStopped]; }
set cancelBubble(value) {
if (value) {
this.stopPropagation();
}
}
stopPropagation() {
this.#propagationStopped = true;
this[kPropagationStopped] = true;
}

static NONE = 0;
Expand All @@ -157,15 +157,8 @@ Object.defineProperty(Event.prototype, SymbolToStringTag, {
// the linked list makes dispatching faster, even if adding/removing is
// slower.
class Listener {
next;
previous;
listener;
callback;
once;
capture;
passive;

constructor(previous, listener, once, capture, passive) {
this.next = undefined;
if (previous !== undefined)
previous.next = this;
this.previous = previous;
Expand Down Expand Up @@ -197,7 +190,9 @@ class EventTarget {
// symbol as EventTarget may be used cross-realm. See discussion in #33661.
static [kIsEventTarget] = true;

[kEvents] = new Map();
constructor() {
this[kEvents] = new Map();
}

[kNewListener](size, type, listener, once, capture, passive) {}
[kRemoveListener](size, type, listener, capture) {}
Expand Down Expand Up @@ -355,17 +350,22 @@ Object.defineProperty(EventTarget.prototype, SymbolToStringTag, {
value: 'EventTarget',
});

const kMaxListeners = Symbol('maxListeners');
const kMaxListenersWarned = Symbol('maxListenersWarned');
class NodeEventTarget extends EventTarget {
static defaultMaxListeners = 10;

#maxListeners = NodeEventTarget.defaultMaxListeners;
#maxListenersWarned = false;
constructor() {
super();
this[kMaxListeners] = NodeEventTarget.defaultMaxListeners;
this[kMaxListenersWarned] = false;
}

[kNewListener](size, type, listener, once, capture, passive) {
if (this.#maxListeners > 0 &&
size > this.#maxListeners &&
!this.#maxListenersWarned) {
this.#maxListenersWarned = true;
if (this[kMaxListeners] > 0 &&
size > this[kMaxListeners] &&
!this[kMaxListenersWarned]) {
this[kMaxListenersWarned] = true;
// No error code for this since it is a Warning
// eslint-disable-next-line no-restricted-syntax
const w = new Error('Possible EventTarget memory leak detected. ' +
Expand All @@ -382,12 +382,12 @@ class NodeEventTarget extends EventTarget {

setMaxListeners(n) {
validateInteger(n, 'n', 0);
this.#maxListeners = n;
this[kMaxListeners] = n;
return this;
}

getMaxListeners() {
return this.#maxListeners;
return this[kMaxListeners];
}

eventNames() {
Expand Down

0 comments on commit b1c3909

Please sign in to comment.