11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst {
41cb0ef41Sopenharmony_ci  ArrayFrom,
51cb0ef41Sopenharmony_ci  ArrayIsArray,
61cb0ef41Sopenharmony_ci  ArrayPrototypeFilter,
71cb0ef41Sopenharmony_ci  ArrayPrototypeIncludes,
81cb0ef41Sopenharmony_ci  ArrayPrototypePush,
91cb0ef41Sopenharmony_ci  ArrayPrototypePushApply,
101cb0ef41Sopenharmony_ci  ArrayPrototypeSlice,
111cb0ef41Sopenharmony_ci  ArrayPrototypeSort,
121cb0ef41Sopenharmony_ci  Error,
131cb0ef41Sopenharmony_ci  MathMax,
141cb0ef41Sopenharmony_ci  MathMin,
151cb0ef41Sopenharmony_ci  ObjectDefineProperties,
161cb0ef41Sopenharmony_ci  ObjectFreeze,
171cb0ef41Sopenharmony_ci  ObjectKeys,
181cb0ef41Sopenharmony_ci  SafeMap,
191cb0ef41Sopenharmony_ci  SafeSet,
201cb0ef41Sopenharmony_ci  Symbol,
211cb0ef41Sopenharmony_ci} = primordials;
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ciconst {
241cb0ef41Sopenharmony_ci  constants: {
251cb0ef41Sopenharmony_ci    NODE_PERFORMANCE_ENTRY_TYPE_GC,
261cb0ef41Sopenharmony_ci    NODE_PERFORMANCE_ENTRY_TYPE_HTTP2,
271cb0ef41Sopenharmony_ci    NODE_PERFORMANCE_ENTRY_TYPE_HTTP,
281cb0ef41Sopenharmony_ci    NODE_PERFORMANCE_ENTRY_TYPE_NET,
291cb0ef41Sopenharmony_ci    NODE_PERFORMANCE_ENTRY_TYPE_DNS,
301cb0ef41Sopenharmony_ci  },
311cb0ef41Sopenharmony_ci  installGarbageCollectionTracking,
321cb0ef41Sopenharmony_ci  observerCounts,
331cb0ef41Sopenharmony_ci  removeGarbageCollectionTracking,
341cb0ef41Sopenharmony_ci  setupObservers,
351cb0ef41Sopenharmony_ci} = internalBinding('performance');
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ciconst {
381cb0ef41Sopenharmony_ci  InternalPerformanceEntry,
391cb0ef41Sopenharmony_ci  isPerformanceEntry,
401cb0ef41Sopenharmony_ci} = require('internal/perf/performance_entry');
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ciconst {
431cb0ef41Sopenharmony_ci  codes: {
441cb0ef41Sopenharmony_ci    ERR_INVALID_ARG_VALUE,
451cb0ef41Sopenharmony_ci    ERR_INVALID_ARG_TYPE,
461cb0ef41Sopenharmony_ci    ERR_MISSING_ARGS,
471cb0ef41Sopenharmony_ci  },
481cb0ef41Sopenharmony_ci} = require('internal/errors');
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ciconst {
511cb0ef41Sopenharmony_ci  validateFunction,
521cb0ef41Sopenharmony_ci  validateObject,
531cb0ef41Sopenharmony_ci} = require('internal/validators');
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ciconst {
561cb0ef41Sopenharmony_ci  customInspectSymbol: kInspect,
571cb0ef41Sopenharmony_ci  deprecate,
581cb0ef41Sopenharmony_ci  lazyDOMException,
591cb0ef41Sopenharmony_ci  kEmptyObject,
601cb0ef41Sopenharmony_ci} = require('internal/util');
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ciconst {
631cb0ef41Sopenharmony_ci  setImmediate,
641cb0ef41Sopenharmony_ci} = require('timers');
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ciconst { inspect } = require('util');
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ciconst { now } = require('internal/perf/utils');
691cb0ef41Sopenharmony_ciconst { convertToInt } = require('internal/webidl');
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ciconst kDispatch = Symbol('kDispatch');
721cb0ef41Sopenharmony_ciconst kMaybeBuffer = Symbol('kMaybeBuffer');
731cb0ef41Sopenharmony_ciconst kDeprecatedFields = Symbol('kDeprecatedFields');
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ciconst kDeprecationMessage =
761cb0ef41Sopenharmony_ci  'Custom PerformanceEntry accessors are deprecated. ' +
771cb0ef41Sopenharmony_ci  'Please use the detail property.';
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ciconst kTypeSingle = 0;
801cb0ef41Sopenharmony_ciconst kTypeMultiple = 1;
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_cilet gcTrackingInstalled = false;
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ciconst kSupportedEntryTypes = ObjectFreeze([
851cb0ef41Sopenharmony_ci  'dns',
861cb0ef41Sopenharmony_ci  'function',
871cb0ef41Sopenharmony_ci  'gc',
881cb0ef41Sopenharmony_ci  'http',
891cb0ef41Sopenharmony_ci  'http2',
901cb0ef41Sopenharmony_ci  'mark',
911cb0ef41Sopenharmony_ci  'measure',
921cb0ef41Sopenharmony_ci  'net',
931cb0ef41Sopenharmony_ci  'resource',
941cb0ef41Sopenharmony_ci]);
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci// Performance timeline entry Buffers
971cb0ef41Sopenharmony_cilet markEntryBuffer = [];
981cb0ef41Sopenharmony_cilet measureEntryBuffer = [];
991cb0ef41Sopenharmony_cilet resourceTimingBuffer = [];
1001cb0ef41Sopenharmony_cilet resourceTimingSecondaryBuffer = [];
1011cb0ef41Sopenharmony_ciconst kPerformanceEntryBufferWarnSize = 1e6;
1021cb0ef41Sopenharmony_ci// https://www.w3.org/TR/timing-entrytypes-registry/#registry
1031cb0ef41Sopenharmony_ci// Default buffer limit for resource timing entries.
1041cb0ef41Sopenharmony_cilet resourceTimingBufferSizeLimit = 250;
1051cb0ef41Sopenharmony_cilet dispatchBufferFull;
1061cb0ef41Sopenharmony_cilet resourceTimingBufferFullPending = false;
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ciconst kClearPerformanceEntryBuffers = ObjectFreeze({
1091cb0ef41Sopenharmony_ci  'mark': 'performance.clearMarks',
1101cb0ef41Sopenharmony_ci  'measure': 'performance.clearMeasures',
1111cb0ef41Sopenharmony_ci});
1121cb0ef41Sopenharmony_ciconst kWarnedEntryTypes = new SafeMap();
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ciconst kObservers = new SafeSet();
1151cb0ef41Sopenharmony_ciconst kPending = new SafeSet();
1161cb0ef41Sopenharmony_cilet isPending = false;
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_cifunction queuePending() {
1191cb0ef41Sopenharmony_ci  if (isPending) return;
1201cb0ef41Sopenharmony_ci  isPending = true;
1211cb0ef41Sopenharmony_ci  setImmediate(() => {
1221cb0ef41Sopenharmony_ci    isPending = false;
1231cb0ef41Sopenharmony_ci    const pendings = ArrayFrom(kPending.values());
1241cb0ef41Sopenharmony_ci    kPending.clear();
1251cb0ef41Sopenharmony_ci    for (const pending of pendings)
1261cb0ef41Sopenharmony_ci      pending[kDispatch]();
1271cb0ef41Sopenharmony_ci  });
1281cb0ef41Sopenharmony_ci}
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_cifunction getObserverType(type) {
1311cb0ef41Sopenharmony_ci  switch (type) {
1321cb0ef41Sopenharmony_ci    case 'gc': return NODE_PERFORMANCE_ENTRY_TYPE_GC;
1331cb0ef41Sopenharmony_ci    case 'http2': return NODE_PERFORMANCE_ENTRY_TYPE_HTTP2;
1341cb0ef41Sopenharmony_ci    case 'http': return NODE_PERFORMANCE_ENTRY_TYPE_HTTP;
1351cb0ef41Sopenharmony_ci    case 'net': return NODE_PERFORMANCE_ENTRY_TYPE_NET;
1361cb0ef41Sopenharmony_ci    case 'dns': return NODE_PERFORMANCE_ENTRY_TYPE_DNS;
1371cb0ef41Sopenharmony_ci  }
1381cb0ef41Sopenharmony_ci}
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_cifunction maybeDecrementObserverCounts(entryTypes) {
1411cb0ef41Sopenharmony_ci  for (const type of entryTypes) {
1421cb0ef41Sopenharmony_ci    const observerType = getObserverType(type);
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci    if (observerType !== undefined) {
1451cb0ef41Sopenharmony_ci      observerCounts[observerType]--;
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci      if (observerType === NODE_PERFORMANCE_ENTRY_TYPE_GC &&
1481cb0ef41Sopenharmony_ci          observerCounts[observerType] === 0) {
1491cb0ef41Sopenharmony_ci        removeGarbageCollectionTracking();
1501cb0ef41Sopenharmony_ci        gcTrackingInstalled = false;
1511cb0ef41Sopenharmony_ci      }
1521cb0ef41Sopenharmony_ci    }
1531cb0ef41Sopenharmony_ci  }
1541cb0ef41Sopenharmony_ci}
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_cifunction maybeIncrementObserverCount(type) {
1571cb0ef41Sopenharmony_ci  const observerType = getObserverType(type);
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ci  if (observerType !== undefined) {
1601cb0ef41Sopenharmony_ci    observerCounts[observerType]++;
1611cb0ef41Sopenharmony_ci    if (!gcTrackingInstalled &&
1621cb0ef41Sopenharmony_ci        observerType === NODE_PERFORMANCE_ENTRY_TYPE_GC) {
1631cb0ef41Sopenharmony_ci      installGarbageCollectionTracking();
1641cb0ef41Sopenharmony_ci      gcTrackingInstalled = true;
1651cb0ef41Sopenharmony_ci    }
1661cb0ef41Sopenharmony_ci  }
1671cb0ef41Sopenharmony_ci}
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ciclass PerformanceObserverEntryList {
1701cb0ef41Sopenharmony_ci  #buffer = [];
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ci  constructor(entries) {
1731cb0ef41Sopenharmony_ci    this.#buffer = ArrayPrototypeSort(entries, (first, second) => {
1741cb0ef41Sopenharmony_ci      return first.startTime - second.startTime;
1751cb0ef41Sopenharmony_ci    });
1761cb0ef41Sopenharmony_ci  }
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ci  getEntries() {
1791cb0ef41Sopenharmony_ci    return ArrayPrototypeSlice(this.#buffer);
1801cb0ef41Sopenharmony_ci  }
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci  getEntriesByType(type) {
1831cb0ef41Sopenharmony_ci    type = `${type}`;
1841cb0ef41Sopenharmony_ci    return ArrayPrototypeFilter(
1851cb0ef41Sopenharmony_ci      this.#buffer,
1861cb0ef41Sopenharmony_ci      (entry) => entry.entryType === type);
1871cb0ef41Sopenharmony_ci  }
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci  getEntriesByName(name, type) {
1901cb0ef41Sopenharmony_ci    name = `${name}`;
1911cb0ef41Sopenharmony_ci    if (type != null /** not nullish */) {
1921cb0ef41Sopenharmony_ci      return ArrayPrototypeFilter(
1931cb0ef41Sopenharmony_ci        this.#buffer,
1941cb0ef41Sopenharmony_ci        (entry) => entry.name === name && entry.entryType === type);
1951cb0ef41Sopenharmony_ci    }
1961cb0ef41Sopenharmony_ci    return ArrayPrototypeFilter(
1971cb0ef41Sopenharmony_ci      this.#buffer,
1981cb0ef41Sopenharmony_ci      (entry) => entry.name === name);
1991cb0ef41Sopenharmony_ci  }
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci  [kInspect](depth, options) {
2021cb0ef41Sopenharmony_ci    if (depth < 0) return this;
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_ci    const opts = {
2051cb0ef41Sopenharmony_ci      ...options,
2061cb0ef41Sopenharmony_ci      depth: options.depth == null ? null : options.depth - 1,
2071cb0ef41Sopenharmony_ci    };
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ci    return `PerformanceObserverEntryList ${inspect(this.#buffer, opts)}`;
2101cb0ef41Sopenharmony_ci  }
2111cb0ef41Sopenharmony_ci}
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ciclass PerformanceObserver {
2141cb0ef41Sopenharmony_ci  #buffer = [];
2151cb0ef41Sopenharmony_ci  #entryTypes = new SafeSet();
2161cb0ef41Sopenharmony_ci  #type;
2171cb0ef41Sopenharmony_ci  #callback;
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci  constructor(callback) {
2201cb0ef41Sopenharmony_ci    validateFunction(callback, 'callback');
2211cb0ef41Sopenharmony_ci    this.#callback = callback;
2221cb0ef41Sopenharmony_ci  }
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_ci  observe(options = kEmptyObject) {
2251cb0ef41Sopenharmony_ci    validateObject(options, 'options');
2261cb0ef41Sopenharmony_ci    const {
2271cb0ef41Sopenharmony_ci      entryTypes,
2281cb0ef41Sopenharmony_ci      type,
2291cb0ef41Sopenharmony_ci      buffered,
2301cb0ef41Sopenharmony_ci    } = { ...options };
2311cb0ef41Sopenharmony_ci    if (entryTypes === undefined && type === undefined)
2321cb0ef41Sopenharmony_ci      throw new ERR_MISSING_ARGS('options.entryTypes', 'options.type');
2331cb0ef41Sopenharmony_ci    if (entryTypes != null && type != null)
2341cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE('options.entryTypes',
2351cb0ef41Sopenharmony_ci                                      entryTypes,
2361cb0ef41Sopenharmony_ci                                      'options.entryTypes can not set with ' +
2371cb0ef41Sopenharmony_ci                                      'options.type together');
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci    switch (this.#type) {
2401cb0ef41Sopenharmony_ci      case undefined:
2411cb0ef41Sopenharmony_ci        if (entryTypes !== undefined) this.#type = kTypeMultiple;
2421cb0ef41Sopenharmony_ci        if (type !== undefined) this.#type = kTypeSingle;
2431cb0ef41Sopenharmony_ci        break;
2441cb0ef41Sopenharmony_ci      case kTypeSingle:
2451cb0ef41Sopenharmony_ci        if (entryTypes !== undefined)
2461cb0ef41Sopenharmony_ci          throw lazyDOMException(
2471cb0ef41Sopenharmony_ci            'PerformanceObserver can not change to multiple observations',
2481cb0ef41Sopenharmony_ci            'InvalidModificationError');
2491cb0ef41Sopenharmony_ci        break;
2501cb0ef41Sopenharmony_ci      case kTypeMultiple:
2511cb0ef41Sopenharmony_ci        if (type !== undefined)
2521cb0ef41Sopenharmony_ci          throw lazyDOMException(
2531cb0ef41Sopenharmony_ci            'PerformanceObserver can not change to single observation',
2541cb0ef41Sopenharmony_ci            'InvalidModificationError');
2551cb0ef41Sopenharmony_ci        break;
2561cb0ef41Sopenharmony_ci    }
2571cb0ef41Sopenharmony_ci
2581cb0ef41Sopenharmony_ci    if (this.#type === kTypeMultiple) {
2591cb0ef41Sopenharmony_ci      if (!ArrayIsArray(entryTypes)) {
2601cb0ef41Sopenharmony_ci        throw new ERR_INVALID_ARG_TYPE(
2611cb0ef41Sopenharmony_ci          'options.entryTypes',
2621cb0ef41Sopenharmony_ci          'string[]',
2631cb0ef41Sopenharmony_ci          entryTypes);
2641cb0ef41Sopenharmony_ci      }
2651cb0ef41Sopenharmony_ci      maybeDecrementObserverCounts(this.#entryTypes);
2661cb0ef41Sopenharmony_ci      this.#entryTypes.clear();
2671cb0ef41Sopenharmony_ci      for (let n = 0; n < entryTypes.length; n++) {
2681cb0ef41Sopenharmony_ci        if (ArrayPrototypeIncludes(kSupportedEntryTypes, entryTypes[n])) {
2691cb0ef41Sopenharmony_ci          this.#entryTypes.add(entryTypes[n]);
2701cb0ef41Sopenharmony_ci          maybeIncrementObserverCount(entryTypes[n]);
2711cb0ef41Sopenharmony_ci        }
2721cb0ef41Sopenharmony_ci      }
2731cb0ef41Sopenharmony_ci    } else {
2741cb0ef41Sopenharmony_ci      if (!ArrayPrototypeIncludes(kSupportedEntryTypes, type))
2751cb0ef41Sopenharmony_ci        return;
2761cb0ef41Sopenharmony_ci      this.#entryTypes.add(type);
2771cb0ef41Sopenharmony_ci      maybeIncrementObserverCount(type);
2781cb0ef41Sopenharmony_ci      if (buffered) {
2791cb0ef41Sopenharmony_ci        const entries = filterBufferMapByNameAndType(undefined, type);
2801cb0ef41Sopenharmony_ci        ArrayPrototypePushApply(this.#buffer, entries);
2811cb0ef41Sopenharmony_ci        kPending.add(this);
2821cb0ef41Sopenharmony_ci        if (kPending.size)
2831cb0ef41Sopenharmony_ci          queuePending();
2841cb0ef41Sopenharmony_ci      }
2851cb0ef41Sopenharmony_ci    }
2861cb0ef41Sopenharmony_ci
2871cb0ef41Sopenharmony_ci    if (this.#entryTypes.size)
2881cb0ef41Sopenharmony_ci      kObservers.add(this);
2891cb0ef41Sopenharmony_ci    else
2901cb0ef41Sopenharmony_ci      this.disconnect();
2911cb0ef41Sopenharmony_ci  }
2921cb0ef41Sopenharmony_ci
2931cb0ef41Sopenharmony_ci  disconnect() {
2941cb0ef41Sopenharmony_ci    maybeDecrementObserverCounts(this.#entryTypes);
2951cb0ef41Sopenharmony_ci    kObservers.delete(this);
2961cb0ef41Sopenharmony_ci    kPending.delete(this);
2971cb0ef41Sopenharmony_ci    this.#buffer = [];
2981cb0ef41Sopenharmony_ci    this.#entryTypes.clear();
2991cb0ef41Sopenharmony_ci    this.#type = undefined;
3001cb0ef41Sopenharmony_ci  }
3011cb0ef41Sopenharmony_ci
3021cb0ef41Sopenharmony_ci  takeRecords() {
3031cb0ef41Sopenharmony_ci    const list = this.#buffer;
3041cb0ef41Sopenharmony_ci    this.#buffer = [];
3051cb0ef41Sopenharmony_ci    return list;
3061cb0ef41Sopenharmony_ci  }
3071cb0ef41Sopenharmony_ci
3081cb0ef41Sopenharmony_ci  static get supportedEntryTypes() {
3091cb0ef41Sopenharmony_ci    return kSupportedEntryTypes;
3101cb0ef41Sopenharmony_ci  }
3111cb0ef41Sopenharmony_ci
3121cb0ef41Sopenharmony_ci  [kMaybeBuffer](entry) {
3131cb0ef41Sopenharmony_ci    if (!this.#entryTypes.has(entry.entryType))
3141cb0ef41Sopenharmony_ci      return;
3151cb0ef41Sopenharmony_ci    ArrayPrototypePush(this.#buffer, entry);
3161cb0ef41Sopenharmony_ci    kPending.add(this);
3171cb0ef41Sopenharmony_ci    if (kPending.size)
3181cb0ef41Sopenharmony_ci      queuePending();
3191cb0ef41Sopenharmony_ci  }
3201cb0ef41Sopenharmony_ci
3211cb0ef41Sopenharmony_ci  [kDispatch]() {
3221cb0ef41Sopenharmony_ci    this.#callback(new PerformanceObserverEntryList(this.takeRecords()),
3231cb0ef41Sopenharmony_ci                   this);
3241cb0ef41Sopenharmony_ci  }
3251cb0ef41Sopenharmony_ci
3261cb0ef41Sopenharmony_ci  [kInspect](depth, options) {
3271cb0ef41Sopenharmony_ci    if (depth < 0) return this;
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci    const opts = {
3301cb0ef41Sopenharmony_ci      ...options,
3311cb0ef41Sopenharmony_ci      depth: options.depth == null ? null : options.depth - 1,
3321cb0ef41Sopenharmony_ci    };
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ci    return `PerformanceObserver ${inspect({
3351cb0ef41Sopenharmony_ci      connected: kObservers.has(this),
3361cb0ef41Sopenharmony_ci      pending: kPending.has(this),
3371cb0ef41Sopenharmony_ci      entryTypes: ArrayFrom(this.#entryTypes),
3381cb0ef41Sopenharmony_ci      buffer: this.#buffer,
3391cb0ef41Sopenharmony_ci    }, opts)}`;
3401cb0ef41Sopenharmony_ci  }
3411cb0ef41Sopenharmony_ci}
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_ci/**
3441cb0ef41Sopenharmony_ci * https://www.w3.org/TR/performance-timeline/#dfn-queue-a-performanceentry
3451cb0ef41Sopenharmony_ci *
3461cb0ef41Sopenharmony_ci * Add the performance entry to the interested performance observer's queue.
3471cb0ef41Sopenharmony_ci */
3481cb0ef41Sopenharmony_cifunction enqueue(entry) {
3491cb0ef41Sopenharmony_ci  if (!isPerformanceEntry(entry))
3501cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_TYPE('entry', 'PerformanceEntry', entry);
3511cb0ef41Sopenharmony_ci
3521cb0ef41Sopenharmony_ci  for (const obs of kObservers) {
3531cb0ef41Sopenharmony_ci    obs[kMaybeBuffer](entry);
3541cb0ef41Sopenharmony_ci  }
3551cb0ef41Sopenharmony_ci}
3561cb0ef41Sopenharmony_ci
3571cb0ef41Sopenharmony_ci/**
3581cb0ef41Sopenharmony_ci * Add the user timing entry to the global buffer.
3591cb0ef41Sopenharmony_ci */
3601cb0ef41Sopenharmony_cifunction bufferUserTiming(entry) {
3611cb0ef41Sopenharmony_ci  const entryType = entry.entryType;
3621cb0ef41Sopenharmony_ci  let buffer;
3631cb0ef41Sopenharmony_ci  if (entryType === 'mark') {
3641cb0ef41Sopenharmony_ci    buffer = markEntryBuffer;
3651cb0ef41Sopenharmony_ci  } else if (entryType === 'measure') {
3661cb0ef41Sopenharmony_ci    buffer = measureEntryBuffer;
3671cb0ef41Sopenharmony_ci  } else {
3681cb0ef41Sopenharmony_ci    return;
3691cb0ef41Sopenharmony_ci  }
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_ci  ArrayPrototypePush(buffer, entry);
3721cb0ef41Sopenharmony_ci  const count = buffer.length;
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ci  if (count > kPerformanceEntryBufferWarnSize &&
3751cb0ef41Sopenharmony_ci    !kWarnedEntryTypes.has(entryType)) {
3761cb0ef41Sopenharmony_ci    kWarnedEntryTypes.set(entryType, true);
3771cb0ef41Sopenharmony_ci    // No error code for this since it is a Warning
3781cb0ef41Sopenharmony_ci    // eslint-disable-next-line no-restricted-syntax
3791cb0ef41Sopenharmony_ci    const w = new Error('Possible perf_hooks memory leak detected. ' +
3801cb0ef41Sopenharmony_ci                        `${count} ${entryType} entries added to the global ` +
3811cb0ef41Sopenharmony_ci                        'performance entry buffer. Use ' +
3821cb0ef41Sopenharmony_ci                        `${kClearPerformanceEntryBuffers[entryType]} to ` +
3831cb0ef41Sopenharmony_ci                        'clear the buffer.');
3841cb0ef41Sopenharmony_ci    w.name = 'MaxPerformanceEntryBufferExceededWarning';
3851cb0ef41Sopenharmony_ci    w.entryType = entryType;
3861cb0ef41Sopenharmony_ci    w.count = count;
3871cb0ef41Sopenharmony_ci    process.emitWarning(w);
3881cb0ef41Sopenharmony_ci  }
3891cb0ef41Sopenharmony_ci}
3901cb0ef41Sopenharmony_ci
3911cb0ef41Sopenharmony_ci/**
3921cb0ef41Sopenharmony_ci * Add the resource timing entry to the global buffer if the buffer size is not
3931cb0ef41Sopenharmony_ci * exceeding the buffer limit, or dispatch a buffer full event on the global
3941cb0ef41Sopenharmony_ci * performance object.
3951cb0ef41Sopenharmony_ci *
3961cb0ef41Sopenharmony_ci * See also https://www.w3.org/TR/resource-timing-2/#dfn-add-a-performanceresourcetiming-entry
3971cb0ef41Sopenharmony_ci */
3981cb0ef41Sopenharmony_cifunction bufferResourceTiming(entry) {
3991cb0ef41Sopenharmony_ci  if (resourceTimingBuffer.length < resourceTimingBufferSizeLimit && !resourceTimingBufferFullPending) {
4001cb0ef41Sopenharmony_ci    ArrayPrototypePush(resourceTimingBuffer, entry);
4011cb0ef41Sopenharmony_ci    return;
4021cb0ef41Sopenharmony_ci  }
4031cb0ef41Sopenharmony_ci
4041cb0ef41Sopenharmony_ci  if (!resourceTimingBufferFullPending) {
4051cb0ef41Sopenharmony_ci    resourceTimingBufferFullPending = true;
4061cb0ef41Sopenharmony_ci    setImmediate(() => {
4071cb0ef41Sopenharmony_ci      while (resourceTimingSecondaryBuffer.length > 0) {
4081cb0ef41Sopenharmony_ci        const excessNumberBefore = resourceTimingSecondaryBuffer.length;
4091cb0ef41Sopenharmony_ci        dispatchBufferFull('resourcetimingbufferfull');
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci        // Calculate the number of items to be pushed to the global buffer.
4121cb0ef41Sopenharmony_ci        const numbersToPreserve = MathMax(
4131cb0ef41Sopenharmony_ci          MathMin(resourceTimingBufferSizeLimit - resourceTimingBuffer.length, resourceTimingSecondaryBuffer.length),
4141cb0ef41Sopenharmony_ci          0,
4151cb0ef41Sopenharmony_ci        );
4161cb0ef41Sopenharmony_ci        const excessNumberAfter = resourceTimingSecondaryBuffer.length - numbersToPreserve;
4171cb0ef41Sopenharmony_ci        for (let idx = 0; idx < numbersToPreserve; idx++) {
4181cb0ef41Sopenharmony_ci          ArrayPrototypePush(resourceTimingBuffer, resourceTimingSecondaryBuffer[idx]);
4191cb0ef41Sopenharmony_ci        }
4201cb0ef41Sopenharmony_ci
4211cb0ef41Sopenharmony_ci        if (excessNumberBefore <= excessNumberAfter) {
4221cb0ef41Sopenharmony_ci          resourceTimingSecondaryBuffer = [];
4231cb0ef41Sopenharmony_ci        }
4241cb0ef41Sopenharmony_ci      }
4251cb0ef41Sopenharmony_ci      resourceTimingBufferFullPending = false;
4261cb0ef41Sopenharmony_ci    });
4271cb0ef41Sopenharmony_ci  }
4281cb0ef41Sopenharmony_ci
4291cb0ef41Sopenharmony_ci  ArrayPrototypePush(resourceTimingSecondaryBuffer, entry);
4301cb0ef41Sopenharmony_ci}
4311cb0ef41Sopenharmony_ci
4321cb0ef41Sopenharmony_ci// https://w3c.github.io/resource-timing/#dom-performance-setresourcetimingbuffersize
4331cb0ef41Sopenharmony_cifunction setResourceTimingBufferSize(maxSize) {
4341cb0ef41Sopenharmony_ci  // unsigned long
4351cb0ef41Sopenharmony_ci  maxSize = convertToInt('maxSize', maxSize, 32);
4361cb0ef41Sopenharmony_ci  // If the maxSize parameter is less than resource timing buffer current
4371cb0ef41Sopenharmony_ci  // size, no PerformanceResourceTiming objects are to be removed from the
4381cb0ef41Sopenharmony_ci  // performance entry buffer.
4391cb0ef41Sopenharmony_ci  resourceTimingBufferSizeLimit = maxSize;
4401cb0ef41Sopenharmony_ci}
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_cifunction setDispatchBufferFull(fn) {
4431cb0ef41Sopenharmony_ci  dispatchBufferFull = fn;
4441cb0ef41Sopenharmony_ci}
4451cb0ef41Sopenharmony_ci
4461cb0ef41Sopenharmony_cifunction clearEntriesFromBuffer(type, name) {
4471cb0ef41Sopenharmony_ci  if (type !== 'mark' && type !== 'measure' && type !== 'resource') {
4481cb0ef41Sopenharmony_ci    return;
4491cb0ef41Sopenharmony_ci  }
4501cb0ef41Sopenharmony_ci
4511cb0ef41Sopenharmony_ci  if (type === 'mark') {
4521cb0ef41Sopenharmony_ci    markEntryBuffer = name === undefined ?
4531cb0ef41Sopenharmony_ci      [] : ArrayPrototypeFilter(markEntryBuffer, (entry) => entry.name !== name);
4541cb0ef41Sopenharmony_ci  } else if (type === 'measure') {
4551cb0ef41Sopenharmony_ci    measureEntryBuffer = name === undefined ?
4561cb0ef41Sopenharmony_ci      [] : ArrayPrototypeFilter(measureEntryBuffer, (entry) => entry.name !== name);
4571cb0ef41Sopenharmony_ci  } else {
4581cb0ef41Sopenharmony_ci    resourceTimingBuffer = name === undefined ?
4591cb0ef41Sopenharmony_ci      [] : ArrayPrototypeFilter(resourceTimingBuffer, (entry) => entry.name !== name);
4601cb0ef41Sopenharmony_ci  }
4611cb0ef41Sopenharmony_ci}
4621cb0ef41Sopenharmony_ci
4631cb0ef41Sopenharmony_cifunction filterBufferMapByNameAndType(name, type) {
4641cb0ef41Sopenharmony_ci  let bufferList;
4651cb0ef41Sopenharmony_ci  if (type === 'mark') {
4661cb0ef41Sopenharmony_ci    bufferList = markEntryBuffer;
4671cb0ef41Sopenharmony_ci  } else if (type === 'measure') {
4681cb0ef41Sopenharmony_ci    bufferList = measureEntryBuffer;
4691cb0ef41Sopenharmony_ci  } else if (type === 'resource') {
4701cb0ef41Sopenharmony_ci    bufferList = resourceTimingBuffer;
4711cb0ef41Sopenharmony_ci  } else if (type !== undefined) {
4721cb0ef41Sopenharmony_ci    // Unrecognized type;
4731cb0ef41Sopenharmony_ci    return [];
4741cb0ef41Sopenharmony_ci  } else {
4751cb0ef41Sopenharmony_ci    bufferList = [];
4761cb0ef41Sopenharmony_ci    ArrayPrototypePushApply(bufferList, markEntryBuffer);
4771cb0ef41Sopenharmony_ci    ArrayPrototypePushApply(bufferList, measureEntryBuffer);
4781cb0ef41Sopenharmony_ci    ArrayPrototypePushApply(bufferList, resourceTimingBuffer);
4791cb0ef41Sopenharmony_ci  }
4801cb0ef41Sopenharmony_ci  if (name !== undefined) {
4811cb0ef41Sopenharmony_ci    bufferList = ArrayPrototypeFilter(bufferList, (buffer) => buffer.name === name);
4821cb0ef41Sopenharmony_ci  } else if (type !== undefined) {
4831cb0ef41Sopenharmony_ci    bufferList = ArrayPrototypeSlice(bufferList);
4841cb0ef41Sopenharmony_ci  }
4851cb0ef41Sopenharmony_ci
4861cb0ef41Sopenharmony_ci  return ArrayPrototypeSort(bufferList, (first, second) => {
4871cb0ef41Sopenharmony_ci    return first.startTime - second.startTime;
4881cb0ef41Sopenharmony_ci  });
4891cb0ef41Sopenharmony_ci}
4901cb0ef41Sopenharmony_ci
4911cb0ef41Sopenharmony_cifunction observerCallback(name, type, startTime, duration, details) {
4921cb0ef41Sopenharmony_ci  const entry =
4931cb0ef41Sopenharmony_ci    new InternalPerformanceEntry(
4941cb0ef41Sopenharmony_ci      name,
4951cb0ef41Sopenharmony_ci      type,
4961cb0ef41Sopenharmony_ci      startTime,
4971cb0ef41Sopenharmony_ci      duration,
4981cb0ef41Sopenharmony_ci      details);
4991cb0ef41Sopenharmony_ci
5001cb0ef41Sopenharmony_ci  if (details !== undefined) {
5011cb0ef41Sopenharmony_ci    // GC, HTTP2, and HTTP PerformanceEntry used additional
5021cb0ef41Sopenharmony_ci    // properties directly off the entry. Those have been
5031cb0ef41Sopenharmony_ci    // moved into the details property. The existing accessors
5041cb0ef41Sopenharmony_ci    // are still included but are deprecated.
5051cb0ef41Sopenharmony_ci    entry[kDeprecatedFields] = new SafeMap();
5061cb0ef41Sopenharmony_ci
5071cb0ef41Sopenharmony_ci    const detailKeys = ObjectKeys(details);
5081cb0ef41Sopenharmony_ci    const props = {};
5091cb0ef41Sopenharmony_ci    for (let n = 0; n < detailKeys.length; n++) {
5101cb0ef41Sopenharmony_ci      const key = detailKeys[n];
5111cb0ef41Sopenharmony_ci      entry[kDeprecatedFields].set(key, details[key]);
5121cb0ef41Sopenharmony_ci      props[key] = {
5131cb0ef41Sopenharmony_ci        configurable: true,
5141cb0ef41Sopenharmony_ci        enumerable: true,
5151cb0ef41Sopenharmony_ci        get: deprecate(() => {
5161cb0ef41Sopenharmony_ci          return entry[kDeprecatedFields].get(key);
5171cb0ef41Sopenharmony_ci        }, kDeprecationMessage, 'DEP0152'),
5181cb0ef41Sopenharmony_ci        set: deprecate((value) => {
5191cb0ef41Sopenharmony_ci          entry[kDeprecatedFields].set(key, value);
5201cb0ef41Sopenharmony_ci        }, kDeprecationMessage, 'DEP0152'),
5211cb0ef41Sopenharmony_ci      };
5221cb0ef41Sopenharmony_ci    }
5231cb0ef41Sopenharmony_ci    ObjectDefineProperties(entry, props);
5241cb0ef41Sopenharmony_ci  }
5251cb0ef41Sopenharmony_ci
5261cb0ef41Sopenharmony_ci  enqueue(entry);
5271cb0ef41Sopenharmony_ci}
5281cb0ef41Sopenharmony_ci
5291cb0ef41Sopenharmony_cisetupObservers(observerCallback);
5301cb0ef41Sopenharmony_ci
5311cb0ef41Sopenharmony_cifunction hasObserver(type) {
5321cb0ef41Sopenharmony_ci  const observerType = getObserverType(type);
5331cb0ef41Sopenharmony_ci  return observerCounts[observerType] > 0;
5341cb0ef41Sopenharmony_ci}
5351cb0ef41Sopenharmony_ci
5361cb0ef41Sopenharmony_ci
5371cb0ef41Sopenharmony_cifunction startPerf(target, key, context = {}) {
5381cb0ef41Sopenharmony_ci  target[key] = {
5391cb0ef41Sopenharmony_ci    ...context,
5401cb0ef41Sopenharmony_ci    startTime: now(),
5411cb0ef41Sopenharmony_ci  };
5421cb0ef41Sopenharmony_ci}
5431cb0ef41Sopenharmony_ci
5441cb0ef41Sopenharmony_cifunction stopPerf(target, key, context = {}) {
5451cb0ef41Sopenharmony_ci  const ctx = target[key];
5461cb0ef41Sopenharmony_ci  if (!ctx) {
5471cb0ef41Sopenharmony_ci    return;
5481cb0ef41Sopenharmony_ci  }
5491cb0ef41Sopenharmony_ci  const startTime = ctx.startTime;
5501cb0ef41Sopenharmony_ci  const entry = new InternalPerformanceEntry(
5511cb0ef41Sopenharmony_ci    ctx.name,
5521cb0ef41Sopenharmony_ci    ctx.type,
5531cb0ef41Sopenharmony_ci    startTime,
5541cb0ef41Sopenharmony_ci    now() - startTime,
5551cb0ef41Sopenharmony_ci    { ...ctx.detail, ...context.detail },
5561cb0ef41Sopenharmony_ci  );
5571cb0ef41Sopenharmony_ci  enqueue(entry);
5581cb0ef41Sopenharmony_ci}
5591cb0ef41Sopenharmony_ci
5601cb0ef41Sopenharmony_cimodule.exports = {
5611cb0ef41Sopenharmony_ci  PerformanceObserver,
5621cb0ef41Sopenharmony_ci  PerformanceObserverEntryList,
5631cb0ef41Sopenharmony_ci  enqueue,
5641cb0ef41Sopenharmony_ci  hasObserver,
5651cb0ef41Sopenharmony_ci  clearEntriesFromBuffer,
5661cb0ef41Sopenharmony_ci  filterBufferMapByNameAndType,
5671cb0ef41Sopenharmony_ci  startPerf,
5681cb0ef41Sopenharmony_ci  stopPerf,
5691cb0ef41Sopenharmony_ci
5701cb0ef41Sopenharmony_ci  bufferUserTiming,
5711cb0ef41Sopenharmony_ci  bufferResourceTiming,
5721cb0ef41Sopenharmony_ci  setResourceTimingBufferSize,
5731cb0ef41Sopenharmony_ci  setDispatchBufferFull,
5741cb0ef41Sopenharmony_ci};
575