Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf_hooks: resource timing idlharness #44460

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions lib/internal/bootstrap/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +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);
exposeInterface(globalThis, 'PerformanceEntry', perf_hooks.PerformanceEntry);
exposeInterface(globalThis, 'PerformanceResourceTiming', perf_hooks.PerformanceResourceTiming);
defineReplacableAttribute(globalThis, 'performance',
perf_hooks.performance);

Expand Down
65 changes: 39 additions & 26 deletions lib/internal/event_target.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const {
ERR_INVALID_THIS,
}
} = require('internal/errors');
const { validateObject, validateString } = require('internal/validators');
const { validateObject, validateString, validateInternalField } = require('internal/validators');

const {
customInspectSymbol,
Expand Down Expand Up @@ -492,6 +492,7 @@ function initEventTarget(self) {
self[kEvents] = new SafeMap();
self[kMaxEventTargetListeners] = EventEmitter.defaultMaxListeners;
self[kMaxEventTargetListenersWarned] = false;
self[kHandlers] = new SafeMap();
}

class EventTarget {
Expand Down Expand Up @@ -1021,34 +1022,46 @@ function makeEventHandler(handler) {

function defineEventHandler(emitter, name) {
// 8.1.5.1 Event handlers - basically `on[eventName]` attributes
ObjectDefineProperty(emitter, `on${name}`, {
const propName = `on${name}`;
function get() {
validateInternalField(this, kHandlers, 'EventTarget');
return this[kHandlers]?.get(name)?.handler ?? null;
}
ObjectDefineProperty(get, 'name', {
__proto__: null,
get() {
return this[kHandlers]?.get(name)?.handler ?? null;
},
set(value) {
if (!this[kHandlers]) {
this[kHandlers] = new SafeMap();
value: `get ${propName}`,
});

function set(value) {
validateInternalField(this, kHandlers, 'EventTarget');
let wrappedHandler = this[kHandlers]?.get(name);
if (wrappedHandler) {
if (typeof wrappedHandler.handler === 'function') {
this[kEvents].get(name).size--;
const size = this[kEvents].get(name).size;
this[kRemoveListener](size, name, wrappedHandler.handler, false);
}
let wrappedHandler = this[kHandlers]?.get(name);
if (wrappedHandler) {
if (typeof wrappedHandler.handler === 'function') {
this[kEvents].get(name).size--;
const size = this[kEvents].get(name).size;
this[kRemoveListener](size, name, wrappedHandler.handler, false);
}
wrappedHandler.handler = value;
if (typeof wrappedHandler.handler === 'function') {
this[kEvents].get(name).size++;
const size = this[kEvents].get(name).size;
this[kNewListener](size, name, value, false, false, false, false);
}
} else {
wrappedHandler = makeEventHandler(value);
this.addEventListener(name, wrappedHandler);
wrappedHandler.handler = value;
if (typeof wrappedHandler.handler === 'function') {
this[kEvents].get(name).size++;
const size = this[kEvents].get(name).size;
this[kNewListener](size, name, value, false, false, false, false);
}
this[kHandlers].set(name, wrappedHandler);
},
} else {
wrappedHandler = makeEventHandler(value);
this.addEventListener(name, wrappedHandler);
}
this[kHandlers].set(name, wrappedHandler);
}
ObjectDefineProperty(set, 'name', {
__proto__: null,
value: `set ${propName}`,
});

ObjectDefineProperty(emitter, propName, {
__proto__: null,
get,
set,
configurable: true,
enumerable: true
});
Expand Down
6 changes: 5 additions & 1 deletion lib/internal/perf/observe.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ const {
const {
validateFunction,
validateObject,
validateInteger,
validateInternalField,
} = require('internal/validators');

const {
Expand All @@ -66,7 +68,7 @@ const {

const { inspect } = require('util');

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

const kDispatch = Symbol('kDispatch');
const kMaybeBuffer = Symbol('kMaybeBuffer');
Expand Down Expand Up @@ -431,6 +433,8 @@ function bufferResourceTiming(entry) {

// https://w3c.github.io/resource-timing/#dom-performance-setresourcetimingbuffersize
function setResourceTimingBufferSize(maxSize) {
validateInteger(maxSize, 'maxSize', 0);
validateInternalField(this, kPerformanceBrand, 'Performance');
// If the maxSize parameter is less than resource timing buffer current
// size, no PerformanceResourceTiming objects are to be removed from the
// performance entry buffer.
Expand Down
58 changes: 45 additions & 13 deletions lib/internal/perf/performance.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ const {
EventTarget,
Event,
kTrustEvent,
defineEventHandler,
} = require('internal/event_target');

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

const { markResourceTiming } = require('internal/perf/resource_timing');

Expand All @@ -40,6 +44,7 @@ const nodeTiming = require('internal/perf/nodetiming');
const timerify = require('internal/perf/timerify');
const { customInspectSymbol: kInspect } = require('internal/util');
const { inspect } = require('util');
const { validateInternalField } = require('internal/validators');

const {
getTimeOriginTimestamp
Expand Down Expand Up @@ -88,7 +93,8 @@ function clearMeasures(name) {
clearEntriesFromBuffer('measure', name);
}

function clearResourceTimings(name) {
function clearResourceTimings(name = undefined) {
validateInternalField(this, kPerformanceBrand, 'Performance');
if (name !== undefined) {
name = `${name}`;
}
Expand All @@ -115,95 +121,118 @@ function getEntriesByType(type) {
return filterBufferMapByNameAndType(undefined, type);
}

class InternalPerformance extends EventTarget {}
class InternalPerformance extends EventTarget {
constructor() {
super();
this[kPerformanceBrand] = true;
}
}
InternalPerformance.prototype.constructor = Performance.prototype.constructor;
ObjectSetPrototypeOf(InternalPerformance.prototype, Performance.prototype);

ObjectDefineProperties(Performance.prototype, {
clearMarks: {
__proto__: null,
configurable: true,
enumerable: false,
enumerable: true,
writable: true,
value: clearMarks,
},
clearMeasures: {
__proto__: null,
configurable: true,
enumerable: false,
enumerable: true,
writable: true,
value: clearMeasures,
},
clearResourceTimings: {
__proto__: null,
configurable: true,
enumerable: false,
enumerable: true,
writable: true,
value: clearResourceTimings,
},
eventLoopUtilization: {
__proto__: null,
configurable: true,
// Node.js specific extensions.
enumerable: false,
writable: true,
value: eventLoopUtilization,
},
getEntries: {
__proto__: null,
configurable: true,
enumerable: false,
enumerable: true,
writable: true,
value: getEntries,
},
getEntriesByName: {
__proto__: null,
configurable: true,
enumerable: false,
enumerable: true,
writable: true,
value: getEntriesByName,
},
getEntriesByType: {
__proto__: null,
configurable: true,
enumerable: false,
enumerable: true,
writable: true,
value: getEntriesByType,
},
mark: {
__proto__: null,
configurable: true,
enumerable: false,
enumerable: true,
writable: true,
value: mark,
},
measure: {
__proto__: null,
configurable: true,
enumerable: false,
enumerable: true,
writable: true,
value: measure,
},
nodeTiming: {
__proto__: null,
configurable: true,
// Node.js specific extensions.
enumerable: false,
writable: true,
value: nodeTiming,
},
// In the browser, this function is not public. However, it must be used inside fetch
// which is a Node.js dependency, not a internal module
markResourceTiming: {
__proto__: null,
configurable: true,
// Node.js specific extensions.
enumerable: false,
writable: true,
value: markResourceTiming,
},
now: {
__proto__: null,
configurable: true,
enumerable: false,
enumerable: true,
writable: true,
value: now,
},
setResourceTimingBufferSize: {
__proto__: null,
configurable: true,
enumerable: false,
enumerable: true,
writable: true,
value: setResourceTimingBufferSize
},
timerify: {
__proto__: null,
configurable: true,
// Node.js specific extensions.
enumerable: false,
writable: true,
value: timerify,
},
// This would be updated during pre-execution in case
Expand All @@ -214,15 +243,18 @@ ObjectDefineProperties(Performance.prototype, {
__proto__: null,
configurable: true,
enumerable: true,
writable: true,
value: getTimeOriginTimestamp(),
},
toJSON: {
__proto__: null,
configurable: true,
enumerable: true,
writable: true,
value: toJSON,
}
});
defineEventHandler(Performance.prototype, 'resourcetimingbufferfull');

function refreshTimeOrigin() {
ObjectDefineProperty(Performance.prototype, 'timeOrigin', {
Expand Down
Loading