Keep canonical callback ownership independent of writable raw-listener metadata. Resolve the native removal argument in current registration order, then let EventEmitter own mutation, getter timing and removal meta-events. Leave registrations unwrapped with explicit observation gaps when methods or receivers do not support that ownership model. Preserve per-callback Evidence for supported registrations and document the remaining limits. Fixes #4513
1330 lines
44 KiB
JavaScript
1330 lines
44 KiB
JavaScript
"use strict";
|
|
|
|
const applyFunction = Reflect.apply;
|
|
const applyArguments = Function.prototype.apply;
|
|
const bindFunction = Function.prototype.bind;
|
|
const callFunction = Function.prototype.call;
|
|
const arrayFrom = Array.from;
|
|
const arrayIsArray = Array.isArray;
|
|
const defineProperty = Object.defineProperty;
|
|
const ownPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
|
const getPrototypeOf = Object.getPrototypeOf;
|
|
const nativeFunctionPrototype = getPrototypeOf(callFunction);
|
|
const getProperty = Reflect.get;
|
|
const setProperty = Reflect.set;
|
|
const SetConstructor = Set;
|
|
const ProxyConstructor = Proxy;
|
|
const bindBuiltinMethod = (method) =>
|
|
applyFunction(bindFunction, callFunction, [method]);
|
|
const forEachMapEntry = bindBuiltinMethod(Map.prototype.forEach);
|
|
const sliceArguments = bindBuiltinMethod(Array.prototype.slice);
|
|
const weakMapHas = bindBuiltinMethod(WeakMap.prototype.has);
|
|
const weakMapGet = bindBuiltinMethod(WeakMap.prototype.get);
|
|
const weakMapSet = bindBuiltinMethod(WeakMap.prototype.set);
|
|
const weakSetAdd = bindBuiltinMethod(WeakSet.prototype.add);
|
|
const weakSetHas = bindBuiltinMethod(WeakSet.prototype.has);
|
|
const setHas = bindBuiltinMethod(Set.prototype.has);
|
|
const setAdd = bindBuiltinMethod(Set.prototype.add);
|
|
const hasOwnProperty = bindBuiltinMethod(Object.prototype.hasOwnProperty);
|
|
|
|
const { isProxy } = require("node:util").types;
|
|
const { EventEmitter: NodeEventEmitter } = require("node:events");
|
|
const nodeEventEmitterMethods = Object.create(null);
|
|
for (const method of [
|
|
"on",
|
|
"once",
|
|
"off",
|
|
"removeListener",
|
|
"removeAllListeners",
|
|
]) {
|
|
const descriptor = ownPropertyDescriptor(NodeEventEmitter.prototype, method);
|
|
nodeEventEmitterMethods[method] =
|
|
descriptor !== undefined && hasOwnProperty(descriptor, "value")
|
|
? descriptor.value
|
|
: undefined;
|
|
}
|
|
const {
|
|
createElectronActiveBoundaryPatches,
|
|
} = require("./electron-active-hook-boundaries.cjs");
|
|
|
|
const ipcEventKinds = new SetConstructor([
|
|
"main-handler-invocation",
|
|
"main-event-invocation",
|
|
"utility-process-fork",
|
|
"utility-process-message",
|
|
"ipc-main-to-renderer",
|
|
"ipc-utility-to-main",
|
|
"ipc-renderer-send",
|
|
"ipc-renderer-invoke",
|
|
"ipc-renderer-post-message",
|
|
]);
|
|
const events = [];
|
|
// Budget serialized data and estimated retained object/array storage together.
|
|
const retentionBudgetBytes = 16 * 1024 * 1024;
|
|
const snapshotEnvelopeReserveBytes = 1024;
|
|
let estimatedRetainedBytes = 0;
|
|
let serializedBytes = 0;
|
|
let observed = 0;
|
|
let observedIpc = 0;
|
|
let observedRuntime = 0;
|
|
let dropped = 0;
|
|
let droppedIpc = 0;
|
|
let droppedRuntime = 0;
|
|
const droppedFamilies = new Map();
|
|
const droppedRoles = new Map();
|
|
let sequence = 0;
|
|
let correlationSequence = 0;
|
|
|
|
const shape = (value, depth = 0) => {
|
|
if (depth > 2 || value === null) return value === null ? "null" : "nested";
|
|
if (arrayIsArray(value)) return "array";
|
|
switch (typeof value) {
|
|
case "string":
|
|
return "string";
|
|
case "number":
|
|
return "number";
|
|
case "boolean":
|
|
return "boolean";
|
|
case "undefined":
|
|
return "undefined";
|
|
case "function":
|
|
return "function";
|
|
case "object":
|
|
return "object";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
};
|
|
|
|
// Measure JSON strings without allocating an encoded copy of a caller value.
|
|
const jsonStringBytes = (value) => {
|
|
let bytes = 2;
|
|