• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3/* eslint-disable node-core/prefer-primordials */
4
5// This file subclasses and stores the JS builtins that come from the VM
6// so that Node.js's builtin modules do not need to later look these up from
7// the global proxy, which can be mutated by users.
8
9// Use of primordials have sometimes a dramatic impact on performance, please
10// benchmark all changes made in performance-sensitive areas of the codebase.
11// See: https://github.com/nodejs/node/pull/38248
12
13const {
14  defineProperty: ReflectDefineProperty,
15  getOwnPropertyDescriptor: ReflectGetOwnPropertyDescriptor,
16  ownKeys: ReflectOwnKeys,
17} = Reflect;
18
19// `uncurryThis` is equivalent to `func => Function.prototype.call.bind(func)`.
20// It is using `bind.bind(call)` to avoid using `Function.prototype.bind`
21// and `Function.prototype.call` after it may have been mutated by users.
22const { apply, bind, call } = Function.prototype;
23const uncurryThis = bind.bind(call);
24primordials.uncurryThis = uncurryThis;
25
26// `applyBind` is equivalent to `func => Function.prototype.apply.bind(func)`.
27// It is using `bind.bind(apply)` to avoid using `Function.prototype.bind`
28// and `Function.prototype.apply` after it may have been mutated by users.
29const applyBind = bind.bind(apply);
30primordials.applyBind = applyBind;
31
32// Methods that accept a variable number of arguments, and thus it's useful to
33// also create `${prefix}${key}Apply`, which uses `Function.prototype.apply`,
34// instead of `Function.prototype.call`, and thus doesn't require iterator
35// destructuring.
36const varargsMethods = [
37  // 'ArrayPrototypeConcat' is omitted, because it performs the spread
38  // on its own for arrays and array-likes with a truthy
39  // @@isConcatSpreadable symbol property.
40  'ArrayOf',
41  'ArrayPrototypePush',
42  'ArrayPrototypeUnshift',
43  // 'FunctionPrototypeCall' is omitted, since there's 'ReflectApply'
44  // and 'FunctionPrototypeApply'.
45  'MathHypot',
46  'MathMax',
47  'MathMin',
48  'StringFromCharCode',
49  'StringFromCodePoint',
50  'StringPrototypeConcat',
51  'TypedArrayOf',
52];
53
54function getNewKey(key) {
55  return typeof key === 'symbol' ?
56    `Symbol${key.description[7].toUpperCase()}${key.description.slice(8)}` :
57    `${key[0].toUpperCase()}${key.slice(1)}`;
58}
59
60function copyAccessor(dest, prefix, key, { enumerable, get, set }) {
61  ReflectDefineProperty(dest, `${prefix}Get${key}`, {
62    __proto__: null,
63    value: uncurryThis(get),
64    enumerable,
65  });
66  if (set !== undefined) {
67    ReflectDefineProperty(dest, `${prefix}Set${key}`, {
68      __proto__: null,
69      value: uncurryThis(set),
70      enumerable,
71    });
72  }
73}
74
75function copyPropsRenamed(src, dest, prefix) {
76  for (const key of ReflectOwnKeys(src)) {
77    const newKey = getNewKey(key);
78    const desc = ReflectGetOwnPropertyDescriptor(src, key);
79    if ('get' in desc) {
80      copyAccessor(dest, prefix, newKey, desc);
81    } else {
82      const name = `${prefix}${newKey}`;
83      ReflectDefineProperty(dest, name, { __proto__: null, ...desc });
84      if (varargsMethods.includes(name)) {
85        ReflectDefineProperty(dest, `${name}Apply`, {
86          __proto__: null,
87          // `src` is bound as the `this` so that the static `this` points
88          // to the object it was defined on,
89          // e.g.: `ArrayOfApply` gets a `this` of `Array`:
90          value: applyBind(desc.value, src),
91        });
92      }
93    }
94  }
95}
96
97function copyPropsRenamedBound(src, dest, prefix) {
98  for (const key of ReflectOwnKeys(src)) {
99    const newKey = getNewKey(key);
100    const desc = ReflectGetOwnPropertyDescriptor(src, key);
101    if ('get' in desc) {
102      copyAccessor(dest, prefix, newKey, desc);
103    } else {
104      const { value } = desc;
105      if (typeof value === 'function') {
106        desc.value = value.bind(src);
107      }
108
109      const name = `${prefix}${newKey}`;
110      ReflectDefineProperty(dest, name, { __proto__: null, ...desc });
111      if (varargsMethods.includes(name)) {
112        ReflectDefineProperty(dest, `${name}Apply`, {
113          __proto__: null,
114          value: applyBind(value, src),
115        });
116      }
117    }
118  }
119}
120
121function copyPrototype(src, dest, prefix) {
122  for (const key of ReflectOwnKeys(src)) {
123    const newKey = getNewKey(key);
124    const desc = ReflectGetOwnPropertyDescriptor(src, key);
125    if ('get' in desc) {
126      copyAccessor(dest, prefix, newKey, desc);
127    } else {
128      const { value } = desc;
129      if (typeof value === 'function') {
130        desc.value = uncurryThis(value);
131      }
132
133      const name = `${prefix}${newKey}`;
134      ReflectDefineProperty(dest, name, { __proto__: null, ...desc });
135      if (varargsMethods.includes(name)) {
136        ReflectDefineProperty(dest, `${name}Apply`, {
137          __proto__: null,
138          value: applyBind(value),
139        });
140      }
141    }
142  }
143}
144
145// Create copies of configurable value properties of the global object
146[
147  'Proxy',
148  'globalThis',
149].forEach((name) => {
150  // eslint-disable-next-line no-restricted-globals
151  primordials[name] = globalThis[name];
152});
153
154// Create copies of URI handling functions
155[
156  decodeURI,
157  decodeURIComponent,
158  encodeURI,
159  encodeURIComponent,
160].forEach((fn) => {
161  primordials[fn.name] = fn;
162});
163
164// Create copies of legacy functions
165[
166  escape,
167  eval,
168  unescape,
169].forEach((fn) => {
170  primordials[fn.name] = fn;
171});
172
173// Create copies of the namespace objects
174[
175  'JSON',
176  'Math',
177  'Proxy',
178  'Reflect',
179].forEach((name) => {
180  // eslint-disable-next-line no-restricted-globals
181  copyPropsRenamed(globalThis[name], primordials, name);
182});
183
184// Create copies of intrinsic objects
185[
186  'AggregateError',
187  'Array',
188  'ArrayBuffer',
189  'BigInt',
190  'BigInt64Array',
191  'BigUint64Array',
192  'Boolean',
193  'DataView',
194  'Date',
195  'Error',
196  'EvalError',
197  'FinalizationRegistry',
198  'Float32Array',
199  'Float64Array',
200  'Function',
201  'Int16Array',
202  'Int32Array',
203  'Int8Array',
204  'Map',
205  'Number',
206  'Object',
207  'RangeError',
208  'ReferenceError',
209  'RegExp',
210  'Set',
211  'String',
212  'Symbol',
213  'SyntaxError',
214  'TypeError',
215  'URIError',
216  'Uint16Array',
217  'Uint32Array',
218  'Uint8Array',
219  'Uint8ClampedArray',
220  'WeakMap',
221  'WeakRef',
222  'WeakSet',
223].forEach((name) => {
224  // eslint-disable-next-line no-restricted-globals
225  const original = globalThis[name];
226  primordials[name] = original;
227  copyPropsRenamed(original, primordials, name);
228  copyPrototype(original.prototype, primordials, `${name}Prototype`);
229});
230
231// Define Symbol.dispose and Symbol.asyncDispose
232// Until these are defined by the environment.
233// TODO(MoLow): Remove this polyfill once Symbol.dispose and Symbol.asyncDispose are available in V8.
234primordials.SymbolDispose ??= primordials.SymbolFor('nodejs.dispose');
235primordials.SymbolAsyncDispose ??= primordials.SymbolFor('nodejs.asyncDispose');
236
237// Create copies of intrinsic objects that require a valid `this` to call
238// static methods.
239// Refs: https://www.ecma-international.org/ecma-262/#sec-promise.all
240[
241  'Promise',
242].forEach((name) => {
243  // eslint-disable-next-line no-restricted-globals
244  const original = globalThis[name];
245  primordials[name] = original;
246  copyPropsRenamedBound(original, primordials, name);
247  copyPrototype(original.prototype, primordials, `${name}Prototype`);
248});
249
250// Create copies of abstract intrinsic objects that are not directly exposed
251// on the global object.
252// Refs: https://tc39.es/ecma262/#sec-%typedarray%-intrinsic-object
253[
254  { name: 'TypedArray', original: Reflect.getPrototypeOf(Uint8Array) },
255  { name: 'ArrayIterator', original: {
256    prototype: Reflect.getPrototypeOf(Array.prototype[Symbol.iterator]()),
257  } },
258  { name: 'StringIterator', original: {
259    prototype: Reflect.getPrototypeOf(String.prototype[Symbol.iterator]()),
260  } },
261].forEach(({ name, original }) => {
262  primordials[name] = original;
263  // The static %TypedArray% methods require a valid `this`, but can't be bound,
264  // as they need a subclass constructor as the receiver:
265  copyPrototype(original, primordials, name);
266  copyPrototype(original.prototype, primordials, `${name}Prototype`);
267});
268
269primordials.IteratorPrototype = Reflect.getPrototypeOf(primordials.ArrayIteratorPrototype);
270
271/* eslint-enable node-core/prefer-primordials */
272
273const {
274  Array: ArrayConstructor,
275  ArrayPrototypeForEach,
276  ArrayPrototypeMap,
277  FinalizationRegistry,
278  FunctionPrototypeCall,
279  Map,
280  ObjectDefineProperties,
281  ObjectDefineProperty,
282  ObjectFreeze,
283  ObjectSetPrototypeOf,
284  Promise,
285  PromisePrototypeThen,
286  PromiseResolve,
287  ReflectApply,
288  ReflectConstruct,
289  ReflectSet,
290  ReflectGet,
291  RegExp,
292  RegExpPrototype,
293  RegExpPrototypeExec,
294  RegExpPrototypeGetDotAll,
295  RegExpPrototypeGetFlags,
296  RegExpPrototypeGetGlobal,
297  RegExpPrototypeGetHasIndices,
298  RegExpPrototypeGetIgnoreCase,
299  RegExpPrototypeGetMultiline,
300  RegExpPrototypeGetSource,
301  RegExpPrototypeGetSticky,
302  RegExpPrototypeGetUnicode,
303  Set,
304  SymbolIterator,
305  SymbolMatch,
306  SymbolMatchAll,
307  SymbolReplace,
308  SymbolSearch,
309  SymbolSpecies,
310  SymbolSplit,
311  WeakMap,
312  WeakRef,
313  WeakSet,
314} = primordials;
315
316
317/**
318 * Creates a class that can be safely iterated over.
319 *
320 * Because these functions are used by `makeSafe`, which is exposed on the
321 * `primordials` object, it's important to use const references to the
322 * primordials that they use.
323 * @template {Iterable} T
324 * @template {*} TReturn
325 * @template {*} TNext
326 * @param {(self: T) => IterableIterator<T>} factory
327 * @param {(...args: [] | [TNext]) => IteratorResult<T, TReturn>} next
328 * @returns {Iterator<T, TReturn, TNext>}
329 */
330const createSafeIterator = (factory, next) => {
331  class SafeIterator {
332    constructor(iterable) {
333      this._iterator = factory(iterable);
334    }
335    next() {
336      return next(this._iterator);
337    }
338    [SymbolIterator]() {
339      return this;
340    }
341  }
342  ObjectSetPrototypeOf(SafeIterator.prototype, null);
343  ObjectFreeze(SafeIterator.prototype);
344  ObjectFreeze(SafeIterator);
345  return SafeIterator;
346};
347
348primordials.SafeArrayIterator = createSafeIterator(
349  primordials.ArrayPrototypeSymbolIterator,
350  primordials.ArrayIteratorPrototypeNext,
351);
352primordials.SafeStringIterator = createSafeIterator(
353  primordials.StringPrototypeSymbolIterator,
354  primordials.StringIteratorPrototypeNext,
355);
356
357const copyProps = (src, dest) => {
358  ArrayPrototypeForEach(ReflectOwnKeys(src), (key) => {
359    if (!ReflectGetOwnPropertyDescriptor(dest, key)) {
360      ReflectDefineProperty(
361        dest,
362        key,
363        { __proto__: null, ...ReflectGetOwnPropertyDescriptor(src, key) });
364    }
365  });
366};
367
368/**
369 * @type {typeof primordials.makeSafe}
370 */
371const makeSafe = (unsafe, safe) => {
372  if (SymbolIterator in unsafe.prototype) {
373    const dummy = new unsafe();
374    let next; // We can reuse the same `next` method.
375
376    ArrayPrototypeForEach(ReflectOwnKeys(unsafe.prototype), (key) => {
377      if (!ReflectGetOwnPropertyDescriptor(safe.prototype, key)) {
378        const desc = ReflectGetOwnPropertyDescriptor(unsafe.prototype, key);
379        if (
380          typeof desc.value === 'function' &&
381          desc.value.length === 0 &&
382          SymbolIterator in (FunctionPrototypeCall(desc.value, dummy) ?? {})
383        ) {
384          const createIterator = uncurryThis(desc.value);
385          next ??= uncurryThis(createIterator(dummy).next);
386          const SafeIterator = createSafeIterator(createIterator, next);
387          desc.value = function() {
388            return new SafeIterator(this);
389          };
390        }
391        ReflectDefineProperty(safe.prototype, key, { __proto__: null, ...desc });
392      }
393    });
394  } else {
395    copyProps(unsafe.prototype, safe.prototype);
396  }
397  copyProps(unsafe, safe);
398
399  ObjectSetPrototypeOf(safe.prototype, null);
400  ObjectFreeze(safe.prototype);
401  ObjectFreeze(safe);
402  return safe;
403};
404primordials.makeSafe = makeSafe;
405
406// Subclass the constructors because we need to use their prototype
407// methods later.
408// Defining the `constructor` is necessary here to avoid the default
409// constructor which uses the user-mutable `%ArrayIteratorPrototype%.next`.
410primordials.SafeMap = makeSafe(
411  Map,
412  class SafeMap extends Map {
413    constructor(i) { super(i); } // eslint-disable-line no-useless-constructor
414  },
415);
416primordials.SafeWeakMap = makeSafe(
417  WeakMap,
418  class SafeWeakMap extends WeakMap {
419    constructor(i) { super(i); } // eslint-disable-line no-useless-constructor
420  },
421);
422
423primordials.SafeSet = makeSafe(
424  Set,
425  class SafeSet extends Set {
426    constructor(i) { super(i); } // eslint-disable-line no-useless-constructor
427  },
428);
429primordials.SafeWeakSet = makeSafe(
430  WeakSet,
431  class SafeWeakSet extends WeakSet {
432    constructor(i) { super(i); } // eslint-disable-line no-useless-constructor
433  },
434);
435
436primordials.SafeFinalizationRegistry = makeSafe(
437  FinalizationRegistry,
438  class SafeFinalizationRegistry extends FinalizationRegistry {
439    // eslint-disable-next-line no-useless-constructor
440    constructor(cleanupCallback) { super(cleanupCallback); }
441  },
442);
443primordials.SafeWeakRef = makeSafe(
444  WeakRef,
445  class SafeWeakRef extends WeakRef {
446    // eslint-disable-next-line no-useless-constructor
447    constructor(target) { super(target); }
448  },
449);
450
451const SafePromise = makeSafe(
452  Promise,
453  class SafePromise extends Promise {
454    // eslint-disable-next-line no-useless-constructor
455    constructor(executor) { super(executor); }
456  },
457);
458
459/**
460 * Attaches a callback that is invoked when the Promise is settled (fulfilled or
461 * rejected). The resolved value cannot be modified from the callback.
462 * Prefer using async functions when possible.
463 * @param {Promise<any>} thisPromise
464 * @param {() => void) | undefined | null} onFinally The callback to execute
465 *        when the Promise is settled (fulfilled or rejected).
466 * @returns {Promise} A Promise for the completion of the callback.
467 */
468primordials.SafePromisePrototypeFinally = (thisPromise, onFinally) =>
469  // Wrapping on a new Promise is necessary to not expose the SafePromise
470  // prototype to user-land.
471  new Promise((a, b) =>
472    new SafePromise((a, b) => PromisePrototypeThen(thisPromise, a, b))
473      .finally(onFinally)
474      .then(a, b),
475  );
476
477primordials.AsyncIteratorPrototype =
478  primordials.ReflectGetPrototypeOf(
479    primordials.ReflectGetPrototypeOf(
480      async function* () {}).prototype);
481
482const arrayToSafePromiseIterable = (promises, mapFn) =>
483  new primordials.SafeArrayIterator(
484    ArrayPrototypeMap(
485      promises,
486      (promise, i) =>
487        new SafePromise((a, b) => PromisePrototypeThen(mapFn == null ? promise : mapFn(promise, i), a, b)),
488    ),
489  );
490
491/**
492 * @template T,U
493 * @param {Array<T | PromiseLike<T>>} promises
494 * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U>} [mapFn]
495 * @returns {Promise<Awaited<U>[]>}
496 */
497primordials.SafePromiseAll = (promises, mapFn) =>
498  // Wrapping on a new Promise is necessary to not expose the SafePromise
499  // prototype to user-land.
500  new Promise((a, b) =>
501    SafePromise.all(arrayToSafePromiseIterable(promises, mapFn)).then(a, b),
502  );
503
504/**
505 * Should only be used for internal functions, this would produce similar
506 * results as `Promise.all` but without prototype pollution, and the return
507 * value is not a genuine Array but an array-like object.
508 * @template T,U
509 * @param {ArrayLike<T | PromiseLike<T>>} promises
510 * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U>} [mapFn]
511 * @returns {Promise<ArrayLike<Awaited<U>>>}
512 */
513primordials.SafePromiseAllReturnArrayLike = (promises, mapFn) =>
514  new Promise((resolve, reject) => {
515    const { length } = promises;
516
517    const returnVal = ArrayConstructor(length);
518    ObjectSetPrototypeOf(returnVal, null);
519    if (length === 0) resolve(returnVal);
520
521    let pendingPromises = length;
522    for (let i = 0; i < length; i++) {
523      const promise = mapFn != null ? mapFn(promises[i], i) : promises[i];
524      PromisePrototypeThen(PromiseResolve(promise), (result) => {
525        returnVal[i] = result;
526        if (--pendingPromises === 0) resolve(returnVal);
527      }, reject);
528    }
529  });
530
531/**
532 * Should only be used when we only care about waiting for all the promises to
533 * resolve, not what value they resolve to.
534 * @template T,U
535 * @param {ArrayLike<T | PromiseLike<T>>} promises
536 * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U>} [mapFn]
537 * @returns {Promise<void>}
538 */
539primordials.SafePromiseAllReturnVoid = (promises, mapFn) =>
540  new Promise((resolve, reject) => {
541    let pendingPromises = promises.length;
542    if (pendingPromises === 0) resolve();
543    for (let i = 0; i < promises.length; i++) {
544      const promise = mapFn != null ? mapFn(promises[i], i) : promises[i];
545      PromisePrototypeThen(PromiseResolve(promise), () => {
546        if (--pendingPromises === 0) resolve();
547      }, reject);
548    }
549  });
550
551/**
552 * @template T,U
553 * @param {Array<T|PromiseLike<T>>} promises
554 * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U>} [mapFn]
555 * @returns {Promise<PromiseSettledResult<any>[]>}
556 */
557primordials.SafePromiseAllSettled = (promises, mapFn) =>
558  // Wrapping on a new Promise is necessary to not expose the SafePromise
559  // prototype to user-land.
560  new Promise((a, b) =>
561    SafePromise.allSettled(arrayToSafePromiseIterable(promises, mapFn)).then(a, b),
562  );
563
564/**
565 * Should only be used when we only care about waiting for all the promises to
566 * settle, not what value they resolve or reject to.
567 * @template T,U
568 * @param {ArrayLike<T|PromiseLike<T>>} promises
569 * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U>} [mapFn]
570 * @returns {Promise<void>}
571 */
572primordials.SafePromiseAllSettledReturnVoid = async (promises, mapFn) => {
573  await primordials.SafePromiseAllSettled(promises, mapFn);
574};
575
576/**
577 * @template T,U
578 * @param {Array<T|PromiseLike<T>>} promises
579 * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U>} [mapFn]
580 * @returns {Promise<Awaited<U>>}
581 */
582primordials.SafePromiseAny = (promises, mapFn) =>
583  // Wrapping on a new Promise is necessary to not expose the SafePromise
584  // prototype to user-land.
585  new Promise((a, b) =>
586    SafePromise.any(arrayToSafePromiseIterable(promises, mapFn)).then(a, b),
587  );
588
589/**
590 * @template T,U
591 * @param {Array<T|PromiseLike<T>>} promises
592 * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U>} [mapFn]
593 * @returns {Promise<Awaited<U>>}
594 */
595primordials.SafePromiseRace = (promises, mapFn) =>
596  // Wrapping on a new Promise is necessary to not expose the SafePromise
597  // prototype to user-land.
598  new Promise((a, b) =>
599    SafePromise.race(arrayToSafePromiseIterable(promises, mapFn)).then(a, b),
600  );
601
602
603const {
604  exec: OriginalRegExpPrototypeExec,
605  [SymbolMatch]: OriginalRegExpPrototypeSymbolMatch,
606  [SymbolMatchAll]: OriginalRegExpPrototypeSymbolMatchAll,
607  [SymbolReplace]: OriginalRegExpPrototypeSymbolReplace,
608  [SymbolSearch]: OriginalRegExpPrototypeSymbolSearch,
609  [SymbolSplit]: OriginalRegExpPrototypeSymbolSplit,
610} = RegExpPrototype;
611
612class RegExpLikeForStringSplitting {
613  #regex;
614  constructor() {
615    this.#regex = ReflectConstruct(RegExp, arguments);
616  }
617
618  get lastIndex() {
619    return ReflectGet(this.#regex, 'lastIndex');
620  }
621  set lastIndex(value) {
622    ReflectSet(this.#regex, 'lastIndex', value);
623  }
624
625  exec() {
626    return ReflectApply(OriginalRegExpPrototypeExec, this.#regex, arguments);
627  }
628}
629ObjectSetPrototypeOf(RegExpLikeForStringSplitting.prototype, null);
630
631/**
632 * @param {RegExp} pattern
633 * @returns {RegExp}
634 */
635primordials.hardenRegExp = function hardenRegExp(pattern) {
636  ObjectDefineProperties(pattern, {
637    [SymbolMatch]: {
638      __proto__: null,
639      configurable: true,
640      value: OriginalRegExpPrototypeSymbolMatch,
641    },
642    [SymbolMatchAll]: {
643      __proto__: null,
644      configurable: true,
645      value: OriginalRegExpPrototypeSymbolMatchAll,
646    },
647    [SymbolReplace]: {
648      __proto__: null,
649      configurable: true,
650      value: OriginalRegExpPrototypeSymbolReplace,
651    },
652    [SymbolSearch]: {
653      __proto__: null,
654      configurable: true,
655      value: OriginalRegExpPrototypeSymbolSearch,
656    },
657    [SymbolSplit]: {
658      __proto__: null,
659      configurable: true,
660      value: OriginalRegExpPrototypeSymbolSplit,
661    },
662    constructor: {
663      __proto__: null,
664      configurable: true,
665      value: {
666        [SymbolSpecies]: RegExpLikeForStringSplitting,
667      },
668    },
669    dotAll: {
670      __proto__: null,
671      configurable: true,
672      value: RegExpPrototypeGetDotAll(pattern),
673    },
674    exec: {
675      __proto__: null,
676      configurable: true,
677      value: OriginalRegExpPrototypeExec,
678    },
679    global: {
680      __proto__: null,
681      configurable: true,
682      value: RegExpPrototypeGetGlobal(pattern),
683    },
684    hasIndices: {
685      __proto__: null,
686      configurable: true,
687      value: RegExpPrototypeGetHasIndices(pattern),
688    },
689    ignoreCase: {
690      __proto__: null,
691      configurable: true,
692      value: RegExpPrototypeGetIgnoreCase(pattern),
693    },
694    multiline: {
695      __proto__: null,
696      configurable: true,
697      value: RegExpPrototypeGetMultiline(pattern),
698    },
699    source: {
700      __proto__: null,
701      configurable: true,
702      value: RegExpPrototypeGetSource(pattern),
703    },
704    sticky: {
705      __proto__: null,
706      configurable: true,
707      value: RegExpPrototypeGetSticky(pattern),
708    },
709    unicode: {
710      __proto__: null,
711      configurable: true,
712      value: RegExpPrototypeGetUnicode(pattern),
713    },
714  });
715  ObjectDefineProperty(pattern, 'flags', {
716    __proto__: null,
717    configurable: true,
718    value: RegExpPrototypeGetFlags(pattern),
719  });
720  return pattern;
721};
722
723
724/**
725 * @param {string} str
726 * @param {RegExp} regexp
727 * @returns {number}
728 */
729primordials.SafeStringPrototypeSearch = (str, regexp) => {
730  regexp.lastIndex = 0;
731  const match = RegExpPrototypeExec(regexp, str);
732  return match ? match.index : -1;
733};
734
735ObjectSetPrototypeOf(primordials, null);
736ObjectFreeze(primordials);
737