Skip to content

Commit

Permalink
perf_hooks: fix webperf idlharness
Browse files Browse the repository at this point in the history
1. Enforce receiver checks on IDL interfaces.
2. Avoid prototype manipulation on constructing IDL interfaces with
   `ReflectConstruct`.
3. `defineReplaceableAttribute` should create IDL getter/setter.
4. Corrected `PerformanceResourceTiming` to inherit the public interface
   `PerformanceEntry` instead of the internal interface
   `InternalPerformanceResourceTiming`.
5. `detail` is not a specified attribute on `PerfomanceEntry`. Node.js
   specific extensions are moved to a subclass of `PerformanceEntry` as
   `PerformanceNodeEntry`.

PR-URL: #44483
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
legendecas committed Oct 3, 2022
1 parent f529f73 commit 364c0e1
Show file tree
Hide file tree
Showing 218 changed files with 8,089 additions and 529 deletions.
316 changes: 271 additions & 45 deletions doc/api/perf_hooks.md

Large diffs are not rendered by default.

31 changes: 25 additions & 6 deletions lib/internal/bootstrap/browser.js
Expand Up @@ -75,8 +75,8 @@ exposeInterface(globalThis, 'Blob', buffer.Blob);
// https://www.w3.org/TR/hr-time-2/#the-performance-attribute
const perf_hooks = require('perf_hooks');
exposeInterface(globalThis, 'Performance', perf_hooks.Performance);
defineReplacableAttribute(globalThis, 'performance',
perf_hooks.performance);
defineReplaceableAttribute(globalThis, 'performance',
perf_hooks.performance);

function createGlobalConsole() {
const consoleFromNode =
Expand Down Expand Up @@ -114,14 +114,33 @@ function exposeGetterAndSetter(target, name, getter, setter = undefined) {
});
}

// https://heycam.github.io/webidl/#Replaceable
function defineReplacableAttribute(target, name, value) {
// https://webidl.spec.whatwg.org/#Replaceable
function defineReplaceableAttribute(target, name, value) {
let slot = value;

// https://webidl.spec.whatwg.org/#dfn-attribute-getter
function get() {
return slot;
}
ObjectDefineProperty(get, 'name', {
__proto__: null,
value: `get ${name}`,
});

function set(value) {
slot = value;
}
ObjectDefineProperty(set, 'name', {
__proto__: null,
value: `set ${name}`,
});

ObjectDefineProperty(target, name, {
__proto__: null,
writable: true,
enumerable: true,
configurable: true,
value,
get,
set,
});
}

Expand Down
75 changes: 59 additions & 16 deletions lib/internal/perf/observe.js
Expand Up @@ -16,9 +16,11 @@ const {
ObjectDefineProperties,
ObjectFreeze,
ObjectKeys,
ReflectConstruct,
SafeMap,
SafeSet,
Symbol,
SymbolToStringTag,
} = primordials;

const {
Expand All @@ -36,12 +38,13 @@ const {
} = internalBinding('performance');

const {
InternalPerformanceEntry,
isPerformanceEntry,
createPerformanceNodeEntry,
} = require('internal/perf/performance_entry');

const {
codes: {
ERR_ILLEGAL_CONSTRUCTOR,
ERR_INVALID_ARG_VALUE,
ERR_INVALID_ARG_TYPE,
ERR_MISSING_ARGS,
Expand All @@ -51,13 +54,15 @@ const {
const {
validateFunction,
validateObject,
validateInternalField,
} = require('internal/validators');

const {
customInspectSymbol: kInspect,
deprecate,
lazyDOMException,
kEmptyObject,
kEnumerableProperty,
} = require('internal/util');

const {
Expand All @@ -68,6 +73,7 @@ const { inspect } = require('util');

const { now } = require('internal/perf/utils');

const kBuffer = Symbol('kBuffer');
const kDispatch = Symbol('kDispatch');
const kMaybeBuffer = Symbol('kMaybeBuffer');
const kDeprecatedFields = Symbol('kDeprecatedFields');
Expand Down Expand Up @@ -167,34 +173,39 @@ function maybeIncrementObserverCount(type) {
}

class PerformanceObserverEntryList {
#buffer = [];

constructor(entries) {
this.#buffer = ArrayPrototypeSort(entries, (first, second) => {
return first.startTime - second.startTime;
});
constructor() {
throw new ERR_ILLEGAL_CONSTRUCTOR();
}

getEntries() {
return ArrayPrototypeSlice(this.#buffer);
validateInternalField(this, kBuffer, 'PerformanceObserverEntryList');
return ArrayPrototypeSlice(this[kBuffer]);
}

getEntriesByType(type) {
validateInternalField(this, kBuffer, 'PerformanceObserverEntryList');
if (arguments.length === 0) {
throw new ERR_MISSING_ARGS('type');
}
type = `${type}`;
return ArrayPrototypeFilter(
this.#buffer,
this[kBuffer],
(entry) => entry.entryType === type);
}

getEntriesByName(name, type) {
getEntriesByName(name, type = undefined) {
validateInternalField(this, kBuffer, 'PerformanceObserverEntryList');
if (arguments.length === 0) {
throw new ERR_MISSING_ARGS('name');
}
name = `${name}`;
if (type != null /** not nullish */) {
return ArrayPrototypeFilter(
this.#buffer,
this[kBuffer],
(entry) => entry.name === name && entry.entryType === type);
}
return ArrayPrototypeFilter(
this.#buffer,
this[kBuffer],
(entry) => entry.name === name);
}

Expand All @@ -206,9 +217,29 @@ class PerformanceObserverEntryList {
depth: options.depth == null ? null : options.depth - 1
};

return `PerformanceObserverEntryList ${inspect(this.#buffer, opts)}`;
return `PerformanceObserverEntryList ${inspect(this[kBuffer], opts)}`;
}
}
ObjectDefineProperties(PerformanceObserverEntryList.prototype, {
getEntries: kEnumerableProperty,
getEntriesByType: kEnumerableProperty,
getEntriesByName: kEnumerableProperty,
[SymbolToStringTag]: {
__proto__: null,
writable: false,
enumerable: false,
configurable: true,
value: 'PerformanceObserverEntryList',
},
});

function createPerformanceObserverEntryList(entries) {
return ReflectConstruct(function PerformanceObserverEntryList() {
this[kBuffer] = ArrayPrototypeSort(entries, (first, second) => {
return first.startTime - second.startTime;
});
}, [], PerformanceObserverEntryList);
}

class PerformanceObserver {
#buffer = [];
Expand Down Expand Up @@ -319,7 +350,7 @@ class PerformanceObserver {
}

[kDispatch]() {
this.#callback(new PerformanceObserverEntryList(this.takeRecords()),
this.#callback(createPerformanceObserverEntryList(this.takeRecords()),
this);
}

Expand All @@ -339,6 +370,18 @@ class PerformanceObserver {
}, opts)}`;
}
}
ObjectDefineProperties(PerformanceObserver.prototype, {
observe: kEnumerableProperty,
disconnect: kEnumerableProperty,
takeRecords: kEnumerableProperty,
[SymbolToStringTag]: {
__proto__: null,
writable: false,
enumerable: false,
configurable: true,
value: 'PerformanceObserver',
},
});

/**
* https://www.w3.org/TR/performance-timeline/#dfn-queue-a-performanceentry
Expand Down Expand Up @@ -485,7 +528,7 @@ function filterBufferMapByNameAndType(name, type) {

function observerCallback(name, type, startTime, duration, details) {
const entry =
new InternalPerformanceEntry(
createPerformanceNodeEntry(
name,
type,
startTime,
Expand Down Expand Up @@ -542,7 +585,7 @@ function stopPerf(target, key, context = {}) {
return;
}
const startTime = ctx.startTime;
const entry = new InternalPerformanceEntry(
const entry = createPerformanceNodeEntry(
ctx.name,
ctx.type,
startTime,
Expand Down

0 comments on commit 364c0e1

Please sign in to comment.