Skip to content

Commit

Permalink
perf_hooks: resource timing idlharness
Browse files Browse the repository at this point in the history
  • Loading branch information
legendecas committed Aug 30, 2022
1 parent 5d32b3b commit 04099b8
Show file tree
Hide file tree
Showing 205 changed files with 7,373 additions and 223 deletions.
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}`;
const get = 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}`,
});

const set = 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
2 changes: 2 additions & 0 deletions lib/internal/perf/observe.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const {
validateFunction,
validateObject,
validateInteger,
validateInternalField,
} = require('internal/validators');

const {
Expand Down Expand Up @@ -433,6 +434,7 @@ 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
60 changes: 45 additions & 15 deletions lib/internal/perf/resource_timing.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use strict';
// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming

const { InternalPerformanceEntry } = require('internal/perf/performance_entry');
const { SymbolToStringTag } = primordials;
const { InternalPerformanceEntry, PerformanceEntry } = require('internal/perf/performance_entry');
const { ObjectDefineProperties, SymbolToStringTag } = primordials;
const assert = require('internal/assert');
const { enqueue, bufferResourceTiming } = require('internal/perf/observe');
const { Symbol, ObjectSetPrototypeOf } = primordials;
Expand All @@ -17,17 +17,12 @@ const {
ERR_ILLEGAL_CONSTRUCTOR,
}
} = require('internal/errors');
const { validateInternalField } = require('internal/validators');
const { kEnumerableProperty } = require('internal/util');

class InternalPerformanceResourceTiming extends InternalPerformanceEntry {
constructor(requestedUrl, initiatorType, timingInfo, cacheMode = '') {
super(requestedUrl, 'resource');
this[kInitiatorType] = initiatorType;
this[kRequestedUrl] = requestedUrl;
// https://fetch.spec.whatwg.org/#fetch-timing-info
// This class is using timingInfo assuming it's already validated.
// The spec doesn't say to validate it in the class construction.
this[kTimingInfo] = timingInfo;
this[kCacheMode] = cacheMode;
class PerformanceResourceTiming extends PerformanceEntry {
constructor() {
throw new ERR_ILLEGAL_CONSTRUCTOR();
}

get [SymbolToStringTag]() {
Expand All @@ -47,6 +42,7 @@ class InternalPerformanceResourceTiming extends InternalPerformanceEntry {
}

get initiatorType() {
validateInternalField(this, kInitiatorType, 'PerformanceResourceTiming');
return this[kInitiatorType];
}

Expand Down Expand Up @@ -120,6 +116,7 @@ class InternalPerformanceResourceTiming extends InternalPerformanceEntry {
}

toJSON() {
validateInternalField(this, kInitiatorType, 'PerformanceResourceTiming');
return {
name: this.name,
entryType: this.entryType,
Expand All @@ -146,12 +143,45 @@ class InternalPerformanceResourceTiming extends InternalPerformanceEntry {
}
}

class PerformanceResourceTiming extends InternalPerformanceResourceTiming {
constructor() {
throw new ERR_ILLEGAL_CONSTRUCTOR();
ObjectDefineProperties(PerformanceResourceTiming.prototype, {
initiatorType: kEnumerableProperty,
nextHopProtocol: kEnumerableProperty,
workerStart: kEnumerableProperty,
redirectStart: kEnumerableProperty,
redirectEnd: kEnumerableProperty,
fetchStart: kEnumerableProperty,
domainLookupStart: kEnumerableProperty,
domainLookupEnd: kEnumerableProperty,
connectStart: kEnumerableProperty,
connectEnd: kEnumerableProperty,
secureConnectionStart: kEnumerableProperty,
requestStart: kEnumerableProperty,
responseStart: kEnumerableProperty,
responseEnd: kEnumerableProperty,
transferSize: kEnumerableProperty,
encodedBodySize: kEnumerableProperty,
decodedBodySize: kEnumerableProperty,
toJSON: kEnumerableProperty,
});

class InternalPerformanceResourceTiming extends InternalPerformanceEntry {
constructor(requestedUrl, initiatorType, timingInfo, cacheMode = '') {
super(requestedUrl, 'resource');
this[kInitiatorType] = initiatorType;
this[kRequestedUrl] = requestedUrl;
// https://fetch.spec.whatwg.org/#fetch-timing-info
// This class is using timingInfo assuming it's already validated.
// The spec doesn't say to validate it in the class construction.
this[kTimingInfo] = timingInfo;
this[kCacheMode] = cacheMode;
}
}

InternalPerformanceEntry.prototype.constructor = PerformanceEntry;
ObjectSetPrototypeOf(
InternalPerformanceEntry.prototype,
PerformanceEntry.prototype);

// https://w3c.github.io/resource-timing/#dfn-mark-resource-timing
function markResourceTiming(
timingInfo,
Expand Down
Loading

0 comments on commit 04099b8

Please sign in to comment.