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