diff --git a/scripts/build/deps/webkit.ts b/scripts/build/deps/webkit.ts index 87776fa6480d..179bd6c9dfbf 100644 --- a/scripts/build/deps/webkit.ts +++ b/scripts/build/deps/webkit.ts @@ -3,7 +3,7 @@ * for local mode. Override via `--webkit-version=` to test a branch. * From https://github.com/oven-sh/WebKit releases. */ -export const WEBKIT_VERSION = "e6e37cda216c0292ae68c30c84a9dc8601d0fba5"; +export const WEBKIT_VERSION = "autobuild-preview-pr-341-291ee11e"; /** * WebKit (JavaScriptCore) — the JS engine. diff --git a/src/codegen/generate-primordials-probe.js b/src/codegen/generate-primordials-probe.js new file mode 100644 index 000000000000..f0df1f020dc7 --- /dev/null +++ b/src/codegen/generate-primordials-probe.js @@ -0,0 +1,202 @@ +// Probe half of src/codegen/generate-primordials.ts. Runs inside a pristine target +// bun binary and reports, for every member Node's primordials construction would +// produce from this engine's intrinsics, where the pristine value comes from. +// Output: JSON { entries: [...], missing: [...] } on stdout. +// +// This mirrors lib/internal/per_context/primordials.js's enumeration exactly; only +// what is recorded differs (provenance instead of values). + +const varargsMethods = [ + "ArrayOf", + "ArrayPrototypePush", + "ArrayPrototypeUnshift", + "MathHypot", + "MathMax", + "MathMin", + "StringFromCharCode", + "StringFromCodePoint", + "StringPrototypeConcat", + "TypedArrayOf", +]; + +const entries = []; +const missing = []; + +function keyDescription(key) { + // Well-known symbols are named by their identifier ("iterator", "toStringTag"). + return typeof key === "symbol" ? key.description.replace(/^Symbol\./, "") : key; +} + +// Same renaming Node applies: symbol keys become SymbolX, string keys get their +// first character upper-cased. +function getNewKey(key) { + return typeof key === "symbol" + ? `Symbol${key.description[7].toUpperCase()}${key.description.slice(8)}` + : `${key[0].toUpperCase()}${key.slice(1)}`; +} + +function record(entry) { + entries.push(entry); +} + +function copyOwnProperties(object, holder, prefix, mode) { + if (object === undefined || object === null) { + missing.push(holder); + return; + } + for (const key of Reflect.ownKeys(object)) { + const newKey = getNewKey(key); + const desc = Reflect.getOwnPropertyDescriptor(object, key); + const symbolKey = typeof key === "symbol"; + // Original attributes, so a descriptor can be rebuilt pristinely by the generator. + const attributes = { enumerable: desc.enumerable, configurable: desc.configurable, writable: desc.writable }; + if ("get" in desc) { + record({ + name: `${prefix}Get${newKey}`, + holder, + key: keyDescription(key), + symbolKey, + kind: "Getter", + attributes, + }); + if (desc.set) + record({ + name: `${prefix}Set${newKey}`, + holder, + key: keyDescription(key), + symbolKey, + kind: "Setter", + attributes, + }); + continue; + } + const name = `${prefix}${newKey}`; + const value = desc.value; + const type = value === null ? "null" : typeof value; + if (type === "function") { + // mode: "uncurried" (prototype methods), "static", or "bound" (receiver-bound statics). + record({ name, holder, key: keyDescription(key), symbolKey, kind: "Method", call: mode, attributes }); + } else if (type === "object" || type === "symbol") { + record({ name, holder, key: keyDescription(key), symbolKey, kind: "Value", valueType: type, attributes }); + } else { + // Spec constants (constructor length/name, Math/Number constants, BYTES_PER_ELEMENT, + // Symbol.toStringTag strings): inlined as literals rather than read at runtime. + const literal = type === "string" ? JSON.stringify(value) : String(value); + record({ name, holder, key: keyDescription(key), symbolKey, kind: "Literal", literal, attributes }); + } + if (varargsMethods.includes(name)) record({ name: `${name}Apply`, kind: "ApplyVariant", base: name }); + } +} + +const G = globalThis; + +// Configurable value properties of the global object. +record({ name: "Proxy", kind: "HolderSelf", holder: "ProxyObject" }); +// The `globalThis` user code observes is the global's own globalThis property +// (an accessor to the global-this object), not the global object itself. +record({ + name: "globalThis", + holder: "GlobalObject", + key: "globalThis", + symbolKey: false, + kind: "Value", + valueType: "object", +}); +for (const name of ["decodeURI", "decodeURIComponent", "encodeURI", "encodeURIComponent", "escape", "eval", "unescape"]) + record({ name, holder: "GlobalObject", key: name, symbolKey: false, kind: "Method", call: "static" }); + +// Namespace objects. +for (const name of ["Atomics", "JSON", "Math", "Reflect"]) copyOwnProperties(G[name], `${name}Object`, name, "static"); +copyOwnProperties(G.Proxy, "ProxyObject", "Proxy", "static"); + +// Intrinsic constructors: the constructor itself, its own properties, and its prototype's. +for (const name of [ + "AggregateError", + "Array", + "ArrayBuffer", + "BigInt", + "BigInt64Array", + "BigUint64Array", + "Boolean", + "DataView", + "Date", + "Error", + "EvalError", + "FinalizationRegistry", + "Float16Array", + "Float32Array", + "Float64Array", + "Function", + "Int16Array", + "Int32Array", + "Int8Array", + "Iterator", + "Map", + "Number", + "Object", + "RangeError", + "ReferenceError", + "RegExp", + "Set", + "String", + "Symbol", + "SyntaxError", + "TypeError", + "URIError", + "Uint16Array", + "Uint32Array", + "Uint8Array", + "Uint8ClampedArray", + "WeakMap", + "WeakRef", + "WeakSet", +]) { + record({ name, kind: "HolderSelf", holder: `${name}Constructor` }); + copyOwnProperties(G[name], `${name}Constructor`, name, "static"); + copyOwnProperties(G[name]?.prototype, `${name}Prototype`, `${name}Prototype`, "uncurried"); +} + +// Constructors whose statics need the constructor as receiver (Promise.all etc.). +for (const name of ["Promise"]) { + record({ name, kind: "HolderSelf", holder: `${name}Constructor` }); + copyOwnProperties(G[name], `${name}Constructor`, name, "bound"); + copyOwnProperties(G[name].prototype, `${name}Prototype`, `${name}Prototype`, "uncurried"); +} + +// %TypedArray%: not on the global object; statics need a concrete constructor receiver. +{ + const TypedArray = Reflect.getPrototypeOf(Uint8Array); + record({ name: "TypedArray", kind: "HolderSelf", holder: "TypedArrayConstructor" }); + copyOwnProperties(TypedArray, "TypedArrayConstructor", "TypedArray", "uncurried"); + copyOwnProperties(TypedArray.prototype, "TypedArrayPrototype", "TypedArrayPrototype", "uncurried"); +} + +// Abstract prototypes with no exposed constructor. +for (const [name, object] of [ + ["ArrayIteratorPrototype", Reflect.getPrototypeOf([][Symbol.iterator]())], + ["AsyncFunctionPrototype", Reflect.getPrototypeOf(async function () {})], + ["AsyncGeneratorFunctionPrototype", Reflect.getPrototypeOf(async function* () {})], + ["AsyncIteratorPrototype", Reflect.getPrototypeOf(Reflect.getPrototypeOf(async function* () {}).prototype)], + ["GeneratorFunctionPrototype", Reflect.getPrototypeOf(function* () {})], + ["IteratorHelperPrototype", Reflect.getPrototypeOf([].values().drop(0))], + ["MapIteratorPrototype", Reflect.getPrototypeOf(new Map()[Symbol.iterator]())], + ["RegExpStringIteratorPrototype", Reflect.getPrototypeOf(RegExp.prototype[Symbol.matchAll].call(/a/g, "a"))], + ["SetIteratorPrototype", Reflect.getPrototypeOf(new Set()[Symbol.iterator]())], + ["StringIteratorPrototype", Reflect.getPrototypeOf(""[Symbol.iterator]())], + [ + "WrapForValidIteratorPrototype", + Reflect.getPrototypeOf( + Iterator.from({ + next() { + return { done: true }; + }, + }), + ), + ], +]) { + record({ name, kind: "HolderSelf", holder: name }); + copyOwnProperties(object, name, name, "uncurried"); +} + +// Bun.write is native: the probe must not depend on the module it generates. +await Bun.write(Bun.stdout, JSON.stringify({ entries, missing })); diff --git a/src/codegen/generate-primordials.ts b/src/codegen/generate-primordials.ts new file mode 100644 index 000000000000..eacbf0a1a479 --- /dev/null +++ b/src/codegen/generate-primordials.ts @@ -0,0 +1,601 @@ +// Generates the primordials artifacts from a live probe of the engine: +// +// 1. /Source/JavaScriptCore/runtime/JSCPrimordialsTable.h — the per-holder +// entry tables, holder lists, and holder-accessor macro consumed by JSCPrimordials.h/.cpp. +// 2. src/js/internal/primordials.js — Node's primordials object, built from the +// $Name link-time constants (member set and semantics identical to Node's +// lib/internal/per_context/primordials.js). +// 3. src/js/primordials.d.ts — typedefs for the $Name link-time constants. +// +// Usage: +// bun src/codegen/generate-primordials.ts --bun= [--webkit=] +// +// The probe (generate-primordials-probe.js) runs Node's construction algorithm inside +// the target binary and reports each member's provenance; this file only maps that +// provenance onto the engine and emits code. Rerun whenever JSC's builtin surface changes; +// test/js/bun/util/primordials.test.ts fails if the checked-in artifacts drift. + +import { spawnSync } from "node:child_process"; +import { existsSync, readFileSync, writeFileSync } from "node:fs"; +import { join, resolve } from "node:path"; + +const root = resolve(import.meta.dir, "../.."); +const probePath = join(import.meta.dir, "generate-primordials-probe.js"); +const moduleOutput = join(root, "src/js/internal/primordials.js"); +const dtsOutput = join(root, "src/js/primordials.d.ts"); + +// ─────────────────────────────────────────────────────────────────────────────── +// Arguments +// ─────────────────────────────────────────────────────────────────────────────── + +function argValue(name: string): string | undefined { + const prefix = `--${name}=`; + return process.argv.find(arg => arg.startsWith(prefix))?.slice(prefix.length); +} + +const bunBinary = argValue("bun") ?? process.execPath; +const webkitDir = + argValue("webkit") ?? + [process.env.BUN_WEBKIT_PATH, join(root, "vendor/WebKit")].find(dir => dir && existsSync(join(dir, "Source"))); +if (!webkitDir) throw new Error("WebKit source directory not found; pass --webkit= or set BUN_WEBKIT_PATH"); +const headerOutput = join(webkitDir, "Source/JavaScriptCore/runtime/JSCPrimordialsTable.h"); + +// ─────────────────────────────────────────────────────────────────────────────── +// Probe +// ─────────────────────────────────────────────────────────────────────────────── + +interface Entry { + name: string; + holder?: string; + key?: string; + symbolKey?: boolean; + kind: "Method" | "Getter" | "Setter" | "Value" | "HolderSelf" | "Literal" | "ApplyVariant"; + call?: "uncurried" | "static" | "bound"; + valueType?: string; + literal?: string; + base?: string; + attributes?: { enumerable: boolean; configurable: boolean; writable?: boolean }; +} + +const probe = spawnSync(bunBinary, [probePath], { env: { ...process.env, BUN_DEBUG_QUIET_LOGS: "1" } }); +if (probe.status !== 0) throw new Error(`probe failed:\n${probe.stderr}`); +const probeResult: { entries: Entry[]; missing: string[] } = JSON.parse(probe.stdout.toString()); +if (probeResult.missing.length) throw new Error(`probe: missing intrinsics: ${probeResult.missing.join(", ")}`); + +// ─────────────────────────────────────────────────────────────────────────────── +// Holder → engine mapping +// ─────────────────────────────────────────────────────────────────────────────── +// +// accessor: expression valid inside a JSGlobalObject member (returns JSObject*). +// eager: exists once JSGlobalObject::init() returns (snapshotted at the end of init); +// lazy holders instead snapshot inside their creation hook. +// type: TypeScript type of the holder object, for the generated .d.ts. + +interface Holder { + accessor: string; + eager: boolean; + type: string; +} + +const nativeError = (member: string, part: "prototype" | "constructor"): Holder => ({ + accessor: `m_${member}Structure.${part}(this)`, + eager: false, + type: part === "prototype" ? "Error" : "ErrorConstructor", +}); +const typedArrayHolder = (type: string, part: "prototype" | "constructor", tsName: string): Holder => ({ + accessor: part === "prototype" ? `typedArrayPrototype(Type${type})` : `typedArrayConstructor(Type${type})`, + eager: false, + type: part === "prototype" ? tsName : `${tsName}Constructor`, +}); +const namespaceHolder = (className: string, jsName: string, creator: string, type: string): Holder => ({ + accessor: `pristineNamespaceObject<${className}>(vm, this, Identifier::fromString(vm, "${jsName}"_s), ${creator})`, + eager: false, + type, +}); + +const holders: Record = { + GlobalObject: { accessor: "this", eager: true, type: "typeof globalThis" }, + ObjectPrototype: { accessor: "objectPrototype()", eager: true, type: "Object" }, + ObjectConstructor: { accessor: "m_objectConstructor.get()", eager: true, type: "ObjectConstructor" }, + FunctionPrototype: { accessor: "functionPrototype()", eager: true, type: "Function" }, + FunctionConstructor: { accessor: "functionConstructor()", eager: true, type: "FunctionConstructor" }, + ArrayPrototype: { accessor: "arrayPrototype()", eager: true, type: "Array" }, + ArrayConstructor: { accessor: "m_arrayConstructor.get()", eager: true, type: "ArrayConstructor" }, + StringPrototype: { accessor: "stringPrototype()", eager: true, type: "String" }, + StringConstructor: { accessor: "stringConstructor()", eager: true, type: "StringConstructor" }, + RegExpPrototype: { accessor: "regExpPrototype()", eager: true, type: "RegExp" }, + RegExpConstructor: { accessor: "regExpConstructor()", eager: true, type: "RegExpConstructor" }, + SymbolPrototype: { accessor: "symbolPrototype()", eager: true, type: "Symbol" }, + SymbolConstructor: { accessor: "symbolConstructor()", eager: true, type: "SymbolConstructor" }, + BigIntPrototype: { accessor: "bigIntPrototype()", eager: true, type: "BigInt" }, + BigIntConstructor: { accessor: "bigIntConstructor()", eager: true, type: "BigIntConstructor" }, + PromisePrototype: { accessor: "promisePrototype()", eager: true, type: "Promise" }, + PromiseConstructor: { accessor: "promiseConstructor()", eager: true, type: "PromiseConstructor" }, + IteratorPrototype: { accessor: "iteratorPrototype()", eager: true, type: "IteratorObject" }, + IteratorConstructor: { accessor: "iteratorConstructor()", eager: true, type: "typeof Iterator" }, + ArrayIteratorPrototype: { accessor: "arrayIteratorPrototype()", eager: true, type: "ArrayIterator" }, + StringIteratorPrototype: { accessor: "m_stringIteratorPrototype.get()", eager: true, type: "StringIterator" }, + MapIteratorPrototype: { accessor: "mapIteratorPrototype()", eager: true, type: "MapIterator" }, + SetIteratorPrototype: { accessor: "setIteratorPrototype()", eager: true, type: "SetIterator" }, + RegExpStringIteratorPrototype: { + accessor: "m_regExpStringIteratorStructure.get()->storedPrototypeObject()", + eager: true, + type: "RegExpStringIterator", + }, + IteratorHelperPrototype: { accessor: "iteratorHelperPrototype()", eager: true, type: "IteratorObject" }, + WrapForValidIteratorPrototype: { + accessor: "m_wrapForValidIteratorStructure.get()->storedPrototypeObject()", + eager: true, + type: "IteratorObject", + }, + AsyncIteratorPrototype: { accessor: "asyncIteratorPrototype()", eager: true, type: "AsyncIteratorObject" }, + GeneratorFunctionPrototype: { accessor: "generatorFunctionPrototype()", eager: true, type: "GeneratorFunction" }, + AsyncFunctionPrototype: { accessor: "asyncFunctionPrototype()", eager: true, type: "Function" }, + AsyncGeneratorFunctionPrototype: { + accessor: "asyncGeneratorFunctionPrototype()", + eager: true, + type: "AsyncGeneratorFunction", + }, + WeakRefPrototype: { accessor: "m_weakObjectRefPrototype.get()", eager: true, type: "WeakRef" }, + WeakRefConstructor: { accessor: "weakObjectRefConstructor()", eager: true, type: "WeakRefConstructor" }, + FinalizationRegistryPrototype: { + accessor: "m_finalizationRegistryPrototype.get()", + eager: true, + type: "FinalizationRegistry", + }, + FinalizationRegistryConstructor: { + accessor: "finalizationRegistryConstructor()", + eager: true, + type: "FinalizationRegistryConstructor", + }, + + // Lazy holders — snapshotted in their creation hooks. + BooleanPrototype: { accessor: "booleanPrototype()", eager: false, type: "Boolean" }, + BooleanConstructor: { + accessor: "booleanObjectConstructor()", + eager: false, + type: "BooleanConstructor", + }, + NumberPrototype: { accessor: "numberPrototype()", eager: false, type: "Number" }, + NumberConstructor: { + accessor: "numberObjectConstructor()", + eager: false, + type: "NumberConstructor", + }, + DatePrototype: { accessor: "datePrototype()", eager: false, type: "Date" }, + DateConstructor: { accessor: "dateConstructor()", eager: false, type: "DateConstructor" }, + ErrorPrototype: { accessor: "errorPrototype()", eager: false, type: "Error" }, + ErrorConstructor: { accessor: "errorConstructor()", eager: false, type: "ErrorConstructor" }, + MapPrototype: { accessor: "mapPrototype()", eager: false, type: "Map" }, + MapConstructor: { accessor: "mapConstructor()", eager: false, type: "MapConstructor" }, + SetPrototype: { accessor: "jsSetPrototype()", eager: false, type: "Set" }, + SetConstructor: { accessor: "setConstructor()", eager: false, type: "SetConstructor" }, + WeakMapPrototype: { + accessor: "m_weakMapStructure.prototype(this)", + eager: false, + type: "WeakMap", + }, + WeakMapConstructor: { accessor: "weakMapConstructor()", eager: false, type: "WeakMapConstructor" }, + WeakSetPrototype: { + accessor: "m_weakSetStructure.prototype(this)", + eager: false, + type: "WeakSet", + }, + WeakSetConstructor: { accessor: "weakSetConstructor()", eager: false, type: "WeakSetConstructor" }, + ArrayBufferPrototype: { + accessor: "arrayBufferPrototype(ArrayBufferSharingMode::Default)", + eager: false, + type: "ArrayBuffer", + }, + ArrayBufferConstructor: { + accessor: "arrayBufferConstructor(ArrayBufferSharingMode::Default)", + eager: false, + type: "ArrayBufferConstructor", + }, + AggregateErrorPrototype: nativeError("aggregateError", "prototype"), + AggregateErrorConstructor: nativeError("aggregateError", "constructor"), + EvalErrorPrototype: nativeError("evalError", "prototype"), + EvalErrorConstructor: nativeError("evalError", "constructor"), + RangeErrorPrototype: nativeError("rangeError", "prototype"), + RangeErrorConstructor: nativeError("rangeError", "constructor"), + ReferenceErrorPrototype: nativeError("referenceError", "prototype"), + ReferenceErrorConstructor: nativeError("referenceError", "constructor"), + SyntaxErrorPrototype: nativeError("syntaxError", "prototype"), + SyntaxErrorConstructor: nativeError("syntaxError", "constructor"), + TypeErrorPrototype: nativeError("typeError", "prototype"), + TypeErrorConstructor: nativeError("typeError", "constructor"), + URIErrorPrototype: nativeError("URIError", "prototype"), + URIErrorConstructor: nativeError("URIError", "constructor"), + TypedArrayPrototype: { + accessor: "m_typedArrayProto.get(this)", + eager: false, + type: "Uint8Array", + }, + TypedArrayConstructor: { + accessor: "m_typedArraySuperConstructor.get(this)", + eager: false, + type: "Uint8ArrayConstructor", + }, + DataViewPrototype: typedArrayHolder("DataView", "prototype", "DataView"), + DataViewConstructor: typedArrayHolder("DataView", "constructor", "DataView"), + Int8ArrayPrototype: typedArrayHolder("Int8", "prototype", "Int8Array"), + Int8ArrayConstructor: typedArrayHolder("Int8", "constructor", "Int8Array"), + Uint8ArrayPrototype: typedArrayHolder("Uint8", "prototype", "Uint8Array"), + Uint8ArrayConstructor: typedArrayHolder("Uint8", "constructor", "Uint8Array"), + Uint8ClampedArrayPrototype: typedArrayHolder("Uint8Clamped", "prototype", "Uint8ClampedArray"), + Uint8ClampedArrayConstructor: typedArrayHolder("Uint8Clamped", "constructor", "Uint8ClampedArray"), + Int16ArrayPrototype: typedArrayHolder("Int16", "prototype", "Int16Array"), + Int16ArrayConstructor: typedArrayHolder("Int16", "constructor", "Int16Array"), + Uint16ArrayPrototype: typedArrayHolder("Uint16", "prototype", "Uint16Array"), + Uint16ArrayConstructor: typedArrayHolder("Uint16", "constructor", "Uint16Array"), + Int32ArrayPrototype: typedArrayHolder("Int32", "prototype", "Int32Array"), + Int32ArrayConstructor: typedArrayHolder("Int32", "constructor", "Int32Array"), + Uint32ArrayPrototype: typedArrayHolder("Uint32", "prototype", "Uint32Array"), + Uint32ArrayConstructor: typedArrayHolder("Uint32", "constructor", "Uint32Array"), + Float16ArrayPrototype: typedArrayHolder("Float16", "prototype", "Float16Array"), + Float16ArrayConstructor: typedArrayHolder("Float16", "constructor", "Float16Array"), + Float32ArrayPrototype: typedArrayHolder("Float32", "prototype", "Float32Array"), + Float32ArrayConstructor: typedArrayHolder("Float32", "constructor", "Float32Array"), + Float64ArrayPrototype: typedArrayHolder("Float64", "prototype", "Float64Array"), + Float64ArrayConstructor: typedArrayHolder("Float64", "constructor", "Float64Array"), + BigInt64ArrayPrototype: typedArrayHolder("BigInt64", "prototype", "BigInt64Array"), + BigInt64ArrayConstructor: typedArrayHolder("BigInt64", "constructor", "BigInt64Array"), + BigUint64ArrayPrototype: typedArrayHolder("BigUint64", "prototype", "BigUint64Array"), + BigUint64ArrayConstructor: typedArrayHolder("BigUint64", "constructor", "BigUint64Array"), + MathObject: namespaceHolder("MathObject", "Math", "createMathProperty", "Math"), + JSONObject: namespaceHolder("JSONObject", "JSON", "createJSONProperty", "JSON"), + ReflectObject: namespaceHolder("ReflectObject", "Reflect", "createReflectProperty", "typeof Reflect"), + AtomicsObject: namespaceHolder("AtomicsObject", "Atomics", "createAtomicsProperty", "Atomics"), + ProxyObject: namespaceHolder("ProxyConstructor", "Proxy", "createProxyProperty", "ProxyConstructor"), +}; + +// Lazy builtin types created by JSGlobalObject.cpp's CREATE_PROTOTYPE_FOR_LAZY_TYPE +// macro, keyed by that macro's capitalName. +const lazyTypeMacroNames: Record = { + Boolean: "Boolean", + Date: "Date", + Error: "Error", + Map: "Map", + Number: "Number", + Set: "Set", + WeakMap: "WeakMap", + WeakSet: "WeakSet", + JSArrayBuffer: "ArrayBuffer", +}; + +// ─────────────────────────────────────────────────────────────────────────────── +// Normalize the probe entries +// ─────────────────────────────────────────────────────────────────────────────── + +const entries = probeResult.entries; +for (const entry of entries) { + if (entry.kind !== "Value" || entry.valueType !== "object" || !entry.holder || !entry.key) continue; + // A constructor's `prototype` / a prototype's own object property that is itself a + // holder: reference the holder object directly rather than reading the property. + const target = + entry.key === "prototype" && entry.holder.endsWith("Constructor") + ? entry.holder.replace(/Constructor$/, "Prototype") + : entry.name in holders + ? entry.name + : null; + if (target && target in holders) { + entry.kind = "HolderSelf"; + entry.holder = target; + delete entry.key; + } +} +for (const entry of entries) + if (entry.holder && !(entry.holder in holders)) + throw new Error(`No engine mapping for holder ${entry.holder} (needed by ${entry.name})`); + +// A member named like an existing link-time constant (Array, Promise, ...) is +// that same object, so it reuses the constant. A name that is only a private +// identifier (Number, ArrayBuffer) keeps a slot under a distinct engine name. +function scanNames(file: string, pattern: RegExp): Set { + return new Set( + [...readFileSync(join(webkitDir, "Source/JavaScriptCore", file), "utf8").matchAll(pattern)].map(m => m[1]), + ); +} +const linkTimeConstantNames = scanNames("bytecode/LinkTimeConstant.h", /^\s*v\((\w+),/gm); +const privateIdentifierNames = scanNames("builtins/BuiltinNames.h", /^\s*macro\((\w+)\)/gm); + +const reused = entries.filter( + e => linkTimeConstantNames.has(e.name) && e.kind !== "Literal" && e.kind !== "ApplyVariant", +); +if (reused.length) console.log(`reusing existing link-time constants for: ${reused.map(e => e.name).join(", ")}`); +for (const entry of reused) + if (entry.kind !== "HolderSelf") + throw new Error(`link-time-constant name collision on non-constructor member: ${entry.name}`); + +// Engine identifiers can't contain the punctuation Node keeps in the legacy +// RegExp static names ("RegExpGet$&", ...), and can't collide with an existing +// private identifier; those get a distinct $Name while the module keeps Node's key. +const dollarSuffixes: Record = { + "&": "Ampersand", + "'": "Apostrophe", + "`": "Backtick", + "+": "Plus", + "_": "Underscore", + "*": "Asterisk", +}; +const engineName = (name: string) => { + const sanitized = name.replace(/\$(.)/g, (_, ch: string) => `Dollar${dollarSuffixes[ch] ?? ch}`); + return privateIdentifierNames.has(sanitized) && !linkTimeConstantNames.has(sanitized) + ? `${sanitized}Primordial` + : sanitized; +}; +const jsKey = (name: string) => (/^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name)); + +const engineEntries = entries.filter( + e => e.kind !== "Literal" && e.kind !== "ApplyVariant" && !linkTimeConstantNames.has(e.name), +); +const engineKinds = { + Method: "Method", + Getter: "Getter", + Setter: "Setter", + Value: "Value", + HolderSelf: "Self", +} as const; + +// ─────────────────────────────────────────────────────────────────────────────── +// 1. JSCPrimordialsTable.h +// ─────────────────────────────────────────────────────────────────────────────── + +const holderOrder = Object.keys(holders); +const entriesByHolder = new Map(holderOrder.map(h => [h, []])); +for (const entry of engineEntries) entriesByHolder.get(entry.holder!)!.push(entry); + +function tableLine(entry: Entry, widths: [number, number]): string { + const key = entry.kind === "HolderSelf" ? "SELF" : entry.symbolKey ? `SYM(${entry.key})` : `PROP("${entry.key}")`; + return ` V(${(engineName(entry.name) + ",").padEnd(widths[0] + 1)} ${(key + ",").padEnd(widths[1] + 1)} ${engineKinds[entry.kind as keyof typeof engineKinds]}) \\`; +} + +let header = `// GENERATED FILE — do not edit. Regenerate with: +// bun src/codegen/generate-primordials.ts --bun= --webkit= +// (src/codegen in oven-sh/bun). Derived from Node.js's primordials construction +// applied to this engine's intrinsics; see JSCPrimordials.h for the mechanism. + +#pragma once + +#if USE(BUN_JSC_ADDITIONS) + +namespace JSC { + +// V(name, key, kind): key is PROP("string"), SYM(wellKnownSymbolName), or SELF +// (the holder object itself); kind is Method | Getter | Setter | Value | Self. +`; + +for (const holder of holderOrder) { + const list = entriesByHolder.get(holder)!; + const widths: [number, number] = [ + Math.max(0, ...list.map(e => engineName(e.name).length)), + Math.max(0, ...list.map(e => (e.kind === "HolderSelf" ? 4 : e.symbolKey ? e.key!.length + 5 : e.key!.length + 8))), + ]; + header += `\n#define JSC_FOREACH_PRIMORDIAL_${holder}(V) \\\n`; + header += list.map(entry => tableLine(entry, widths)).join("\n") + (list.length ? "\n" : "\n\n"); +} + +const eagerHolders = holderOrder.filter(h => holders[h].eager); +const lazyHolders = holderOrder.filter(h => !holders[h].eager); +header += ` +// --------------------------------------------------------------------------- +// Holders, eager (exist after JSGlobalObject::init(), snapshotted there) then +// lazy (snapshotted where they are created). +// --------------------------------------------------------------------------- + +#define JSC_FOREACH_PRIMORDIAL_EAGER_HOLDER(H) \\ +${eagerHolders.map(h => ` H(${h}) \\`).join("\n")} + +#define JSC_FOREACH_PRIMORDIAL_LAZY_HOLDER(H) \\ +${lazyHolders.map(h => ` H(${h}) \\`).join("\n")} + +#define JSC_FOREACH_PRIMORDIAL_HOLDER(H) \\ + JSC_FOREACH_PRIMORDIAL_EAGER_HOLDER(H) \\ + JSC_FOREACH_PRIMORDIAL_LAZY_HOLDER(H) \\ + +#define JSC_FOREACH_PRIMORDIAL_NAME(V) \\ +${holderOrder.map(h => ` JSC_FOREACH_PRIMORDIAL_${h}(V) \\`).join("\n")} + +// V(Holder, expression yielding the holder JSObject* inside a JSGlobalObject member). +#define JSC_FOREACH_PRIMORDIAL_HOLDER_ACCESSOR(V) \\ +${holderOrder.map(h => ` V(${h}, ${holders[h].accessor}) \\`).join("\n")} + +// Names CREATE_PROTOTYPE_FOR_LAZY_TYPE's hook uses for its capitalName parameter. +${Object.entries(lazyTypeMacroNames) + .map( + ([macroName, holder]) => + `#define JSC_PRIMORDIAL_LAZY_TYPE_PROTOTYPE_HOLDER_${macroName} PrimordialHolder::${holder}Prototype\n#define JSC_PRIMORDIAL_LAZY_TYPE_CONSTRUCTOR_HOLDER_${macroName} PrimordialHolder::${holder}Constructor`, + ) + .join("\n")} + +} // namespace JSC + +#endif // USE(BUN_JSC_ADDITIONS) +`; + +writeFileSync(headerOutput, header); +console.log(`wrote ${engineEntries.length} entries across ${holderOrder.length} holders to ${headerOutput}`); + +// ─────────────────────────────────────────────────────────────────────────────── +// 2. src/js/internal/primordials.js +// ─────────────────────────────────────────────────────────────────────────────── + +// The engine constant behind a manifest name; a few Node names differ from ours. +const constant = (entry: Entry) => `$${engineName(entry.name)}`; + +const propertyLines: string[] = []; +for (const entry of entries) { + switch (entry.kind) { + case "Literal": + propertyLines.push(` ${jsKey(entry.name)}: ${entry.literal},`); + break; + case "HolderSelf": + case "Value": + propertyLines.push(` ${jsKey(entry.name)}: ${constant(entry)},`); + break; + case "Getter": + case "Setter": + propertyLines.push(` ${jsKey(entry.name)}: uncurryThis(${constant(entry)}),`); + break; + case "Method": + if (entry.call === "uncurried") propertyLines.push(` ${jsKey(entry.name)}: uncurryThis(${constant(entry)}),`); + else if (entry.call === "bound") + propertyLines.push( + ` ${entry.name}: $FunctionPrototypeBind.$call(${constant(entry)}, $${entry.holder!.replace(/Constructor$/, "")}),`, + ); + else propertyLines.push(` ${jsKey(entry.name)}: ${constant(entry)},`); + break; + case "ApplyVariant": { + const base = entries.find(e => e.name === entry.base)!; + // Statics/bound get the receiver pre-bound so the variant takes (argsArray), + // as in Node; prototype methods take (thisArg, argsArray). Namespace (Math) + // statics never read `this`, so their bound receiver is undefined. + const boundReceiver = + base.call === "static" && base.holder!.endsWith("Constructor") + ? `$${base.holder!.replace(/Constructor$/, "")}` + : base.call === "static" + ? "undefined" + : null; + propertyLines.push( + boundReceiver !== null + ? ` ${jsKey(entry.name)}: applyBind($${engineName(base.name)}, ${boundReceiver}),` + : ` ${jsKey(entry.name)}: applyBind($${engineName(base.name)}),`, + ); + break; + } + } +} + +// Pristine own-property descriptor records for the Safe* bases: the epilogue's +// Safe classes are built from these ($Name values, original attributes) rather +// than by reading the live prototypes, so a load after user code stays pristine. +const safeBases = ["Map", "Set", "WeakMap", "WeakSet", "FinalizationRegistry", "WeakRef", "Promise"]; +const pristineDescriptorLines: string[] = []; +for (const base of safeBases) { + for (const part of ["Prototype", "Constructor"]) { + const holder = `${base}${part}`; + const byKey = new Map(); + for (const entry of entries) { + if (entry.holder !== holder || entry.kind === "HolderSelf" || entry.kind === "ApplyVariant") continue; + const key = `${entry.symbolKey ? "symbol:" : ""}${entry.key}`; + const slot = byKey.get(key) ?? {}; + if (entry.kind === "Getter") slot.get = entry; + else if (entry.kind === "Setter") slot.set = entry; + else slot.data = entry; + byKey.set(key, slot); + } + const descriptorLines: string[] = []; + for (const [key, slot] of byKey) { + const anyEntry = (slot.data ?? slot.get ?? slot.set)!; + const property = + slot.data?.symbolKey || slot.get?.symbolKey + ? `[$${engineName(`Symbol${anyEntry.key![0].toUpperCase()}${anyEntry.key!.slice(1)}`)}]` + : jsKey(anyEntry.key!); + const { enumerable, configurable, writable } = anyEntry.attributes!; + const parts: string[] = ["__proto__: null"]; + if (slot.data) { + parts.push(`value: ${slot.data.kind === "Literal" ? slot.data.literal : constant(slot.data)}`); + parts.push(`writable: ${writable}`); + } else { + if (slot.get) parts.push(`get: ${constant(slot.get)}`); + if (slot.set) parts.push(`set: ${constant(slot.set)}`); + } + parts.push(`enumerable: ${enumerable}`, `configurable: ${configurable}`); + descriptorLines.push(` ${property}: { ${parts.join(", ")} },`); + } + pristineDescriptorLines.push(`pristineDescriptors.${holder} = {`, " __proto__: null,", ...descriptorLines, "};"); + } +} + +const moduleHeader = readFileSync(join(import.meta.dir, "primordials-module-prologue.js"), "utf8"); +const module = `${moduleHeader} +const primordials = { + __proto__: null, +${propertyLines.join("\n")} +}; + +// Pristine descriptors of the Safe* bases' original properties (see epilogue). +const pristineDescriptors = { __proto__: null }; +${pristineDescriptorLines.join("\n")} + +${readFileSync(join(import.meta.dir, "primordials-module-epilogue.js"), "utf8")} +export default primordials; +`; +// Every $Name the module's code references must resolve at parse time: to one of our +// primordial entries or an existing engine constant. Fail generation otherwise. +const declaredConstants = new Set([...engineEntries.map(e => engineName(e.name)), ...linkTimeConstantNames]); +const codeOnly = module.replace(/\/\/[^\n]*|\/\*[\s\S]*?\*\/|"(?:[^"\\]|\\.)*"/g, ""); +// (? m[1])), +].filter(name => !declaredConstants.has(name)); +if (unknownReferences.length) + throw new Error(`generated module references undefined constants: ${unknownReferences.join(", ")}`); + +writeFileSync(moduleOutput, module); +console.log(`wrote ${entries.length} members to ${moduleOutput}`); + +// ─────────────────────────────────────────────────────────────────────────────── +// 3. src/js/primordials.d.ts +// ─────────────────────────────────────────────────────────────────────────────── + +const dtsLines: string[] = []; +for (const entry of engineEntries) { + const type = holders[entry.holder!].type; + const key = entry.symbolKey ? `typeof Symbol.${entry.key}` : JSON.stringify(entry.key); + switch (entry.kind) { + case "HolderSelf": + dtsLines.push(`declare const $${engineName(entry.name)}: ${type};`); + break; + case "Value": + dtsLines.push(`declare const $${engineName(entry.name)}: PrimordialValue<${type}, ${key}>;`); + break; + case "Getter": + dtsLines.push(`declare const $${engineName(entry.name)}: PrimordialGetter<${type}, ${key}>;`); + break; + case "Setter": + dtsLines.push(`declare const $${engineName(entry.name)}: PrimordialSetter<${type}, ${key}>;`); + break; + case "Method": + dtsLines.push(`declare const $${engineName(entry.name)}: PrimordialMethod<${type}, ${key}>;`); + break; + } +} + +const dts = `// GENERATED FILE — do not edit. Regenerate with: +// bun src/codegen/generate-primordials.ts --bun= --webkit= +// oxlint-disable typescript/no-wrapper-object-types -- wrapper types model real prototype receivers +// +// Tamper-proof references to the original ECMAScript builtins, exposed by JSC +// (JSCPrimordials.h) as link-time constants and named after Node.js's primordials. +// Prototype methods, getters, and setters take the receiver via .$call/.$apply: +// +// $ArrayPrototypePush.$call(array, value); +// $MapPrototypeGetSize.$call(map); +// $ObjectDefineProperty(target, key, descriptor); + +type PrimordialMethod = Holder extends Record + ? Method extends (...args: infer Args) => infer Return + ? (this: Holder, ...args: Args) => Return + : Function + : Function; +type PrimordialGetter = Holder extends Record + ? (this: Holder) => Value + : Function; +type PrimordialSetter = Holder extends Record + ? (this: Holder, value: Value) => void + : Function; +type PrimordialValue = Holder extends Record ? Value : unknown; + +${dtsLines.join("\n")} +`; +writeFileSync(dtsOutput, dts); +console.log(`wrote ${dtsLines.length} declarations to ${dtsOutput}`); + +// Format the repo-local artifacts with the repo's formatter so the checked-in +// generated files are already in the shape CI's autofix would produce. +const format = spawnSync(join(root, "node_modules/.bin/prettier"), ["--write", moduleOutput, dtsOutput], { + cwd: root, + stdio: "inherit", +}); +if (format.status !== 0) throw new Error("prettier failed on the generated files"); diff --git a/src/codegen/primordials-module-epilogue.js b/src/codegen/primordials-module-epilogue.js new file mode 100644 index 000000000000..84d5eb10fed7 --- /dev/null +++ b/src/codegen/primordials-module-epilogue.js @@ -0,0 +1,402 @@ +// ─── helpers layered on the generated object (mirrors Node's primordials.js) ─── + +primordials.uncurryThis = uncurryThis; +primordials.applyBind = applyBind; + +const { + Array: ArrayConstructor, + ArrayPrototypeForEach, + ArrayPrototypeMap, + ArrayPrototypePushApply, + ArrayPrototypeSlice, + ArrayIteratorPrototypeNext, + ArrayPrototypeSymbolIterator, + FinalizationRegistry, + FunctionPrototypeCall, + Map, + MapIteratorPrototypeNext, + ObjectDefineProperties, + ObjectDefineProperty, + ObjectFreeze, + ObjectGetPrototypeOf, + ObjectSetPrototypeOf, + Promise, + PromisePrototypeThen, + PromiseResolve, + ReflectApply, + ReflectConstruct, + ReflectDefineProperty, + ReflectGet, + ReflectGetOwnPropertyDescriptor, + ReflectOwnKeys, + ReflectSet, + RegExp, + RegExpPrototypeExec, + RegExpPrototypeGetDotAll, + RegExpPrototypeGetFlags, + RegExpPrototypeGetGlobal, + RegExpPrototypeGetHasIndices, + RegExpPrototypeGetIgnoreCase, + RegExpPrototypeGetMultiline, + RegExpPrototypeGetSource, + RegExpPrototypeGetSticky, + RegExpPrototypeGetUnicode, + Set, + SetIteratorPrototypeNext, + StringIteratorPrototypeNext, + StringPrototypeSymbolIterator, + SymbolIterator, + SymbolMatch, + SymbolMatchAll, + SymbolReplace, + SymbolSearch, + SymbolSpecies, + SymbolSplit, + WeakMap, + WeakRef, + WeakSet, +} = primordials; + +// An iterator user code can't intercept: its next() and Symbol.iterator are +// captured functions and its prototype is detached and frozen. +const createSafeIterator = (factory, next) => { + class SafeIterator { + constructor(iterable) { + this._iterator = factory(iterable); + } + next() { + return next(this._iterator); + } + [SymbolIterator]() { + return this; + } + } + ObjectSetPrototypeOf(SafeIterator.prototype, null); + ObjectFreeze(SafeIterator.prototype); + ObjectFreeze(SafeIterator); + return SafeIterator; +}; + +const SafeArrayIterator = createSafeIterator(ArrayPrototypeSymbolIterator, ArrayIteratorPrototypeNext); +primordials.SafeArrayIterator = SafeArrayIterator; +primordials.SafeStringIterator = createSafeIterator(StringPrototypeSymbolIterator, StringIteratorPrototypeNext); + +const copyOwnProperties = (source, target) => { + ArrayPrototypeForEach(ReflectOwnKeys(source), key => { + if (!ReflectGetOwnPropertyDescriptor(target, key)) + ReflectDefineProperty(target, key, { __proto__: null, ...ReflectGetOwnPropertyDescriptor(source, key) }); + }); +}; + +const detachAndFreeze = safe => { + ObjectSetPrototypeOf(safe.prototype, null); + ObjectFreeze(safe.prototype); + ObjectFreeze(safe); + return safe; +}; + +const defineFromDescriptors = (descriptors, target, mapDescriptor) => { + ArrayPrototypeForEach(ReflectOwnKeys(descriptors), key => { + if (!ReflectGetOwnPropertyDescriptor(target, key)) + ReflectDefineProperty(target, key, mapDescriptor({ __proto__: null, ...descriptors[key] }, key)); + }); +}; + +// This module loads lazily, possibly after user code, so our own Safe* classes are +// built from the pristine descriptor records the generator emits rather than by +// reading the live prototypes. `iterator` = { prototype, next } (pristine): zero-arg +// methods that hand out that iterator kind are rewrapped to return safe iterators. +const makeSafeFromPristine = (unsafe, safe, prototypeDescriptors, staticDescriptors, iterator) => { + const instance = iterator ? new unsafe() : null; + defineFromDescriptors(prototypeDescriptors, safe.prototype, descriptor => { + const method = descriptor.value; + if (iterator && typeof method === "function" && method.length === 0) { + const result = FunctionPrototypeCall(method, instance); + if (result != null && typeof result === "object" && ObjectGetPrototypeOf(result) === iterator.prototype) { + const SafeIterator = createSafeIterator(uncurryThis(method), iterator.next); + descriptor.value = function () { + return new SafeIterator(this); + }; + } + } + return descriptor; + }); + defineFromDescriptors(staticDescriptors, safe, descriptor => descriptor); + return detachAndFreeze(safe); +}; + +// The exported makeSafe copies from a consumer's own classes at their call time +// (as in Node); zero-arg iterator-returning methods are rewrapped so the copies +// hand out safe iterators over a captured pristine `next`. +const makeSafe = (unsafe, safe) => { + const unsafePrototype = unsafe.prototype; + if (SymbolIterator in unsafePrototype) { + const dummy = new unsafe(); + let next; // We can reuse the same `next` method. + ArrayPrototypeForEach(ReflectOwnKeys(unsafePrototype), key => { + if (ReflectGetOwnPropertyDescriptor(safe.prototype, key)) return; + const descriptor = ReflectGetOwnPropertyDescriptor(unsafePrototype, key); + if ( + typeof descriptor.value === "function" && + descriptor.value.length === 0 && + SymbolIterator in (FunctionPrototypeCall(descriptor.value, dummy) ?? {}) + ) { + const createIterator = uncurryThis(descriptor.value); + next ??= uncurryThis(createIterator(dummy).next); + const SafeIterator = createSafeIterator(createIterator, next); + descriptor.value = function () { + return new SafeIterator(this); + }; + } + ReflectDefineProperty(safe.prototype, key, { __proto__: null, ...descriptor }); + }); + } else { + copyOwnProperties(unsafePrototype, safe.prototype); + } + copyOwnProperties(unsafe, safe); + return detachAndFreeze(safe); +}; +primordials.makeSafe = makeSafe; + +const mapIteration = { prototype: primordials.MapIteratorPrototype, next: MapIteratorPrototypeNext }; +const setIteration = { prototype: primordials.SetIteratorPrototype, next: SetIteratorPrototypeNext }; +primordials.SafeMap = makeSafeFromPristine( + Map, + class SafeMap extends Map { + constructor(i) { + super(i); + } + }, + pristineDescriptors.MapPrototype, + pristineDescriptors.MapConstructor, + mapIteration, +); +primordials.SafeWeakMap = makeSafeFromPristine( + WeakMap, + class SafeWeakMap extends WeakMap { + constructor(i) { + super(i); + } + }, + pristineDescriptors.WeakMapPrototype, + pristineDescriptors.WeakMapConstructor, +); +primordials.SafeSet = makeSafeFromPristine( + Set, + class SafeSet extends Set { + constructor(i) { + super(i); + } + }, + pristineDescriptors.SetPrototype, + pristineDescriptors.SetConstructor, + setIteration, +); +primordials.SafeWeakSet = makeSafeFromPristine( + WeakSet, + class SafeWeakSet extends WeakSet { + constructor(i) { + super(i); + } + }, + pristineDescriptors.WeakSetPrototype, + pristineDescriptors.WeakSetConstructor, +); +primordials.SafeFinalizationRegistry = makeSafeFromPristine( + FinalizationRegistry, + class SafeFinalizationRegistry extends FinalizationRegistry { + constructor(i) { + super(i); + } + }, + pristineDescriptors.FinalizationRegistryPrototype, + pristineDescriptors.FinalizationRegistryConstructor, +); +primordials.SafeWeakRef = makeSafeFromPristine( + WeakRef, + class SafeWeakRef extends WeakRef { + constructor(i) { + super(i); + } + }, + pristineDescriptors.WeakRefPrototype, + pristineDescriptors.WeakRefConstructor, +); + +const SafePromise = makeSafeFromPristine( + Promise, + class SafePromise extends Promise { + constructor(i) { + super(i); + } + }, + pristineDescriptors.PromisePrototype, + pristineDescriptors.PromiseConstructor, +); + +// The Safe* promise combinators wrap results in a plain Promise so the SafePromise +// prototype never reaches user code, and wrap each input so a tampered .then on +// a user promise cannot observe the combinator. +const SafePromisePrototypeFinallyOfSafe = uncurryThis(SafePromise.prototype.finally); +const SafePromisePrototypeThenOfSafe = uncurryThis(SafePromise.prototype.then); +primordials.SafePromisePrototypeFinally = (thisPromise, onFinally) => + new Promise((resolve, reject) => { + const wrapped = new SafePromise((resolveInner, rejectInner) => + PromisePrototypeThen(thisPromise, resolveInner, rejectInner), + ); + SafePromisePrototypeThenOfSafe(SafePromisePrototypeFinallyOfSafe(wrapped, onFinally), resolve, reject); + }); + +const arrayToSafePromiseIterable = (promises, mapFn) => + new SafeArrayIterator( + ArrayPrototypeMap( + promises, + (promise, i) => + new SafePromise((resolve, reject) => + PromisePrototypeThen(mapFn == null ? promise : mapFn(promise, i), resolve, reject), + ), + ), + ); + +const safePromiseCombinator = combinator => (promises, mapFn) => + new Promise((resolve, reject) => + SafePromisePrototypeThenOfSafe( + FunctionPrototypeCall(combinator, SafePromise, arrayToSafePromiseIterable(promises, mapFn)), + resolve, + reject, + ), + ); + +primordials.SafePromiseAll = safePromiseCombinator(SafePromise.all); +primordials.SafePromiseAllSettled = safePromiseCombinator(SafePromise.allSettled); +primordials.SafePromiseAny = safePromiseCombinator(SafePromise.any); +primordials.SafePromiseRace = safePromiseCombinator(SafePromise.race); + +// The *ReturnArrayLike/*ReturnVoid variants avoid Promise.all entirely: no +// prototype lookups, and the array-like result has no Array.prototype. +primordials.SafePromiseAllReturnArrayLike = (promises, mapFn) => + new Promise((resolve, reject) => { + const { length } = promises; + const results = ArrayConstructor(length); + ObjectSetPrototypeOf(results, null); + if (length === 0) resolve(results); + let pending = length; + for (let i = 0; i < length; i++) { + const promise = mapFn != null ? mapFn(promises[i], i) : promises[i]; + PromisePrototypeThen( + PromiseResolve(promise), + result => { + results[i] = result; + if (--pending === 0) resolve(results); + }, + reject, + ); + } + }); + +primordials.SafePromiseAllReturnVoid = (promises, mapFn) => + new Promise((resolve, reject) => { + let pending = promises.length; + if (pending === 0) resolve(); + const onFulfilled = () => { + if (--pending === 0) resolve(); + }; + for (let i = 0; i < promises.length; i++) { + const promise = mapFn != null ? mapFn(promises[i], i) : promises[i]; + PromisePrototypeThen(PromiseResolve(promise), onFulfilled, reject); + } + }); + +primordials.SafePromiseAllSettledReturnVoid = (promises, mapFn) => + new Promise(resolve => { + let pending = promises.length; + if (pending === 0) resolve(); + const onSettled = () => { + if (--pending === 0) resolve(); + }; + for (let i = 0; i < promises.length; i++) { + const promise = mapFn != null ? mapFn(promises[i], i) : promises[i]; + PromisePrototypeThen(PromiseResolve(promise), onSettled, onSettled); + } + }); + +// The raw (this-taking) originals: hardenRegExp installs them on the pattern +// itself. They come from the pristine constants, not the live RegExp.prototype, +// because this module can load after user code has replaced those properties. +const OriginalRegExpPrototypeExec = $RegExpPrototypeExec; +const OriginalRegExpPrototypeSymbolMatch = $RegExpPrototypeSymbolMatch; +const OriginalRegExpPrototypeSymbolMatchAll = $RegExpPrototypeSymbolMatchAll; +const OriginalRegExpPrototypeSymbolReplace = $RegExpPrototypeSymbolReplace; +const OriginalRegExpPrototypeSymbolSearch = $RegExpPrototypeSymbolSearch; +const OriginalRegExpPrototypeSymbolSplit = $RegExpPrototypeSymbolSplit; + +// The species String.prototype.split uses on a hardened pattern: only lastIndex +// and exec are ever consulted, and the inner pattern is a real, private RegExp. +class RegExpLikeForStringSplitting { + #regex; + constructor() { + this.#regex = ReflectConstruct(RegExp, arguments); + } + get lastIndex() { + return ReflectGet(this.#regex, "lastIndex"); + } + set lastIndex(value) { + ReflectSet(this.#regex, "lastIndex", value); + } + exec() { + return ReflectApply(OriginalRegExpPrototypeExec, this.#regex, arguments); + } +} +ObjectSetPrototypeOf(RegExpLikeForStringSplitting.prototype, null); + +// Freezes a pattern's observable protocol (Symbol.match/replace/..., exec, flags, +// species) to the original algorithms so String methods can use it after user code ran. +primordials.hardenRegExp = function hardenRegExp(pattern) { + ObjectDefineProperties(pattern, { + [SymbolMatch]: { __proto__: null, configurable: true, value: OriginalRegExpPrototypeSymbolMatch }, + [SymbolMatchAll]: { __proto__: null, configurable: true, value: OriginalRegExpPrototypeSymbolMatchAll }, + [SymbolReplace]: { __proto__: null, configurable: true, value: OriginalRegExpPrototypeSymbolReplace }, + [SymbolSearch]: { __proto__: null, configurable: true, value: OriginalRegExpPrototypeSymbolSearch }, + [SymbolSplit]: { __proto__: null, configurable: true, value: OriginalRegExpPrototypeSymbolSplit }, + constructor: { __proto__: null, configurable: true, value: { [SymbolSpecies]: RegExpLikeForStringSplitting } }, + dotAll: { __proto__: null, configurable: true, value: RegExpPrototypeGetDotAll(pattern) }, + exec: { __proto__: null, configurable: true, value: OriginalRegExpPrototypeExec }, + global: { __proto__: null, configurable: true, value: RegExpPrototypeGetGlobal(pattern) }, + hasIndices: { __proto__: null, configurable: true, value: RegExpPrototypeGetHasIndices(pattern) }, + ignoreCase: { __proto__: null, configurable: true, value: RegExpPrototypeGetIgnoreCase(pattern) }, + multiline: { __proto__: null, configurable: true, value: RegExpPrototypeGetMultiline(pattern) }, + source: { __proto__: null, configurable: true, value: RegExpPrototypeGetSource(pattern) }, + sticky: { __proto__: null, configurable: true, value: RegExpPrototypeGetSticky(pattern) }, + unicode: { __proto__: null, configurable: true, value: RegExpPrototypeGetUnicode(pattern) }, + }); + ObjectDefineProperty(pattern, "flags", { + __proto__: null, + configurable: true, + value: RegExpPrototypeGetFlags(pattern), + }); + return pattern; +}; + +primordials.SafeStringPrototypeSearch = (str, regexp) => { + regexp.lastIndex = 0; + const match = RegExpPrototypeExec(regexp, str); + return match ? match.index : -1; +}; + +// Chunked push.apply so arbitrarily large arrays don't exhaust the stack. +primordials.SafeArrayPrototypePushApply = (array, items) => { + const { length } = items; + let end = 0x10000; + if (end < length) { + let start = 0; + do { + ArrayPrototypePushApply(array, ArrayPrototypeSlice(items, start, (start = end))); + end += 0x10000; + } while (end < length); + items = ArrayPrototypeSlice(items, start); + } + return ArrayPrototypePushApply(array, items); +}; + +ObjectSetPrototypeOf(primordials, null); +ObjectFreeze(primordials); diff --git a/src/codegen/primordials-module-prologue.js b/src/codegen/primordials-module-prologue.js new file mode 100644 index 000000000000..7e972ac73039 --- /dev/null +++ b/src/codegen/primordials-module-prologue.js @@ -0,0 +1,21 @@ +// GENERATED FILE — do not edit. See src/codegen/generate-primordials.ts. +// +// Node.js's `primordials` object, for modules ported from Node's lib/: the same +// member names and call semantics as lib/internal/per_context/primordials.js +// (uncurried prototype methods, XGetY/XSetY accessors, *Apply variants for +// varargs methods, Safe* classes, hardenRegExp, promise helpers). Everything is +// built from JSC's link-time constants ($Name), which the engine captures before +// user code can run, so nothing here reads a global at load time. Spec constants +// (constructor lengths, Math/Number constants, BYTES_PER_ELEMENT, ...) are inlined +// as literals instead of read at runtime. +// +// This object exists for Node compatibility; Bun's own modules should use the +// $Name constants and intrinsics directly rather than going through it. + +// (thisArg, ...args) => func.call(thisArg, ...args) without touching +// Function.prototype: bind and call are both pristine link-time constants. +const uncurryThis = $FunctionPrototypeBind.$call($FunctionPrototypeBind, $FunctionPrototypeCall); + +// applyBind(func) => (thisArg, args) => func.apply(thisArg, args); +// applyBind(func, receiver) binds the receiver as `this` (static methods). +const applyBind = $FunctionPrototypeBind.$call($FunctionPrototypeBind, $FunctionPrototypeApply); diff --git a/src/js/internal-for-testing.ts b/src/js/internal-for-testing.ts index 39663d1026fb..e3c45ce1390e 100644 --- a/src/js/internal-for-testing.ts +++ b/src/js/internal-for-testing.ts @@ -225,21 +225,86 @@ export const isolatedModuleCacheSourceType: (specifier: string) => string | null ); export const Dequeue = require("internal/fifo"); +// Link-time-constant primordials probe; one entry per holder kind in JSCPrimordials.h. +export const primordials = { + run(arrayLike: unknown[], string: string, mapLike: Map, u8: Uint8Array, regexp: RegExp) { + return { + ArrayPrototypePush: $ArrayPrototypePush.$call(arrayLike, 1, 2), + ArrayPrototypeSlice: $ArrayPrototypeSlice.$call(arrayLike, 0), + ArrayPrototypeSymbolIterator: $ArrayPrototypeSymbolIterator.$call(arrayLike).next().value, + StringPrototypeSlice: $StringPrototypeSlice.$call(string, 1, 3), + StringPrototypeSplit: $StringPrototypeSplit.$call(string, ""), + ObjectKeys: $ObjectKeys({ a: 1, b: 2 }), + ObjectDefineProperty: $ObjectDefineProperty({}, "x", { value: 42 }).x, + FunctionPrototypeBind: $FunctionPrototypeBind.$call(function (this: number, y: number) { + return this + y; + }, 5)(3), + RegExpPrototypeTest: $RegExpPrototypeTest.$call(regexp, string), + RegExpPrototypeGetSource: $RegExpPrototypeGetSource.$call(regexp), + MapPrototypeGet: $MapPrototypeGet.$call(mapLike, "k"), + MapPrototypeGetSize: $MapPrototypeGetSize.$call(mapLike), + DateNow: typeof $DateNow(), + NumberIsInteger: $NumberIsInteger(3), + MathMax: $MathMax(1, 5, 3), + ReflectOwnKeys: $ReflectOwnKeys({ a: 1 }), + JSONStringify: $JSONStringify({ a: 1 }), + TypedArrayPrototypeGetLength: $TypedArrayPrototypeGetLength.$call(u8), + TypedArrayPrototypeSubarray: $TypedArrayPrototypeGetLength.$call($TypedArrayPrototypeSubarray.$call(u8, 1, 3)), + DataViewPrototypeGetByteLength: $DataViewPrototypeGetByteLength.$call( + new DataView($TypedArrayPrototypeGetBuffer.$call(u8)), + ), + PromiseResolve: $PromiseResolve.$call($Promise, 1) instanceof $Promise, + }; + }, + // Materializes every primordial and returns one { name, holder, kind, key, value, available } + // row per JSCPrimordialsTable.h entry, straight from JSC. + audit: $newCppFunction("PrimordialsAudit.cpp", "Bun__primordialsAudit", 0) as () => Array<{ + name: string; + holder: string; + kind: "Method" | "Getter" | "Setter" | "Value" | "Self"; + key: string | symbol | null; + value: unknown; + available: boolean; + }>, + // Node's primordials object as internal modules see it (like Node's + // internal/test/binding.primordials); user code has no other way to reach it. + get object() { + return require("internal/primordials"); + }, +}; + // Userland access to node-internal modules for vendored node tests that // declare `// Flags: --expose-internals` (served via the require interceptor // in test/js/node/test/common/index.js). Static requires only — the builtin // bundler cannot rewrite variable-path requires. Extend the map as more -// vendored tests need more internals. +// vendored tests need more internals. Values are lazy so merely requiring +// bun:internal-for-testing does not evaluate the whole internal-module graph. export const exposedInternals = { - "internal/streams/add-abort-signal": require("internal/streams/add-abort-signal"), - "internal/async_context_frame": require("internal/async_context_frame"), - "internal/async_hooks": require("internal/async_hooks"), - "internal/webstreams/adapters": require("internal/webstreams_adapters"), - "internal/dgram": require("internal/dgram"), + get "internal/streams/add-abort-signal"() { + return require("internal/streams/add-abort-signal"); + }, + get "internal/async_context_frame"() { + return require("internal/async_context_frame"); + }, + get "internal/async_hooks"() { + return require("internal/async_hooks"); + }, + get "internal/webstreams/adapters"() { + return require("internal/webstreams_adapters"); + }, + get "internal/dgram"() { + return require("internal/dgram"); + }, // Node's internal/fixed_queue module IS the FixedQueue class. - "internal/fixed_queue": require("internal/fixed_queue").FixedQueue, - "internal/freelist": require("internal/freelist"), - "internal/validators": require("internal/validators"), + get "internal/fixed_queue"() { + return require("internal/fixed_queue").FixedQueue; + }, + get "internal/freelist"() { + return require("internal/freelist"); + }, + get "internal/validators"() { + return require("internal/validators"); + }, "internal/fs/utils": { // Both are the REAL parsers the fs entry points use (FileSystemFlags::from_js // and args::Rm::from_js), not JS reimplementations -- vendored tests assert diff --git a/src/js/internal/primordials.js b/src/js/internal/primordials.js index 014a88b625b2..e83fc0508e20 100644 --- a/src/js/internal/primordials.js +++ b/src/js/internal/primordials.js @@ -1,19 +1,1217 @@ -// TODO: Use native code and JSC intrinsics for everything in this file. -// Do not use this file for new code, many things here will be slow especailly when intrinsics for these operations is available. -// It is primarily used for `internal/util` +// GENERATED FILE — do not edit. See src/codegen/generate-primordials.ts. +// +// Node.js's `primordials` object, for modules ported from Node's lib/: the same +// member names and call semantics as lib/internal/per_context/primordials.js +// (uncurried prototype methods, XGetY/XSetY accessors, *Apply variants for +// varargs methods, Safe* classes, hardenRegExp, promise helpers). Everything is +// built from JSC's link-time constants ($Name), which the engine captures before +// user code can run, so nothing here reads a global at load time. Spec constants +// (constructor lengths, Math/Number constants, BYTES_PER_ELEMENT, ...) are inlined +// as literals instead of read at runtime. +// +// This object exists for Node compatibility; Bun's own modules should use the +// $Name constants and intrinsics directly rather than going through it. -const ObjectSetPrototypeOf = Object.setPrototypeOf; -const ObjectFreeze = Object.freeze; +// (thisArg, ...args) => func.call(thisArg, ...args) without touching +// Function.prototype: bind and call are both pristine link-time constants. +const uncurryThis = $FunctionPrototypeBind.$call($FunctionPrototypeBind, $FunctionPrototypeCall); -const createSafeIterator = (factory, next_) => { +// applyBind(func) => (thisArg, args) => func.apply(thisArg, args); +// applyBind(func, receiver) binds the receiver as `this` (static methods). +const applyBind = $FunctionPrototypeBind.$call($FunctionPrototypeBind, $FunctionPrototypeApply); + +const primordials = { + __proto__: null, + Proxy: $Proxy, + globalThis: $globalThis, + decodeURI: $decodeURI, + decodeURIComponent: $decodeURIComponent, + encodeURI: $encodeURI, + encodeURIComponent: $encodeURIComponent, + escape: $escape, + eval: $eval, + unescape: $unescape, + AtomicsAdd: $AtomicsAdd, + AtomicsAnd: $AtomicsAnd, + AtomicsCompareExchange: $AtomicsCompareExchange, + AtomicsExchange: $AtomicsExchange, + AtomicsIsLockFree: $AtomicsIsLockFree, + AtomicsLoad: $AtomicsLoad, + AtomicsNotify: $AtomicsNotify, + AtomicsOr: $AtomicsOr, + AtomicsStore: $AtomicsStore, + AtomicsSub: $AtomicsSub, + AtomicsWait: $AtomicsWait, + AtomicsXor: $AtomicsXor, + AtomicsPause: $AtomicsPause, + AtomicsWaitAsync: $AtomicsWaitAsync, + AtomicsSymbolToStringTag: "Atomics", + JSONParse: $JSONParse, + JSONStringify: $JSONStringify, + JSONIsRawJSON: $JSONIsRawJSON, + JSONRawJSON: $JSONRawJSON, + JSONSymbolToStringTag: "JSON", + MathE: 2.718281828459045, + MathLN2: 0.6931471805599453, + MathLN10: 2.302585092994046, + MathLOG2E: 1.4426950408889634, + MathLOG10E: 0.4342944819032518, + MathPI: 3.141592653589793, + MathSQRT1_2: 0.7071067811865476, + MathSQRT2: 1.4142135623730951, + MathAbs: $MathAbs, + MathAcos: $MathAcos, + MathAsin: $MathAsin, + MathAtan: $MathAtan, + MathAcosh: $MathAcosh, + MathAsinh: $MathAsinh, + MathAtanh: $MathAtanh, + MathAtan2: $MathAtan2, + MathCbrt: $MathCbrt, + MathCeil: $MathCeil, + MathClz32: $MathClz32, + MathCos: $MathCos, + MathCosh: $MathCosh, + MathExp: $MathExp, + MathExpm1: $MathExpm1, + MathFloor: $MathFloor, + MathFround: $MathFround, + MathHypot: $MathHypot, + MathHypotApply: applyBind($MathHypot, undefined), + MathLog: $MathLog, + MathLog10: $MathLog10, + MathLog1p: $MathLog1p, + MathLog2: $MathLog2, + MathMax: $MathMax, + MathMaxApply: applyBind($MathMax, undefined), + MathMin: $MathMin, + MathMinApply: applyBind($MathMin, undefined), + MathPow: $MathPow, + MathRandom: $MathRandom, + MathRound: $MathRound, + MathSign: $MathSign, + MathSin: $MathSin, + MathSinh: $MathSinh, + MathSqrt: $MathSqrt, + MathTan: $MathTan, + MathTanh: $MathTanh, + MathTrunc: $MathTrunc, + MathImul: $MathImul, + MathF16round: $MathF16round, + MathSumPrecise: $MathSumPrecise, + MathSymbolToStringTag: "Math", + ReflectApply: $ReflectApply, + ReflectConstruct: $ReflectConstruct, + ReflectDefineProperty: $ReflectDefineProperty, + ReflectDeleteProperty: $ReflectDeleteProperty, + ReflectGet: $ReflectGet, + ReflectGetOwnPropertyDescriptor: $ReflectGetOwnPropertyDescriptor, + ReflectGetPrototypeOf: $ReflectGetPrototypeOf, + ReflectHas: $ReflectHas, + ReflectIsExtensible: $ReflectIsExtensible, + ReflectOwnKeys: $ReflectOwnKeys, + ReflectPreventExtensions: $ReflectPreventExtensions, + ReflectSet: $ReflectSet, + ReflectSetPrototypeOf: $ReflectSetPrototypeOf, + ReflectSymbolToStringTag: "Reflect", + ProxyLength: 2, + ProxyName: "Proxy", + ProxyRevocable: $ProxyRevocable, + AggregateError: $AggregateError, + AggregateErrorLength: 2, + AggregateErrorName: "AggregateError", + AggregateErrorPrototype: $AggregateErrorPrototype, + AggregateErrorPrototypeName: "AggregateError", + AggregateErrorPrototypeMessage: "", + AggregateErrorPrototypeConstructor: uncurryThis($AggregateErrorPrototypeConstructor), + Array: $Array, + ArrayFrom: $ArrayFrom, + ArrayLength: 1, + ArrayName: "Array", + ArrayPrototype: $ArrayPrototype, + ArrayOf: $ArrayOf, + ArrayOfApply: applyBind($ArrayOf, $Array), + ArrayIsArray: $ArrayIsArray, + ArrayFromAsync: $ArrayFromAsync, + ArrayGetSymbolSpecies: uncurryThis($ArrayGetSymbolSpecies), + ArrayPrototypeLength: 0, + ArrayPrototypeToString: uncurryThis($ArrayPrototypeToString), + ArrayPrototypeValues: uncurryThis($ArrayPrototypeValues), + ArrayPrototypeToLocaleString: uncurryThis($ArrayPrototypeToLocaleString), + ArrayPrototypeConcat: uncurryThis($ArrayPrototypeConcat), + ArrayPrototypeFill: uncurryThis($ArrayPrototypeFill), + ArrayPrototypeJoin: uncurryThis($ArrayPrototypeJoin), + ArrayPrototypePop: uncurryThis($ArrayPrototypePop), + ArrayPrototypePush: uncurryThis($ArrayPrototypePush), + ArrayPrototypePushApply: applyBind($ArrayPrototypePush), + ArrayPrototypeReverse: uncurryThis($ArrayPrototypeReverse), + ArrayPrototypeShift: uncurryThis($ArrayPrototypeShift), + ArrayPrototypeSlice: uncurryThis($ArrayPrototypeSlice), + ArrayPrototypeSort: uncurryThis($ArrayPrototypeSort), + ArrayPrototypeSplice: uncurryThis($ArrayPrototypeSplice), + ArrayPrototypeUnshift: uncurryThis($ArrayPrototypeUnshift), + ArrayPrototypeUnshiftApply: applyBind($ArrayPrototypeUnshift), + ArrayPrototypeEvery: uncurryThis($ArrayPrototypeEvery), + ArrayPrototypeForEach: uncurryThis($ArrayPrototypeForEach), + ArrayPrototypeSome: uncurryThis($ArrayPrototypeSome), + ArrayPrototypeIndexOf: uncurryThis($ArrayPrototypeIndexOf), + ArrayPrototypeLastIndexOf: uncurryThis($ArrayPrototypeLastIndexOf), + ArrayPrototypeFilter: uncurryThis($ArrayPrototypeFilter), + ArrayPrototypeFlat: uncurryThis($ArrayPrototypeFlat), + ArrayPrototypeFlatMap: uncurryThis($ArrayPrototypeFlatMap), + ArrayPrototypeReduce: uncurryThis($ArrayPrototypeReduce), + ArrayPrototypeReduceRight: uncurryThis($ArrayPrototypeReduceRight), + ArrayPrototypeMap: uncurryThis($ArrayPrototypeMap), + ArrayPrototypeKeys: uncurryThis($ArrayPrototypeKeys), + ArrayPrototypeEntries: uncurryThis($ArrayPrototypeEntries), + ArrayPrototypeFind: uncurryThis($ArrayPrototypeFind), + ArrayPrototypeFindLast: uncurryThis($ArrayPrototypeFindLast), + ArrayPrototypeFindIndex: uncurryThis($ArrayPrototypeFindIndex), + ArrayPrototypeFindLastIndex: uncurryThis($ArrayPrototypeFindLastIndex), + ArrayPrototypeIncludes: uncurryThis($ArrayPrototypeIncludes), + ArrayPrototypeCopyWithin: uncurryThis($ArrayPrototypeCopyWithin), + ArrayPrototypeAt: uncurryThis($ArrayPrototypeAt), + ArrayPrototypeToReversed: uncurryThis($ArrayPrototypeToReversed), + ArrayPrototypeToSorted: uncurryThis($ArrayPrototypeToSorted), + ArrayPrototypeToSpliced: uncurryThis($ArrayPrototypeToSpliced), + ArrayPrototypeWith: uncurryThis($ArrayPrototypeWith), + ArrayPrototypeConstructor: uncurryThis($ArrayPrototypeConstructor), + ArrayPrototypeSymbolIterator: uncurryThis($ArrayPrototypeSymbolIterator), + ArrayPrototypeSymbolUnscopables: $ArrayPrototypeSymbolUnscopables, + ArrayBuffer: $ArrayBufferPrimordial, + ArrayBufferLength: 1, + ArrayBufferName: "ArrayBuffer", + ArrayBufferPrototype: $ArrayBufferPrototype, + ArrayBufferIsView: $ArrayBufferIsView, + ArrayBufferGetSymbolSpecies: uncurryThis($ArrayBufferGetSymbolSpecies), + ArrayBufferPrototypeSlice: uncurryThis($ArrayBufferPrototypeSlice), + ArrayBufferPrototypeGetByteLength: uncurryThis($ArrayBufferPrototypeGetByteLength), + ArrayBufferPrototypeResize: uncurryThis($ArrayBufferPrototypeResize), + ArrayBufferPrototypeTransfer: uncurryThis($ArrayBufferPrototypeTransfer), + ArrayBufferPrototypeTransferToFixedLength: uncurryThis($ArrayBufferPrototypeTransferToFixedLength), + ArrayBufferPrototypeGetResizable: uncurryThis($ArrayBufferPrototypeGetResizable), + ArrayBufferPrototypeGetMaxByteLength: uncurryThis($ArrayBufferPrototypeGetMaxByteLength), + ArrayBufferPrototypeGetDetached: uncurryThis($ArrayBufferPrototypeGetDetached), + ArrayBufferPrototypeConstructor: uncurryThis($ArrayBufferPrototypeConstructor), + ArrayBufferPrototypeSymbolToStringTag: "ArrayBuffer", + BigInt: $BigInt, + BigIntAsUintN: $BigIntAsUintN, + BigIntAsIntN: $BigIntAsIntN, + BigIntLength: 1, + BigIntName: "BigInt", + BigIntPrototype: $BigIntPrototype, + BigIntPrototypeToString: uncurryThis($BigIntPrototypeToString), + BigIntPrototypeToLocaleString: uncurryThis($BigIntPrototypeToLocaleString), + BigIntPrototypeValueOf: uncurryThis($BigIntPrototypeValueOf), + BigIntPrototypeConstructor: uncurryThis($BigIntPrototypeConstructor), + BigIntPrototypeSymbolToStringTag: "BigInt", + BigInt64Array: $BigInt64Array, + BigInt64ArrayLength: 3, + BigInt64ArrayName: "BigInt64Array", + BigInt64ArrayPrototype: $BigInt64ArrayPrototype, + BigInt64ArrayBYTES_PER_ELEMENT: 8, + BigInt64ArrayPrototypeBYTES_PER_ELEMENT: 8, + BigInt64ArrayPrototypeConstructor: uncurryThis($BigInt64ArrayPrototypeConstructor), + BigUint64Array: $BigUint64Array, + BigUint64ArrayLength: 3, + BigUint64ArrayName: "BigUint64Array", + BigUint64ArrayPrototype: $BigUint64ArrayPrototype, + BigUint64ArrayBYTES_PER_ELEMENT: 8, + BigUint64ArrayPrototypeBYTES_PER_ELEMENT: 8, + BigUint64ArrayPrototypeConstructor: uncurryThis($BigUint64ArrayPrototypeConstructor), + Boolean: $Boolean, + BooleanLength: 1, + BooleanName: "Boolean", + BooleanPrototype: $BooleanPrototype, + BooleanPrototypeToString: uncurryThis($BooleanPrototypeToString), + BooleanPrototypeValueOf: uncurryThis($BooleanPrototypeValueOf), + BooleanPrototypeConstructor: uncurryThis($BooleanPrototypeConstructor), + DataView: $DataView, + DataViewLength: 1, + DataViewName: "DataView", + DataViewPrototype: $DataViewPrototype, + DataViewBYTES_PER_ELEMENT: 1, + DataViewPrototypeGetInt8: uncurryThis($DataViewPrototypeGetInt8), + DataViewPrototypeGetUint8: uncurryThis($DataViewPrototypeGetUint8), + DataViewPrototypeGetInt16: uncurryThis($DataViewPrototypeGetInt16), + DataViewPrototypeGetUint16: uncurryThis($DataViewPrototypeGetUint16), + DataViewPrototypeGetInt32: uncurryThis($DataViewPrototypeGetInt32), + DataViewPrototypeGetUint32: uncurryThis($DataViewPrototypeGetUint32), + DataViewPrototypeGetFloat16: uncurryThis($DataViewPrototypeGetFloat16), + DataViewPrototypeGetFloat32: uncurryThis($DataViewPrototypeGetFloat32), + DataViewPrototypeGetFloat64: uncurryThis($DataViewPrototypeGetFloat64), + DataViewPrototypeGetBigInt64: uncurryThis($DataViewPrototypeGetBigInt64), + DataViewPrototypeGetBigUint64: uncurryThis($DataViewPrototypeGetBigUint64), + DataViewPrototypeSetInt8: uncurryThis($DataViewPrototypeSetInt8), + DataViewPrototypeSetUint8: uncurryThis($DataViewPrototypeSetUint8), + DataViewPrototypeSetInt16: uncurryThis($DataViewPrototypeSetInt16), + DataViewPrototypeSetUint16: uncurryThis($DataViewPrototypeSetUint16), + DataViewPrototypeSetInt32: uncurryThis($DataViewPrototypeSetInt32), + DataViewPrototypeSetUint32: uncurryThis($DataViewPrototypeSetUint32), + DataViewPrototypeSetFloat16: uncurryThis($DataViewPrototypeSetFloat16), + DataViewPrototypeSetFloat32: uncurryThis($DataViewPrototypeSetFloat32), + DataViewPrototypeSetFloat64: uncurryThis($DataViewPrototypeSetFloat64), + DataViewPrototypeSetBigInt64: uncurryThis($DataViewPrototypeSetBigInt64), + DataViewPrototypeSetBigUint64: uncurryThis($DataViewPrototypeSetBigUint64), + DataViewPrototypeGetBuffer: uncurryThis($DataViewPrototypeGetBuffer), + DataViewPrototypeGetByteOffset: uncurryThis($DataViewPrototypeGetByteOffset), + DataViewPrototypeGetByteLength: uncurryThis($DataViewPrototypeGetByteLength), + DataViewPrototypeConstructor: uncurryThis($DataViewPrototypeConstructor), + DataViewPrototypeSymbolToStringTag: "DataView", + Date: $Date, + DateParse: $DateParse, + DateUTC: $DateUTC, + DateNow: $DateNow, + DateLength: 7, + DateName: "Date", + DatePrototype: $DatePrototype, + DatePrototypeToString: uncurryThis($DatePrototypeToString), + DatePrototypeToISOString: uncurryThis($DatePrototypeToISOString), + DatePrototypeToDateString: uncurryThis($DatePrototypeToDateString), + DatePrototypeToTimeString: uncurryThis($DatePrototypeToTimeString), + DatePrototypeToLocaleString: uncurryThis($DatePrototypeToLocaleString), + DatePrototypeToLocaleDateString: uncurryThis($DatePrototypeToLocaleDateString), + DatePrototypeToLocaleTimeString: uncurryThis($DatePrototypeToLocaleTimeString), + DatePrototypeValueOf: uncurryThis($DatePrototypeValueOf), + DatePrototypeGetTime: uncurryThis($DatePrototypeGetTime), + DatePrototypeGetFullYear: uncurryThis($DatePrototypeGetFullYear), + DatePrototypeGetUTCFullYear: uncurryThis($DatePrototypeGetUTCFullYear), + DatePrototypeGetMonth: uncurryThis($DatePrototypeGetMonth), + DatePrototypeGetUTCMonth: uncurryThis($DatePrototypeGetUTCMonth), + DatePrototypeGetDate: uncurryThis($DatePrototypeGetDate), + DatePrototypeGetUTCDate: uncurryThis($DatePrototypeGetUTCDate), + DatePrototypeGetDay: uncurryThis($DatePrototypeGetDay), + DatePrototypeGetUTCDay: uncurryThis($DatePrototypeGetUTCDay), + DatePrototypeGetHours: uncurryThis($DatePrototypeGetHours), + DatePrototypeGetUTCHours: uncurryThis($DatePrototypeGetUTCHours), + DatePrototypeGetMinutes: uncurryThis($DatePrototypeGetMinutes), + DatePrototypeGetUTCMinutes: uncurryThis($DatePrototypeGetUTCMinutes), + DatePrototypeGetSeconds: uncurryThis($DatePrototypeGetSeconds), + DatePrototypeGetUTCSeconds: uncurryThis($DatePrototypeGetUTCSeconds), + DatePrototypeGetMilliseconds: uncurryThis($DatePrototypeGetMilliseconds), + DatePrototypeGetUTCMilliseconds: uncurryThis($DatePrototypeGetUTCMilliseconds), + DatePrototypeGetTimezoneOffset: uncurryThis($DatePrototypeGetTimezoneOffset), + DatePrototypeGetYear: uncurryThis($DatePrototypeGetYear), + DatePrototypeSetTime: uncurryThis($DatePrototypeSetTime), + DatePrototypeSetMilliseconds: uncurryThis($DatePrototypeSetMilliseconds), + DatePrototypeSetUTCMilliseconds: uncurryThis($DatePrototypeSetUTCMilliseconds), + DatePrototypeSetSeconds: uncurryThis($DatePrototypeSetSeconds), + DatePrototypeSetUTCSeconds: uncurryThis($DatePrototypeSetUTCSeconds), + DatePrototypeSetMinutes: uncurryThis($DatePrototypeSetMinutes), + DatePrototypeSetUTCMinutes: uncurryThis($DatePrototypeSetUTCMinutes), + DatePrototypeSetHours: uncurryThis($DatePrototypeSetHours), + DatePrototypeSetUTCHours: uncurryThis($DatePrototypeSetUTCHours), + DatePrototypeSetDate: uncurryThis($DatePrototypeSetDate), + DatePrototypeSetUTCDate: uncurryThis($DatePrototypeSetUTCDate), + DatePrototypeSetMonth: uncurryThis($DatePrototypeSetMonth), + DatePrototypeSetUTCMonth: uncurryThis($DatePrototypeSetUTCMonth), + DatePrototypeSetFullYear: uncurryThis($DatePrototypeSetFullYear), + DatePrototypeSetUTCFullYear: uncurryThis($DatePrototypeSetUTCFullYear), + DatePrototypeSetYear: uncurryThis($DatePrototypeSetYear), + DatePrototypeToJSON: uncurryThis($DatePrototypeToJSON), + DatePrototypeToUTCString: uncurryThis($DatePrototypeToUTCString), + DatePrototypeToGMTString: uncurryThis($DatePrototypeToGMTString), + DatePrototypeConstructor: uncurryThis($DatePrototypeConstructor), + DatePrototypeSymbolToPrimitive: uncurryThis($DatePrototypeSymbolToPrimitive), + Error: $Error, + ErrorLength: 1, + ErrorName: "Error", + ErrorPrototype: $ErrorPrototype, + ErrorStackTraceLimit: 10, + ErrorCaptureStackTrace: $ErrorCaptureStackTrace, + ErrorIsError: $ErrorIsError, + ErrorAppendStackTrace: $ErrorAppendStackTrace, + ErrorPrepareStackTrace: $ErrorPrepareStackTrace, + ErrorPrototypeToString: uncurryThis($ErrorPrototypeToString), + ErrorPrototypeName: "Error", + ErrorPrototypeMessage: "", + ErrorPrototypeConstructor: uncurryThis($ErrorPrototypeConstructor), + EvalError: $EvalError, + EvalErrorLength: 1, + EvalErrorName: "EvalError", + EvalErrorPrototype: $EvalErrorPrototype, + EvalErrorPrototypeName: "EvalError", + EvalErrorPrototypeMessage: "", + EvalErrorPrototypeConstructor: uncurryThis($EvalErrorPrototypeConstructor), + FinalizationRegistry: $FinalizationRegistry, + FinalizationRegistryLength: 1, + FinalizationRegistryName: "FinalizationRegistry", + FinalizationRegistryPrototype: $FinalizationRegistryPrototype, + FinalizationRegistryPrototypeRegister: uncurryThis($FinalizationRegistryPrototypeRegister), + FinalizationRegistryPrototypeUnregister: uncurryThis($FinalizationRegistryPrototypeUnregister), + FinalizationRegistryPrototypeConstructor: uncurryThis($FinalizationRegistryPrototypeConstructor), + FinalizationRegistryPrototypeSymbolToStringTag: "FinalizationRegistry", + Float16Array: $Float16Array, + Float16ArrayLength: 3, + Float16ArrayName: "Float16Array", + Float16ArrayPrototype: $Float16ArrayPrototype, + Float16ArrayBYTES_PER_ELEMENT: 2, + Float16ArrayPrototypeBYTES_PER_ELEMENT: 2, + Float16ArrayPrototypeConstructor: uncurryThis($Float16ArrayPrototypeConstructor), + Float32Array: $Float32Array, + Float32ArrayLength: 3, + Float32ArrayName: "Float32Array", + Float32ArrayPrototype: $Float32ArrayPrototype, + Float32ArrayBYTES_PER_ELEMENT: 4, + Float32ArrayPrototypeBYTES_PER_ELEMENT: 4, + Float32ArrayPrototypeConstructor: uncurryThis($Float32ArrayPrototypeConstructor), + Float64Array: $Float64Array, + Float64ArrayLength: 3, + Float64ArrayName: "Float64Array", + Float64ArrayPrototype: $Float64ArrayPrototype, + Float64ArrayBYTES_PER_ELEMENT: 8, + Float64ArrayPrototypeBYTES_PER_ELEMENT: 8, + Float64ArrayPrototypeConstructor: uncurryThis($Float64ArrayPrototypeConstructor), + Function: $Function, + FunctionLength: 1, + FunctionName: "Function", + FunctionPrototype: $FunctionPrototype, + FunctionPrototypeLength: 0, + FunctionPrototypeName: "", + FunctionPrototypeToString: uncurryThis($FunctionPrototypeToString), + FunctionPrototypeApply: uncurryThis($FunctionPrototypeApply), + FunctionPrototypeCall: uncurryThis($FunctionPrototypeCall), + FunctionPrototypeBind: uncurryThis($FunctionPrototypeBind), + FunctionPrototypeGetArguments: uncurryThis($FunctionPrototypeGetArguments), + FunctionPrototypeSetArguments: uncurryThis($FunctionPrototypeSetArguments), + FunctionPrototypeGetCaller: uncurryThis($FunctionPrototypeGetCaller), + FunctionPrototypeSetCaller: uncurryThis($FunctionPrototypeSetCaller), + FunctionPrototypeConstructor: uncurryThis($FunctionPrototypeConstructor), + FunctionPrototypeSymbolHasInstance: uncurryThis($FunctionPrototypeSymbolHasInstance), + Int16Array: $Int16Array, + Int16ArrayLength: 3, + Int16ArrayName: "Int16Array", + Int16ArrayPrototype: $Int16ArrayPrototype, + Int16ArrayBYTES_PER_ELEMENT: 2, + Int16ArrayPrototypeBYTES_PER_ELEMENT: 2, + Int16ArrayPrototypeConstructor: uncurryThis($Int16ArrayPrototypeConstructor), + Int32Array: $Int32Array, + Int32ArrayLength: 3, + Int32ArrayName: "Int32Array", + Int32ArrayPrototype: $Int32ArrayPrototype, + Int32ArrayBYTES_PER_ELEMENT: 4, + Int32ArrayPrototypeBYTES_PER_ELEMENT: 4, + Int32ArrayPrototypeConstructor: uncurryThis($Int32ArrayPrototypeConstructor), + Int8Array: $Int8Array, + Int8ArrayLength: 3, + Int8ArrayName: "Int8Array", + Int8ArrayPrototype: $Int8ArrayPrototype, + Int8ArrayBYTES_PER_ELEMENT: 1, + Int8ArrayPrototypeBYTES_PER_ELEMENT: 1, + Int8ArrayPrototypeConstructor: uncurryThis($Int8ArrayPrototypeConstructor), + Iterator: $Iterator, + IteratorLength: 0, + IteratorName: "Iterator", + IteratorPrototype: $IteratorPrototype, + IteratorFrom: $IteratorFrom, + IteratorConcat: $IteratorConcat, + IteratorPrototypeGetConstructor: uncurryThis($IteratorPrototypeGetConstructor), + IteratorPrototypeSetConstructor: uncurryThis($IteratorPrototypeSetConstructor), + IteratorPrototypeToArray: uncurryThis($IteratorPrototypeToArray), + IteratorPrototypeForEach: uncurryThis($IteratorPrototypeForEach), + IteratorPrototypeSome: uncurryThis($IteratorPrototypeSome), + IteratorPrototypeEvery: uncurryThis($IteratorPrototypeEvery), + IteratorPrototypeFind: uncurryThis($IteratorPrototypeFind), + IteratorPrototypeReduce: uncurryThis($IteratorPrototypeReduce), + IteratorPrototypeMap: uncurryThis($IteratorPrototypeMap), + IteratorPrototypeFilter: uncurryThis($IteratorPrototypeFilter), + IteratorPrototypeTake: uncurryThis($IteratorPrototypeTake), + IteratorPrototypeDrop: uncurryThis($IteratorPrototypeDrop), + IteratorPrototypeFlatMap: uncurryThis($IteratorPrototypeFlatMap), + IteratorPrototypeIncludes: uncurryThis($IteratorPrototypeIncludes), + IteratorPrototypeSymbolIterator: uncurryThis($IteratorPrototypeSymbolIterator), + IteratorPrototypeGetSymbolToStringTag: uncurryThis($IteratorPrototypeGetSymbolToStringTag), + IteratorPrototypeSetSymbolToStringTag: uncurryThis($IteratorPrototypeSetSymbolToStringTag), + IteratorPrototypeSymbolDispose: uncurryThis($IteratorPrototypeSymbolDispose), + Map: $Map, + MapLength: 0, + MapName: "Map", + MapPrototype: $MapPrototype, + MapGroupBy: $MapGroupBy, + MapGetSymbolSpecies: uncurryThis($MapGetSymbolSpecies), + MapPrototypeClear: uncurryThis($MapPrototypeClear), + MapPrototypeDelete: uncurryThis($MapPrototypeDelete), + MapPrototypeEntries: uncurryThis($MapPrototypeEntries), + MapPrototypeForEach: uncurryThis($MapPrototypeForEach), + MapPrototypeGet: uncurryThis($MapPrototypeGet), + MapPrototypeHas: uncurryThis($MapPrototypeHas), + MapPrototypeKeys: uncurryThis($MapPrototypeKeys), + MapPrototypeSet: uncurryThis($MapPrototypeSet), + MapPrototypeGetOrInsert: uncurryThis($MapPrototypeGetOrInsert), + MapPrototypeGetOrInsertComputed: uncurryThis($MapPrototypeGetOrInsertComputed), + MapPrototypeGetSize: uncurryThis($MapPrototypeGetSize), + MapPrototypeValues: uncurryThis($MapPrototypeValues), + MapPrototypeConstructor: uncurryThis($MapPrototypeConstructor), + MapPrototypeSymbolIterator: uncurryThis($MapPrototypeSymbolIterator), + MapPrototypeSymbolToStringTag: "Map", + Number: $NumberPrimordial, + NumberLength: 1, + NumberName: "Number", + NumberIsFinite: $NumberIsFinite, + NumberIsNaN: $NumberIsNaN, + NumberIsSafeInteger: $NumberIsSafeInteger, + NumberPrototype: $NumberPrototype, + NumberEPSILON: 2.220446049250313e-16, + NumberMAX_VALUE: 1.7976931348623157e308, + NumberMIN_VALUE: 5e-324, + NumberMAX_SAFE_INTEGER: 9007199254740991, + NumberMIN_SAFE_INTEGER: -9007199254740991, + NumberNEGATIVE_INFINITY: -Infinity, + NumberPOSITIVE_INFINITY: Infinity, + NumberNaN: NaN, + NumberParseInt: $NumberParseInt, + NumberParseFloat: $NumberParseFloat, + NumberIsInteger: $NumberIsInteger, + NumberPrototypeToLocaleString: uncurryThis($NumberPrototypeToLocaleString), + NumberPrototypeValueOf: uncurryThis($NumberPrototypeValueOf), + NumberPrototypeToFixed: uncurryThis($NumberPrototypeToFixed), + NumberPrototypeToExponential: uncurryThis($NumberPrototypeToExponential), + NumberPrototypeToPrecision: uncurryThis($NumberPrototypeToPrecision), + NumberPrototypeToString: uncurryThis($NumberPrototypeToString), + NumberPrototypeConstructor: uncurryThis($NumberPrototypeConstructor), + Object: $Object, + ObjectGetPrototypeOf: $ObjectGetPrototypeOf, + ObjectSetPrototypeOf: $ObjectSetPrototypeOf, + ObjectGetOwnPropertyDescriptor: $ObjectGetOwnPropertyDescriptor, + ObjectGetOwnPropertyDescriptors: $ObjectGetOwnPropertyDescriptors, + ObjectGetOwnPropertyNames: $ObjectGetOwnPropertyNames, + ObjectGetOwnPropertySymbols: $ObjectGetOwnPropertySymbols, + ObjectKeys: $ObjectKeys, + ObjectDefineProperty: $ObjectDefineProperty, + ObjectDefineProperties: $ObjectDefineProperties, + ObjectCreate: $ObjectCreate, + ObjectSeal: $ObjectSeal, + ObjectFreeze: $ObjectFreeze, + ObjectPreventExtensions: $ObjectPreventExtensions, + ObjectIsSealed: $ObjectIsSealed, + ObjectIsFrozen: $ObjectIsFrozen, + ObjectIsExtensible: $ObjectIsExtensible, + ObjectIs: $ObjectIs, + ObjectAssign: $ObjectAssign, + ObjectValues: $ObjectValues, + ObjectEntries: $ObjectEntries, + ObjectFromEntries: $ObjectFromEntries, + ObjectLength: 1, + ObjectName: "Object", + ObjectPrototype: $ObjectPrototype, + ObjectHasOwn: $ObjectHasOwn, + ObjectGroupBy: $ObjectGroupBy, + ObjectPrototypeToString: uncurryThis($ObjectPrototypeToString), + ObjectPrototypeToLocaleString: uncurryThis($ObjectPrototypeToLocaleString), + ObjectPrototypeValueOf: uncurryThis($ObjectPrototypeValueOf), + ObjectPrototypeHasOwnProperty: uncurryThis($ObjectPrototypeHasOwnProperty), + ObjectPrototypePropertyIsEnumerable: uncurryThis($ObjectPrototypePropertyIsEnumerable), + ObjectPrototypeIsPrototypeOf: uncurryThis($ObjectPrototypeIsPrototypeOf), + ObjectPrototype__defineGetter__: uncurryThis($ObjectPrototype__defineGetter__), + ObjectPrototype__defineSetter__: uncurryThis($ObjectPrototype__defineSetter__), + ObjectPrototype__lookupGetter__: uncurryThis($ObjectPrototype__lookupGetter__), + ObjectPrototype__lookupSetter__: uncurryThis($ObjectPrototype__lookupSetter__), + ObjectPrototypeGet__proto__: uncurryThis($ObjectPrototypeGet__proto__), + ObjectPrototypeSet__proto__: uncurryThis($ObjectPrototypeSet__proto__), + ObjectPrototypeConstructor: uncurryThis($ObjectPrototypeConstructor), + RangeError: $RangeError, + RangeErrorLength: 1, + RangeErrorName: "RangeError", + RangeErrorPrototype: $RangeErrorPrototype, + RangeErrorPrototypeName: "RangeError", + RangeErrorPrototypeMessage: "", + RangeErrorPrototypeConstructor: uncurryThis($RangeErrorPrototypeConstructor), + ReferenceError: $ReferenceError, + ReferenceErrorLength: 1, + ReferenceErrorName: "ReferenceError", + ReferenceErrorPrototype: $ReferenceErrorPrototype, + ReferenceErrorPrototypeName: "ReferenceError", + ReferenceErrorPrototypeMessage: "", + ReferenceErrorPrototypeConstructor: uncurryThis($ReferenceErrorPrototypeConstructor), + RegExp: $RegExp, + RegExpGetInput: uncurryThis($RegExpGetInput), + RegExpSetInput: uncurryThis($RegExpSetInput), + RegExpGet$_: uncurryThis($RegExpGetDollarUnderscore), + RegExpSet$_: uncurryThis($RegExpSetDollarUnderscore), + RegExpGetMultiline: uncurryThis($RegExpGetMultiline), + RegExpSetMultiline: uncurryThis($RegExpSetMultiline), + "RegExpGet$*": uncurryThis($RegExpGetDollarAsterisk), + "RegExpSet$*": uncurryThis($RegExpSetDollarAsterisk), + RegExpGetLastMatch: uncurryThis($RegExpGetLastMatch), + "RegExpGet$&": uncurryThis($RegExpGetDollarAmpersand), + RegExpGetLastParen: uncurryThis($RegExpGetLastParen), + "RegExpGet$+": uncurryThis($RegExpGetDollarPlus), + RegExpGetLeftContext: uncurryThis($RegExpGetLeftContext), + "RegExpGet$`": uncurryThis($RegExpGetDollarBacktick), + RegExpGetRightContext: uncurryThis($RegExpGetRightContext), + "RegExpGet$'": uncurryThis($RegExpGetDollarApostrophe), + RegExpGet$1: uncurryThis($RegExpGetDollar1), + RegExpGet$2: uncurryThis($RegExpGetDollar2), + RegExpGet$3: uncurryThis($RegExpGetDollar3), + RegExpGet$4: uncurryThis($RegExpGetDollar4), + RegExpGet$5: uncurryThis($RegExpGetDollar5), + RegExpGet$6: uncurryThis($RegExpGetDollar6), + RegExpGet$7: uncurryThis($RegExpGetDollar7), + RegExpGet$8: uncurryThis($RegExpGetDollar8), + RegExpGet$9: uncurryThis($RegExpGetDollar9), + RegExpLength: 2, + RegExpName: "RegExp", + RegExpPrototype: $RegExpPrototype, + RegExpEscape: $RegExpEscape, + RegExpGetSymbolSpecies: uncurryThis($RegExpGetSymbolSpecies), + RegExpPrototypeCompile: uncurryThis($RegExpPrototypeCompile), + RegExpPrototypeExec: uncurryThis($RegExpPrototypeExec), + RegExpPrototypeToString: uncurryThis($RegExpPrototypeToString), + RegExpPrototypeGetGlobal: uncurryThis($RegExpPrototypeGetGlobal), + RegExpPrototypeGetDotAll: uncurryThis($RegExpPrototypeGetDotAll), + RegExpPrototypeGetHasIndices: uncurryThis($RegExpPrototypeGetHasIndices), + RegExpPrototypeGetIgnoreCase: uncurryThis($RegExpPrototypeGetIgnoreCase), + RegExpPrototypeGetMultiline: uncurryThis($RegExpPrototypeGetMultiline), + RegExpPrototypeGetSticky: uncurryThis($RegExpPrototypeGetSticky), + RegExpPrototypeGetUnicode: uncurryThis($RegExpPrototypeGetUnicode), + RegExpPrototypeGetUnicodeSets: uncurryThis($RegExpPrototypeGetUnicodeSets), + RegExpPrototypeGetSource: uncurryThis($RegExpPrototypeGetSource), + RegExpPrototypeGetFlags: uncurryThis($RegExpPrototypeGetFlags), + RegExpPrototypeTest: uncurryThis($RegExpPrototypeTest), + RegExpPrototypeConstructor: uncurryThis($RegExpPrototypeConstructor), + RegExpPrototypeSymbolMatch: uncurryThis($RegExpPrototypeSymbolMatch), + RegExpPrototypeSymbolMatchAll: uncurryThis($RegExpPrototypeSymbolMatchAll), + RegExpPrototypeSymbolReplace: uncurryThis($RegExpPrototypeSymbolReplace), + RegExpPrototypeSymbolSearch: uncurryThis($RegExpPrototypeSymbolSearch), + RegExpPrototypeSymbolSplit: uncurryThis($RegExpPrototypeSymbolSplit), + Set: $Set, + SetLength: 0, + SetName: "Set", + SetPrototype: $SetPrototype, + SetGetSymbolSpecies: uncurryThis($SetGetSymbolSpecies), + SetPrototypeAdd: uncurryThis($SetPrototypeAdd), + SetPrototypeClear: uncurryThis($SetPrototypeClear), + SetPrototypeDelete: uncurryThis($SetPrototypeDelete), + SetPrototypeEntries: uncurryThis($SetPrototypeEntries), + SetPrototypeForEach: uncurryThis($SetPrototypeForEach), + SetPrototypeHas: uncurryThis($SetPrototypeHas), + SetPrototypeKeys: uncurryThis($SetPrototypeKeys), + SetPrototypeGetSize: uncurryThis($SetPrototypeGetSize), + SetPrototypeValues: uncurryThis($SetPrototypeValues), + SetPrototypeUnion: uncurryThis($SetPrototypeUnion), + SetPrototypeIntersection: uncurryThis($SetPrototypeIntersection), + SetPrototypeDifference: uncurryThis($SetPrototypeDifference), + SetPrototypeSymmetricDifference: uncurryThis($SetPrototypeSymmetricDifference), + SetPrototypeIsSubsetOf: uncurryThis($SetPrototypeIsSubsetOf), + SetPrototypeIsSupersetOf: uncurryThis($SetPrototypeIsSupersetOf), + SetPrototypeIsDisjointFrom: uncurryThis($SetPrototypeIsDisjointFrom), + SetPrototypeConstructor: uncurryThis($SetPrototypeConstructor), + SetPrototypeSymbolIterator: uncurryThis($SetPrototypeSymbolIterator), + SetPrototypeSymbolToStringTag: "Set", + String: $String, + StringLength: 1, + StringName: "String", + StringFromCharCode: $StringFromCharCode, + StringFromCharCodeApply: applyBind($StringFromCharCode, $String), + StringFromCodePoint: $StringFromCodePoint, + StringFromCodePointApply: applyBind($StringFromCodePoint, $String), + StringRaw: $StringRaw, + StringPrototype: $StringPrototype, + StringPrototypeLength: 0, + StringPrototypeAnchor: uncurryThis($StringPrototypeAnchor), + StringPrototypeBig: uncurryThis($StringPrototypeBig), + StringPrototypeBold: uncurryThis($StringPrototypeBold), + StringPrototypeBlink: uncurryThis($StringPrototypeBlink), + StringPrototypeFixed: uncurryThis($StringPrototypeFixed), + StringPrototypeFontcolor: uncurryThis($StringPrototypeFontcolor), + StringPrototypeFontsize: uncurryThis($StringPrototypeFontsize), + StringPrototypeItalics: uncurryThis($StringPrototypeItalics), + StringPrototypeLink: uncurryThis($StringPrototypeLink), + StringPrototypeSmall: uncurryThis($StringPrototypeSmall), + StringPrototypeStrike: uncurryThis($StringPrototypeStrike), + StringPrototypeSub: uncurryThis($StringPrototypeSub), + StringPrototypeSup: uncurryThis($StringPrototypeSup), + StringPrototypeToString: uncurryThis($StringPrototypeToString), + StringPrototypeValueOf: uncurryThis($StringPrototypeValueOf), + StringPrototypeCharAt: uncurryThis($StringPrototypeCharAt), + StringPrototypeCharCodeAt: uncurryThis($StringPrototypeCharCodeAt), + StringPrototypeCodePointAt: uncurryThis($StringPrototypeCodePointAt), + StringPrototypeConcat: uncurryThis($StringPrototypeConcat), + StringPrototypeConcatApply: applyBind($StringPrototypeConcat), + StringPrototypeIndexOf: uncurryThis($StringPrototypeIndexOf), + StringPrototypeLastIndexOf: uncurryThis($StringPrototypeLastIndexOf), + StringPrototypeReplace: uncurryThis($StringPrototypeReplace), + StringPrototypeReplaceAll: uncurryThis($StringPrototypeReplaceAll), + StringPrototypeRepeat: uncurryThis($StringPrototypeRepeat), + StringPrototypePadStart: uncurryThis($StringPrototypePadStart), + StringPrototypePadEnd: uncurryThis($StringPrototypePadEnd), + StringPrototypeSlice: uncurryThis($StringPrototypeSlice), + StringPrototypeSubstr: uncurryThis($StringPrototypeSubstr), + StringPrototypeAt: uncurryThis($StringPrototypeAt), + StringPrototypeSubstring: uncurryThis($StringPrototypeSubstring), + StringPrototypeToLowerCase: uncurryThis($StringPrototypeToLowerCase), + StringPrototypeToUpperCase: uncurryThis($StringPrototypeToUpperCase), + StringPrototypeLocaleCompare: uncurryThis($StringPrototypeLocaleCompare), + StringPrototypeToLocaleLowerCase: uncurryThis($StringPrototypeToLocaleLowerCase), + StringPrototypeToLocaleUpperCase: uncurryThis($StringPrototypeToLocaleUpperCase), + StringPrototypeTrim: uncurryThis($StringPrototypeTrim), + StringPrototypeStartsWith: uncurryThis($StringPrototypeStartsWith), + StringPrototypeEndsWith: uncurryThis($StringPrototypeEndsWith), + StringPrototypeIncludes: uncurryThis($StringPrototypeIncludes), + StringPrototypeMatch: uncurryThis($StringPrototypeMatch), + StringPrototypeSearch: uncurryThis($StringPrototypeSearch), + StringPrototypeMatchAll: uncurryThis($StringPrototypeMatchAll), + StringPrototypeSplit: uncurryThis($StringPrototypeSplit), + StringPrototypeNormalize: uncurryThis($StringPrototypeNormalize), + StringPrototypeTrimStart: uncurryThis($StringPrototypeTrimStart), + StringPrototypeTrimLeft: uncurryThis($StringPrototypeTrimLeft), + StringPrototypeTrimEnd: uncurryThis($StringPrototypeTrimEnd), + StringPrototypeTrimRight: uncurryThis($StringPrototypeTrimRight), + StringPrototypeIsWellFormed: uncurryThis($StringPrototypeIsWellFormed), + StringPrototypeToWellFormed: uncurryThis($StringPrototypeToWellFormed), + StringPrototypeConstructor: uncurryThis($StringPrototypeConstructor), + StringPrototypeSymbolIterator: uncurryThis($StringPrototypeSymbolIterator), + Symbol: $Symbol, + SymbolFor: $SymbolFor, + SymbolKeyFor: $SymbolKeyFor, + SymbolLength: 0, + SymbolName: "Symbol", + SymbolPrototype: $SymbolPrototype, + SymbolHasInstance: $SymbolHasInstance, + SymbolIsConcatSpreadable: $SymbolIsConcatSpreadable, + SymbolAsyncIterator: $SymbolAsyncIterator, + SymbolIterator: $SymbolIterator, + SymbolMatch: $SymbolMatch, + SymbolMatchAll: $SymbolMatchAll, + SymbolReplace: $SymbolReplace, + SymbolSearch: $SymbolSearch, + SymbolSpecies: $SymbolSpecies, + SymbolSplit: $SymbolSplit, + SymbolToPrimitive: $SymbolToPrimitive, + SymbolToStringTag: $SymbolToStringTag, + SymbolUnscopables: $SymbolUnscopables, + SymbolDispose: $SymbolDispose, + SymbolAsyncDispose: $SymbolAsyncDispose, + SymbolPrototypeGetDescription: uncurryThis($SymbolPrototypeGetDescription), + SymbolPrototypeToString: uncurryThis($SymbolPrototypeToString), + SymbolPrototypeValueOf: uncurryThis($SymbolPrototypeValueOf), + SymbolPrototypeConstructor: uncurryThis($SymbolPrototypeConstructor), + SymbolPrototypeSymbolToPrimitive: uncurryThis($SymbolPrototypeSymbolToPrimitive), + SymbolPrototypeSymbolToStringTag: "Symbol", + SyntaxError: $SyntaxError, + SyntaxErrorLength: 1, + SyntaxErrorName: "SyntaxError", + SyntaxErrorPrototype: $SyntaxErrorPrototype, + SyntaxErrorPrototypeName: "SyntaxError", + SyntaxErrorPrototypeMessage: "", + SyntaxErrorPrototypeConstructor: uncurryThis($SyntaxErrorPrototypeConstructor), + TypeError: $TypeError, + TypeErrorLength: 1, + TypeErrorName: "TypeError", + TypeErrorPrototype: $TypeErrorPrototype, + TypeErrorPrototypeName: "TypeError", + TypeErrorPrototypeMessage: "", + TypeErrorPrototypeConstructor: uncurryThis($TypeErrorPrototypeConstructor), + URIError: $URIError, + URIErrorLength: 1, + URIErrorName: "URIError", + URIErrorPrototype: $URIErrorPrototype, + URIErrorPrototypeName: "URIError", + URIErrorPrototypeMessage: "", + URIErrorPrototypeConstructor: uncurryThis($URIErrorPrototypeConstructor), + Uint16Array: $Uint16Array, + Uint16ArrayLength: 3, + Uint16ArrayName: "Uint16Array", + Uint16ArrayPrototype: $Uint16ArrayPrototype, + Uint16ArrayBYTES_PER_ELEMENT: 2, + Uint16ArrayPrototypeBYTES_PER_ELEMENT: 2, + Uint16ArrayPrototypeConstructor: uncurryThis($Uint16ArrayPrototypeConstructor), + Uint32Array: $Uint32Array, + Uint32ArrayLength: 3, + Uint32ArrayName: "Uint32Array", + Uint32ArrayPrototype: $Uint32ArrayPrototype, + Uint32ArrayBYTES_PER_ELEMENT: 4, + Uint32ArrayPrototypeBYTES_PER_ELEMENT: 4, + Uint32ArrayPrototypeConstructor: uncurryThis($Uint32ArrayPrototypeConstructor), + Uint8Array: $Uint8Array, + Uint8ArrayLength: 3, + Uint8ArrayName: "Uint8Array", + Uint8ArrayPrototype: $Uint8ArrayPrototype, + Uint8ArrayBYTES_PER_ELEMENT: 1, + Uint8ArrayFromBase64: $Uint8ArrayFromBase64, + Uint8ArrayFromHex: $Uint8ArrayFromHex, + Uint8ArrayPrototypeBYTES_PER_ELEMENT: 1, + Uint8ArrayPrototypeSetFromBase64: uncurryThis($Uint8ArrayPrototypeSetFromBase64), + Uint8ArrayPrototypeSetFromHex: uncurryThis($Uint8ArrayPrototypeSetFromHex), + Uint8ArrayPrototypeToBase64: uncurryThis($Uint8ArrayPrototypeToBase64), + Uint8ArrayPrototypeToHex: uncurryThis($Uint8ArrayPrototypeToHex), + Uint8ArrayPrototypeConstructor: uncurryThis($Uint8ArrayPrototypeConstructor), + Uint8ClampedArray: $Uint8ClampedArray, + Uint8ClampedArrayLength: 3, + Uint8ClampedArrayName: "Uint8ClampedArray", + Uint8ClampedArrayPrototype: $Uint8ClampedArrayPrototype, + Uint8ClampedArrayBYTES_PER_ELEMENT: 1, + Uint8ClampedArrayPrototypeBYTES_PER_ELEMENT: 1, + Uint8ClampedArrayPrototypeConstructor: uncurryThis($Uint8ClampedArrayPrototypeConstructor), + WeakMap: $WeakMap, + WeakMapLength: 0, + WeakMapName: "WeakMap", + WeakMapPrototype: $WeakMapPrototype, + WeakMapPrototypeDelete: uncurryThis($WeakMapPrototypeDelete), + WeakMapPrototypeGet: uncurryThis($WeakMapPrototypeGet), + WeakMapPrototypeHas: uncurryThis($WeakMapPrototypeHas), + WeakMapPrototypeSet: uncurryThis($WeakMapPrototypeSet), + WeakMapPrototypeGetOrInsert: uncurryThis($WeakMapPrototypeGetOrInsert), + WeakMapPrototypeGetOrInsertComputed: uncurryThis($WeakMapPrototypeGetOrInsertComputed), + WeakMapPrototypeConstructor: uncurryThis($WeakMapPrototypeConstructor), + WeakMapPrototypeSymbolToStringTag: "WeakMap", + WeakRef: $WeakRef, + WeakRefLength: 1, + WeakRefName: "WeakRef", + WeakRefPrototype: $WeakRefPrototype, + WeakRefPrototypeDeref: uncurryThis($WeakRefPrototypeDeref), + WeakRefPrototypeConstructor: uncurryThis($WeakRefPrototypeConstructor), + WeakRefPrototypeSymbolToStringTag: "WeakRef", + WeakSet: $WeakSet, + WeakSetLength: 0, + WeakSetName: "WeakSet", + WeakSetPrototype: $WeakSetPrototype, + WeakSetPrototypeDelete: uncurryThis($WeakSetPrototypeDelete), + WeakSetPrototypeHas: uncurryThis($WeakSetPrototypeHas), + WeakSetPrototypeAdd: uncurryThis($WeakSetPrototypeAdd), + WeakSetPrototypeConstructor: uncurryThis($WeakSetPrototypeConstructor), + WeakSetPrototypeSymbolToStringTag: "WeakSet", + Promise: $Promise, + PromiseLength: 1, + PromiseName: "Promise", + PromiseResolve: $FunctionPrototypeBind.$call($PromiseResolve, $Promise), + PromiseReject: $FunctionPrototypeBind.$call($PromiseReject, $Promise), + PromiseRace: $FunctionPrototypeBind.$call($PromiseRace, $Promise), + PromiseAll: $FunctionPrototypeBind.$call($PromiseAll, $Promise), + PromiseAllSettled: $FunctionPrototypeBind.$call($PromiseAllSettled, $Promise), + PromiseAny: $FunctionPrototypeBind.$call($PromiseAny, $Promise), + PromiseWithResolvers: $FunctionPrototypeBind.$call($PromiseWithResolvers, $Promise), + PromisePrototype: $PromisePrototype, + PromiseTry: $FunctionPrototypeBind.$call($PromiseTry, $Promise), + PromiseGetSymbolSpecies: uncurryThis($PromiseGetSymbolSpecies), + PromisePrototypeFinally: uncurryThis($PromisePrototypeFinally), + PromisePrototypeThen: uncurryThis($PromisePrototypeThen), + PromisePrototypeCatch: uncurryThis($PromisePrototypeCatch), + PromisePrototypeConstructor: uncurryThis($PromisePrototypeConstructor), + PromisePrototypeSymbolToStringTag: "Promise", + TypedArray: $TypedArray, + TypedArrayLength: 0, + TypedArrayName: "TypedArray", + TypedArrayPrototype: $TypedArrayPrototype, + TypedArrayOf: uncurryThis($TypedArrayOf), + TypedArrayOfApply: applyBind($TypedArrayOf), + TypedArrayFrom: uncurryThis($TypedArrayFrom), + TypedArrayGetSymbolSpecies: uncurryThis($TypedArrayGetSymbolSpecies), + TypedArrayPrototypeToString: uncurryThis($TypedArrayPrototypeToString), + TypedArrayPrototypeGetBuffer: uncurryThis($TypedArrayPrototypeGetBuffer), + TypedArrayPrototypeGetByteLength: uncurryThis($TypedArrayPrototypeGetByteLength), + TypedArrayPrototypeGetByteOffset: uncurryThis($TypedArrayPrototypeGetByteOffset), + TypedArrayPrototypeCopyWithin: uncurryThis($TypedArrayPrototypeCopyWithin), + TypedArrayPrototypeSort: uncurryThis($TypedArrayPrototypeSort), + TypedArrayPrototypeEvery: uncurryThis($TypedArrayPrototypeEvery), + TypedArrayPrototypeFilter: uncurryThis($TypedArrayPrototypeFilter), + TypedArrayPrototypeEntries: uncurryThis($TypedArrayPrototypeEntries), + TypedArrayPrototypeIncludes: uncurryThis($TypedArrayPrototypeIncludes), + TypedArrayPrototypeFill: uncurryThis($TypedArrayPrototypeFill), + TypedArrayPrototypeFind: uncurryThis($TypedArrayPrototypeFind), + TypedArrayPrototypeFindLast: uncurryThis($TypedArrayPrototypeFindLast), + TypedArrayPrototypeFindIndex: uncurryThis($TypedArrayPrototypeFindIndex), + TypedArrayPrototypeFindLastIndex: uncurryThis($TypedArrayPrototypeFindLastIndex), + TypedArrayPrototypeForEach: uncurryThis($TypedArrayPrototypeForEach), + TypedArrayPrototypeIndexOf: uncurryThis($TypedArrayPrototypeIndexOf), + TypedArrayPrototypeJoin: uncurryThis($TypedArrayPrototypeJoin), + TypedArrayPrototypeKeys: uncurryThis($TypedArrayPrototypeKeys), + TypedArrayPrototypeLastIndexOf: uncurryThis($TypedArrayPrototypeLastIndexOf), + TypedArrayPrototypeGetLength: uncurryThis($TypedArrayPrototypeGetLength), + TypedArrayPrototypeMap: uncurryThis($TypedArrayPrototypeMap), + TypedArrayPrototypeReduce: uncurryThis($TypedArrayPrototypeReduce), + TypedArrayPrototypeReduceRight: uncurryThis($TypedArrayPrototypeReduceRight), + TypedArrayPrototypeReverse: uncurryThis($TypedArrayPrototypeReverse), + TypedArrayPrototypeSet: uncurryThis($TypedArrayPrototypeSet), + TypedArrayPrototypeSlice: uncurryThis($TypedArrayPrototypeSlice), + TypedArrayPrototypeSome: uncurryThis($TypedArrayPrototypeSome), + TypedArrayPrototypeSubarray: uncurryThis($TypedArrayPrototypeSubarray), + TypedArrayPrototypeToLocaleString: uncurryThis($TypedArrayPrototypeToLocaleString), + TypedArrayPrototypeToReversed: uncurryThis($TypedArrayPrototypeToReversed), + TypedArrayPrototypeToSorted: uncurryThis($TypedArrayPrototypeToSorted), + TypedArrayPrototypeWith: uncurryThis($TypedArrayPrototypeWith), + TypedArrayPrototypeAt: uncurryThis($TypedArrayPrototypeAt), + TypedArrayPrototypeValues: uncurryThis($TypedArrayPrototypeValues), + TypedArrayPrototypeConstructor: uncurryThis($TypedArrayPrototypeConstructor), + TypedArrayPrototypeGetSymbolToStringTag: uncurryThis($TypedArrayPrototypeGetSymbolToStringTag), + TypedArrayPrototypeSymbolIterator: uncurryThis($TypedArrayPrototypeSymbolIterator), + ArrayIteratorPrototype: $ArrayIteratorPrototype, + ArrayIteratorPrototypeNext: uncurryThis($ArrayIteratorPrototypeNext), + ArrayIteratorPrototypeSymbolToStringTag: "Array Iterator", + AsyncFunctionPrototype: $AsyncFunctionPrototype, + AsyncFunctionPrototypeConstructor: uncurryThis($AsyncFunctionPrototypeConstructor), + AsyncFunctionPrototypeSymbolToStringTag: "AsyncFunction", + AsyncGeneratorFunctionPrototype: $AsyncGeneratorFunctionPrototype, + AsyncGeneratorFunctionPrototypeConstructor: uncurryThis($AsyncGeneratorFunctionPrototypeConstructor), + AsyncGeneratorFunctionPrototypePrototype: $AsyncGeneratorFunctionPrototypePrototype, + AsyncGeneratorFunctionPrototypeSymbolToStringTag: "AsyncGeneratorFunction", + AsyncIteratorPrototype: $AsyncIteratorPrototype, + AsyncIteratorPrototypeSymbolAsyncIterator: uncurryThis($AsyncIteratorPrototypeSymbolAsyncIterator), + AsyncIteratorPrototypeSymbolAsyncDispose: uncurryThis($AsyncIteratorPrototypeSymbolAsyncDispose), + GeneratorFunctionPrototype: $GeneratorFunctionPrototype, + GeneratorFunctionPrototypeConstructor: uncurryThis($GeneratorFunctionPrototypeConstructor), + GeneratorFunctionPrototypePrototype: $GeneratorFunctionPrototypePrototype, + GeneratorFunctionPrototypeSymbolToStringTag: "GeneratorFunction", + IteratorHelperPrototype: $IteratorHelperPrototype, + IteratorHelperPrototypeNext: uncurryThis($IteratorHelperPrototypeNext), + IteratorHelperPrototypeReturn: uncurryThis($IteratorHelperPrototypeReturn), + IteratorHelperPrototypeSymbolToStringTag: "Iterator Helper", + MapIteratorPrototype: $MapIteratorPrototype, + MapIteratorPrototypeNext: uncurryThis($MapIteratorPrototypeNext), + MapIteratorPrototypeSymbolToStringTag: "Map Iterator", + RegExpStringIteratorPrototype: $RegExpStringIteratorPrototype, + RegExpStringIteratorPrototypeNext: uncurryThis($RegExpStringIteratorPrototypeNext), + RegExpStringIteratorPrototypeSymbolToStringTag: "RegExp String Iterator", + SetIteratorPrototype: $SetIteratorPrototype, + SetIteratorPrototypeNext: uncurryThis($SetIteratorPrototypeNext), + SetIteratorPrototypeSymbolToStringTag: "Set Iterator", + StringIteratorPrototype: $StringIteratorPrototype, + StringIteratorPrototypeNext: uncurryThis($StringIteratorPrototypeNext), + StringIteratorPrototypeSymbolToStringTag: "String Iterator", + WrapForValidIteratorPrototype: $WrapForValidIteratorPrototype, + WrapForValidIteratorPrototypeNext: uncurryThis($WrapForValidIteratorPrototypeNext), + WrapForValidIteratorPrototypeReturn: uncurryThis($WrapForValidIteratorPrototypeReturn), + WrapForValidIteratorPrototypeSymbolToStringTag: "Iterator", +}; + +// Pristine descriptors of the Safe* bases' original properties (see epilogue). +const pristineDescriptors = { __proto__: null }; +pristineDescriptors.MapPrototype = { + __proto__: null, + clear: { __proto__: null, value: $MapPrototypeClear, writable: true, enumerable: false, configurable: true }, + delete: { __proto__: null, value: $MapPrototypeDelete, writable: true, enumerable: false, configurable: true }, + entries: { __proto__: null, value: $MapPrototypeEntries, writable: true, enumerable: false, configurable: true }, + forEach: { __proto__: null, value: $MapPrototypeForEach, writable: true, enumerable: false, configurable: true }, + get: { __proto__: null, value: $MapPrototypeGet, writable: true, enumerable: false, configurable: true }, + has: { __proto__: null, value: $MapPrototypeHas, writable: true, enumerable: false, configurable: true }, + keys: { __proto__: null, value: $MapPrototypeKeys, writable: true, enumerable: false, configurable: true }, + set: { __proto__: null, value: $MapPrototypeSet, writable: true, enumerable: false, configurable: true }, + getOrInsert: { + __proto__: null, + value: $MapPrototypeGetOrInsert, + writable: true, + enumerable: false, + configurable: true, + }, + getOrInsertComputed: { + __proto__: null, + value: $MapPrototypeGetOrInsertComputed, + writable: true, + enumerable: false, + configurable: true, + }, + size: { __proto__: null, get: $MapPrototypeGetSize, enumerable: false, configurable: true }, + values: { __proto__: null, value: $MapPrototypeValues, writable: true, enumerable: false, configurable: true }, + constructor: { + __proto__: null, + value: $MapPrototypeConstructor, + writable: true, + enumerable: false, + configurable: true, + }, + [$SymbolIterator]: { + __proto__: null, + value: $MapPrototypeSymbolIterator, + writable: true, + enumerable: false, + configurable: true, + }, + [$SymbolToStringTag]: { __proto__: null, value: "Map", writable: false, enumerable: false, configurable: true }, +}; +pristineDescriptors.MapConstructor = { + __proto__: null, + length: { __proto__: null, value: 0, writable: false, enumerable: false, configurable: true }, + name: { __proto__: null, value: "Map", writable: false, enumerable: false, configurable: true }, + groupBy: { __proto__: null, value: $MapGroupBy, writable: true, enumerable: false, configurable: true }, + [$SymbolSpecies]: { __proto__: null, get: $MapGetSymbolSpecies, enumerable: false, configurable: true }, +}; +pristineDescriptors.SetPrototype = { + __proto__: null, + add: { __proto__: null, value: $SetPrototypeAdd, writable: true, enumerable: false, configurable: true }, + clear: { __proto__: null, value: $SetPrototypeClear, writable: true, enumerable: false, configurable: true }, + delete: { __proto__: null, value: $SetPrototypeDelete, writable: true, enumerable: false, configurable: true }, + entries: { __proto__: null, value: $SetPrototypeEntries, writable: true, enumerable: false, configurable: true }, + forEach: { __proto__: null, value: $SetPrototypeForEach, writable: true, enumerable: false, configurable: true }, + has: { __proto__: null, value: $SetPrototypeHas, writable: true, enumerable: false, configurable: true }, + keys: { __proto__: null, value: $SetPrototypeKeys, writable: true, enumerable: false, configurable: true }, + size: { __proto__: null, get: $SetPrototypeGetSize, enumerable: false, configurable: true }, + values: { __proto__: null, value: $SetPrototypeValues, writable: true, enumerable: false, configurable: true }, + union: { __proto__: null, value: $SetPrototypeUnion, writable: true, enumerable: false, configurable: true }, + intersection: { + __proto__: null, + value: $SetPrototypeIntersection, + writable: true, + enumerable: false, + configurable: true, + }, + difference: { + __proto__: null, + value: $SetPrototypeDifference, + writable: true, + enumerable: false, + configurable: true, + }, + symmetricDifference: { + __proto__: null, + value: $SetPrototypeSymmetricDifference, + writable: true, + enumerable: false, + configurable: true, + }, + isSubsetOf: { + __proto__: null, + value: $SetPrototypeIsSubsetOf, + writable: true, + enumerable: false, + configurable: true, + }, + isSupersetOf: { + __proto__: null, + value: $SetPrototypeIsSupersetOf, + writable: true, + enumerable: false, + configurable: true, + }, + isDisjointFrom: { + __proto__: null, + value: $SetPrototypeIsDisjointFrom, + writable: true, + enumerable: false, + configurable: true, + }, + constructor: { + __proto__: null, + value: $SetPrototypeConstructor, + writable: true, + enumerable: false, + configurable: true, + }, + [$SymbolIterator]: { + __proto__: null, + value: $SetPrototypeSymbolIterator, + writable: true, + enumerable: false, + configurable: true, + }, + [$SymbolToStringTag]: { __proto__: null, value: "Set", writable: false, enumerable: false, configurable: true }, +}; +pristineDescriptors.SetConstructor = { + __proto__: null, + length: { __proto__: null, value: 0, writable: false, enumerable: false, configurable: true }, + name: { __proto__: null, value: "Set", writable: false, enumerable: false, configurable: true }, + [$SymbolSpecies]: { __proto__: null, get: $SetGetSymbolSpecies, enumerable: false, configurable: true }, +}; +pristineDescriptors.WeakMapPrototype = { + __proto__: null, + delete: { __proto__: null, value: $WeakMapPrototypeDelete, writable: true, enumerable: false, configurable: true }, + get: { __proto__: null, value: $WeakMapPrototypeGet, writable: true, enumerable: false, configurable: true }, + has: { __proto__: null, value: $WeakMapPrototypeHas, writable: true, enumerable: false, configurable: true }, + set: { __proto__: null, value: $WeakMapPrototypeSet, writable: true, enumerable: false, configurable: true }, + getOrInsert: { + __proto__: null, + value: $WeakMapPrototypeGetOrInsert, + writable: true, + enumerable: false, + configurable: true, + }, + getOrInsertComputed: { + __proto__: null, + value: $WeakMapPrototypeGetOrInsertComputed, + writable: true, + enumerable: false, + configurable: true, + }, + constructor: { + __proto__: null, + value: $WeakMapPrototypeConstructor, + writable: true, + enumerable: false, + configurable: true, + }, + [$SymbolToStringTag]: { __proto__: null, value: "WeakMap", writable: false, enumerable: false, configurable: true }, +}; +pristineDescriptors.WeakMapConstructor = { + __proto__: null, + length: { __proto__: null, value: 0, writable: false, enumerable: false, configurable: true }, + name: { __proto__: null, value: "WeakMap", writable: false, enumerable: false, configurable: true }, +}; +pristineDescriptors.WeakSetPrototype = { + __proto__: null, + delete: { __proto__: null, value: $WeakSetPrototypeDelete, writable: true, enumerable: false, configurable: true }, + has: { __proto__: null, value: $WeakSetPrototypeHas, writable: true, enumerable: false, configurable: true }, + add: { __proto__: null, value: $WeakSetPrototypeAdd, writable: true, enumerable: false, configurable: true }, + constructor: { + __proto__: null, + value: $WeakSetPrototypeConstructor, + writable: true, + enumerable: false, + configurable: true, + }, + [$SymbolToStringTag]: { __proto__: null, value: "WeakSet", writable: false, enumerable: false, configurable: true }, +}; +pristineDescriptors.WeakSetConstructor = { + __proto__: null, + length: { __proto__: null, value: 0, writable: false, enumerable: false, configurable: true }, + name: { __proto__: null, value: "WeakSet", writable: false, enumerable: false, configurable: true }, +}; +pristineDescriptors.FinalizationRegistryPrototype = { + __proto__: null, + register: { + __proto__: null, + value: $FinalizationRegistryPrototypeRegister, + writable: true, + enumerable: false, + configurable: true, + }, + unregister: { + __proto__: null, + value: $FinalizationRegistryPrototypeUnregister, + writable: true, + enumerable: false, + configurable: true, + }, + constructor: { + __proto__: null, + value: $FinalizationRegistryPrototypeConstructor, + writable: true, + enumerable: false, + configurable: true, + }, + [$SymbolToStringTag]: { + __proto__: null, + value: "FinalizationRegistry", + writable: false, + enumerable: false, + configurable: true, + }, +}; +pristineDescriptors.FinalizationRegistryConstructor = { + __proto__: null, + length: { __proto__: null, value: 1, writable: false, enumerable: false, configurable: true }, + name: { __proto__: null, value: "FinalizationRegistry", writable: false, enumerable: false, configurable: true }, +}; +pristineDescriptors.WeakRefPrototype = { + __proto__: null, + deref: { __proto__: null, value: $WeakRefPrototypeDeref, writable: true, enumerable: false, configurable: true }, + constructor: { + __proto__: null, + value: $WeakRefPrototypeConstructor, + writable: true, + enumerable: false, + configurable: true, + }, + [$SymbolToStringTag]: { __proto__: null, value: "WeakRef", writable: false, enumerable: false, configurable: true }, +}; +pristineDescriptors.WeakRefConstructor = { + __proto__: null, + length: { __proto__: null, value: 1, writable: false, enumerable: false, configurable: true }, + name: { __proto__: null, value: "WeakRef", writable: false, enumerable: false, configurable: true }, +}; +pristineDescriptors.PromisePrototype = { + __proto__: null, + finally: { __proto__: null, value: $PromisePrototypeFinally, writable: true, enumerable: false, configurable: true }, + then: { __proto__: null, value: $PromisePrototypeThen, writable: true, enumerable: false, configurable: true }, + catch: { __proto__: null, value: $PromisePrototypeCatch, writable: true, enumerable: false, configurable: true }, + constructor: { + __proto__: null, + value: $PromisePrototypeConstructor, + writable: true, + enumerable: false, + configurable: true, + }, + [$SymbolToStringTag]: { __proto__: null, value: "Promise", writable: false, enumerable: false, configurable: true }, +}; +pristineDescriptors.PromiseConstructor = { + __proto__: null, + length: { __proto__: null, value: 1, writable: false, enumerable: false, configurable: true }, + name: { __proto__: null, value: "Promise", writable: false, enumerable: false, configurable: true }, + resolve: { __proto__: null, value: $PromiseResolve, writable: true, enumerable: false, configurable: true }, + reject: { __proto__: null, value: $PromiseReject, writable: true, enumerable: false, configurable: true }, + race: { __proto__: null, value: $PromiseRace, writable: true, enumerable: false, configurable: true }, + all: { __proto__: null, value: $PromiseAll, writable: true, enumerable: false, configurable: true }, + allSettled: { __proto__: null, value: $PromiseAllSettled, writable: true, enumerable: false, configurable: true }, + any: { __proto__: null, value: $PromiseAny, writable: true, enumerable: false, configurable: true }, + withResolvers: { + __proto__: null, + value: $PromiseWithResolvers, + writable: true, + enumerable: false, + configurable: true, + }, + try: { __proto__: null, value: $PromiseTry, writable: true, enumerable: false, configurable: true }, + [$SymbolSpecies]: { __proto__: null, get: $PromiseGetSymbolSpecies, enumerable: false, configurable: true }, +}; + +// ─── helpers layered on the generated object (mirrors Node's primordials.js) ─── + +primordials.uncurryThis = uncurryThis; +primordials.applyBind = applyBind; + +const { + Array: ArrayConstructor, + ArrayPrototypeForEach, + ArrayPrototypeMap, + ArrayPrototypePushApply, + ArrayPrototypeSlice, + ArrayIteratorPrototypeNext, + ArrayPrototypeSymbolIterator, + FinalizationRegistry, + FunctionPrototypeCall, + Map, + MapIteratorPrototypeNext, + ObjectDefineProperties, + ObjectDefineProperty, + ObjectFreeze, + ObjectGetPrototypeOf, + ObjectSetPrototypeOf, + Promise, + PromisePrototypeThen, + PromiseResolve, + ReflectApply, + ReflectConstruct, + ReflectDefineProperty, + ReflectGet, + ReflectGetOwnPropertyDescriptor, + ReflectOwnKeys, + ReflectSet, + RegExp, + RegExpPrototypeExec, + RegExpPrototypeGetDotAll, + RegExpPrototypeGetFlags, + RegExpPrototypeGetGlobal, + RegExpPrototypeGetHasIndices, + RegExpPrototypeGetIgnoreCase, + RegExpPrototypeGetMultiline, + RegExpPrototypeGetSource, + RegExpPrototypeGetSticky, + RegExpPrototypeGetUnicode, + Set, + SetIteratorPrototypeNext, + StringIteratorPrototypeNext, + StringPrototypeSymbolIterator, + SymbolIterator, + SymbolMatch, + SymbolMatchAll, + SymbolReplace, + SymbolSearch, + SymbolSpecies, + SymbolSplit, + WeakMap, + WeakRef, + WeakSet, +} = primordials; + +// An iterator user code can't intercept: its next() and Symbol.iterator are +// captured functions and its prototype is detached and frozen. +const createSafeIterator = (factory, next) => { class SafeIterator { constructor(iterable) { this._iterator = factory(iterable); } next() { - return next_(this._iterator); + return next(this._iterator); } - [Symbol.iterator]() { + [SymbolIterator]() { return this; } } @@ -23,154 +1221,328 @@ const createSafeIterator = (factory, next_) => { return SafeIterator; }; -// Intrinsics do not have `call` as a valid identifier, so this cannot be `Function.prototype.call.bind`. -const FunctionPrototypeCall = $getByIdDirect(Function.prototype, "call"); +const SafeArrayIterator = createSafeIterator(ArrayPrototypeSymbolIterator, ArrayIteratorPrototypeNext); +primordials.SafeArrayIterator = SafeArrayIterator; +primordials.SafeStringIterator = createSafeIterator(StringPrototypeSymbolIterator, StringIteratorPrototypeNext); -function getGetter(cls, getter) { - // TODO: __lookupGetter__ is deprecated, but Object.getOwnPropertyDescriptor doesn't work on built-ins like Typed Arrays. - return FunctionPrototypeCall.bind(cls.prototype.__lookupGetter__(getter)); -} +const copyOwnProperties = (source, target) => { + ArrayPrototypeForEach(ReflectOwnKeys(source), key => { + if (!ReflectGetOwnPropertyDescriptor(target, key)) + ReflectDefineProperty(target, key, { __proto__: null, ...ReflectGetOwnPropertyDescriptor(source, key) }); + }); +}; -function uncurryThis(func) { - // Intrinsics do not have `call` as a valid identifier, so this cannot be `Function.prototype.call.bind`. - return FunctionPrototypeCall.bind(func); -} +const detachAndFreeze = safe => { + ObjectSetPrototypeOf(safe.prototype, null); + ObjectFreeze(safe.prototype); + ObjectFreeze(safe); + return safe; +}; + +const defineFromDescriptors = (descriptors, target, mapDescriptor) => { + ArrayPrototypeForEach(ReflectOwnKeys(descriptors), key => { + if (!ReflectGetOwnPropertyDescriptor(target, key)) + ReflectDefineProperty(target, key, mapDescriptor({ __proto__: null, ...descriptors[key] }, key)); + }); +}; -const copyProps = (src, dest) => { - ArrayPrototypeForEach(Reflect.ownKeys(src), key => { - if (!Reflect.getOwnPropertyDescriptor(dest, key)) { - Reflect.defineProperty(dest, key, Reflect.getOwnPropertyDescriptor(src, key)); +// This module loads lazily, possibly after user code, so our own Safe* classes are +// built from the pristine descriptor records the generator emits rather than by +// reading the live prototypes. `iterator` = { prototype, next } (pristine): zero-arg +// methods that hand out that iterator kind are rewrapped to return safe iterators. +const makeSafeFromPristine = (unsafe, safe, prototypeDescriptors, staticDescriptors, iterator) => { + const instance = iterator ? new unsafe() : null; + defineFromDescriptors(prototypeDescriptors, safe.prototype, descriptor => { + const method = descriptor.value; + if (iterator && typeof method === "function" && method.length === 0) { + const result = FunctionPrototypeCall(method, instance); + if (result != null && typeof result === "object" && ObjectGetPrototypeOf(result) === iterator.prototype) { + const SafeIterator = createSafeIterator(uncurryThis(method), iterator.next); + descriptor.value = function () { + return new SafeIterator(this); + }; + } } + return descriptor; }); + defineFromDescriptors(staticDescriptors, safe, descriptor => descriptor); + return detachAndFreeze(safe); }; +// The exported makeSafe copies from a consumer's own classes at their call time +// (as in Node); zero-arg iterator-returning methods are rewrapped so the copies +// hand out safe iterators over a captured pristine `next`. const makeSafe = (unsafe, safe) => { const unsafePrototype = unsafe.prototype; - const safePrototype = safe.prototype; - if (Symbol.iterator in unsafePrototype) { + if (SymbolIterator in unsafePrototype) { const dummy = new unsafe(); let next; // We can reuse the same `next` method. - - ArrayPrototypeForEach(Reflect.ownKeys(unsafePrototype), key => { - if (!Reflect.getOwnPropertyDescriptor(safePrototype, key)) { - const desc = Reflect.getOwnPropertyDescriptor(unsafePrototype, key); - if (typeof desc.value === "function" && desc.value.length === 0) { - const called = desc.value.$call(dummy) || {}; - if (Symbol.iterator in (typeof called === "object" ? called : {})) { - const createIterator = uncurryThis(desc.value); - next ??= uncurryThis(createIterator(dummy).next); - const SafeIterator = createSafeIterator(createIterator, next); - desc.value = function () { - return new SafeIterator(this); - }; - } - } - Reflect.defineProperty(safePrototype, key, desc); + ArrayPrototypeForEach(ReflectOwnKeys(unsafePrototype), key => { + if (ReflectGetOwnPropertyDescriptor(safe.prototype, key)) return; + const descriptor = ReflectGetOwnPropertyDescriptor(unsafePrototype, key); + if ( + typeof descriptor.value === "function" && + descriptor.value.length === 0 && + SymbolIterator in (FunctionPrototypeCall(descriptor.value, dummy) ?? {}) + ) { + const createIterator = uncurryThis(descriptor.value); + next ??= uncurryThis(createIterator(dummy).next); + const SafeIterator = createSafeIterator(createIterator, next); + descriptor.value = function () { + return new SafeIterator(this); + }; } + ReflectDefineProperty(safe.prototype, key, { __proto__: null, ...descriptor }); }); - } else copyProps(unsafePrototype, safePrototype); - copyProps(unsafe, safe); - - Object.setPrototypeOf(safePrototype, null); - Object.freeze(safePrototype); - Object.freeze(safe); - return safe; + } else { + copyOwnProperties(unsafePrototype, safe.prototype); + } + copyOwnProperties(unsafe, safe); + return detachAndFreeze(safe); }; +primordials.makeSafe = makeSafe; -const StringIterator = uncurryThis(String.prototype[Symbol.iterator]); -const StringIteratorPrototype = Reflect.getPrototypeOf(StringIterator("")); -const ArrayPrototypeForEach = uncurryThis(Array.prototype.forEach); -const ArrayPrototypeSymbolIterator = uncurryThis(Array.prototype[Symbol.iterator]); -const ArrayIteratorPrototypeNext = uncurryThis(Array.prototype[Symbol.iterator]().next); -const SafeArrayIterator = createSafeIterator(ArrayPrototypeSymbolIterator, ArrayIteratorPrototypeNext); +const mapIteration = { prototype: primordials.MapIteratorPrototype, next: MapIteratorPrototypeNext }; +const setIteration = { prototype: primordials.SetIteratorPrototype, next: SetIteratorPrototypeNext }; +primordials.SafeMap = makeSafeFromPristine( + Map, + class SafeMap extends Map { + constructor(i) { + super(i); + } + }, + pristineDescriptors.MapPrototype, + pristineDescriptors.MapConstructor, + mapIteration, +); +primordials.SafeWeakMap = makeSafeFromPristine( + WeakMap, + class SafeWeakMap extends WeakMap { + constructor(i) { + super(i); + } + }, + pristineDescriptors.WeakMapPrototype, + pristineDescriptors.WeakMapConstructor, +); +primordials.SafeSet = makeSafeFromPristine( + Set, + class SafeSet extends Set { + constructor(i) { + super(i); + } + }, + pristineDescriptors.SetPrototype, + pristineDescriptors.SetConstructor, + setIteration, +); +primordials.SafeWeakSet = makeSafeFromPristine( + WeakSet, + class SafeWeakSet extends WeakSet { + constructor(i) { + super(i); + } + }, + pristineDescriptors.WeakSetPrototype, + pristineDescriptors.WeakSetConstructor, +); +primordials.SafeFinalizationRegistry = makeSafeFromPristine( + FinalizationRegistry, + class SafeFinalizationRegistry extends FinalizationRegistry { + constructor(i) { + super(i); + } + }, + pristineDescriptors.FinalizationRegistryPrototype, + pristineDescriptors.FinalizationRegistryConstructor, +); +primordials.SafeWeakRef = makeSafeFromPristine( + WeakRef, + class SafeWeakRef extends WeakRef { + constructor(i) { + super(i); + } + }, + pristineDescriptors.WeakRefPrototype, + pristineDescriptors.WeakRefConstructor, +); + +const SafePromise = makeSafeFromPristine( + Promise, + class SafePromise extends Promise { + constructor(i) { + super(i); + } + }, + pristineDescriptors.PromisePrototype, + pristineDescriptors.PromiseConstructor, +); -const PromisePrototypeThen = $Promise.prototype.$then; -const PromiseResolve = Promise.$resolve.bind(Promise); -// Shared scheduler for SafePromiseAllReturnVoid/ReturnArrayLike: `returnVal` -// is null for the void variant (no result bookkeeping, resolves with nothing). -const safePromiseAllCollect = (promises, mapFn, returnVal) => +// The Safe* promise combinators wrap results in a plain Promise so the SafePromise +// prototype never reaches user code, and wrap each input so a tampered .then on +// a user promise cannot observe the combinator. +const SafePromisePrototypeFinallyOfSafe = uncurryThis(SafePromise.prototype.finally); +const SafePromisePrototypeThenOfSafe = uncurryThis(SafePromise.prototype.then); +primordials.SafePromisePrototypeFinally = (thisPromise, onFinally) => new Promise((resolve, reject) => { - const { length } = promises; + const wrapped = new SafePromise((resolveInner, rejectInner) => + PromisePrototypeThen(thisPromise, resolveInner, rejectInner), + ); + SafePromisePrototypeThenOfSafe(SafePromisePrototypeFinallyOfSafe(wrapped, onFinally), resolve, reject); + }); - if (length === 0) resolve(returnVal ?? undefined); +const arrayToSafePromiseIterable = (promises, mapFn) => + new SafeArrayIterator( + ArrayPrototypeMap( + promises, + (promise, i) => + new SafePromise((resolve, reject) => + PromisePrototypeThen(mapFn == null ? promise : mapFn(promise, i), resolve, reject), + ), + ), + ); - let pendingPromises = length; +const safePromiseCombinator = combinator => (promises, mapFn) => + new Promise((resolve, reject) => + SafePromisePrototypeThenOfSafe( + FunctionPrototypeCall(combinator, SafePromise, arrayToSafePromiseIterable(promises, mapFn)), + resolve, + reject, + ), + ); + +primordials.SafePromiseAll = safePromiseCombinator(SafePromise.all); +primordials.SafePromiseAllSettled = safePromiseCombinator(SafePromise.allSettled); +primordials.SafePromiseAny = safePromiseCombinator(SafePromise.any); +primordials.SafePromiseRace = safePromiseCombinator(SafePromise.race); + +// The *ReturnArrayLike/*ReturnVoid variants avoid Promise.all entirely: no +// prototype lookups, and the array-like result has no Array.prototype. +primordials.SafePromiseAllReturnArrayLike = (promises, mapFn) => + new Promise((resolve, reject) => { + const { length } = promises; + const results = ArrayConstructor(length); + ObjectSetPrototypeOf(results, null); + if (length === 0) resolve(results); + let pending = length; for (let i = 0; i < length; i++) { const promise = mapFn != null ? mapFn(promises[i], i) : promises[i]; - PromisePrototypeThen.$call( + PromisePrototypeThen( PromiseResolve(promise), result => { - if (returnVal !== null) returnVal[i] = result; - if (--pendingPromises === 0) resolve(returnVal ?? undefined); + results[i] = result; + if (--pending === 0) resolve(results); }, reject, ); } }); -const SafePromiseAllReturnVoid = (promises, mapFn) => safePromiseAllCollect(promises, mapFn, null); -const SafePromiseAllReturnArrayLike = (promises, mapFn) => { - const returnVal = Array(promises.length); - ObjectSetPrototypeOf(returnVal, null); - return safePromiseAllCollect(promises, mapFn, returnVal); -}; - -export default { - Array, - SafeArrayIterator, - MapPrototypeGetSize: getGetter(Map, "size"), - Number, - Object, - RegExp, - SafeStringIterator: createSafeIterator(StringIterator, uncurryThis(StringIteratorPrototype.next)), - SafeMap: makeSafe( - Map, - class SafeMap extends Map { - constructor(i) { - super(i); - } - }, - ), - SafePromiseAllReturnArrayLike, - SafePromiseAllReturnVoid, - SafeSet: makeSafe( - Set, - class SafeSet extends Set { - constructor(i) { - super(i); - } - }, - ), - SafeWeakSet: makeSafe( - WeakSet, - class SafeWeakSet extends WeakSet { - constructor(i) { - super(i); - } - }, - ), - SafeWeakMap: makeSafe( - WeakMap, - class SafeWeakMap extends WeakMap { - constructor(i) { - super(i); - } - }, - ), - SetPrototypeGetSize: getGetter(Set, "size"), - String, - TypedArrayPrototypeGetLength: getGetter(Uint8Array, "length"), - TypedArrayPrototypeGetSymbolToStringTag: getGetter(Uint8Array, Symbol.toStringTag), - Uint8ClampedArray, - Uint8Array, - Uint16Array, - Uint32Array, - Int8Array, - Int16Array, - Int32Array, - Float16Array, - Float32Array, - Float64Array, - BigUint64Array, - BigInt64Array, - uncurryThis, + +primordials.SafePromiseAllReturnVoid = (promises, mapFn) => + new Promise((resolve, reject) => { + let pending = promises.length; + if (pending === 0) resolve(); + const onFulfilled = () => { + if (--pending === 0) resolve(); + }; + for (let i = 0; i < promises.length; i++) { + const promise = mapFn != null ? mapFn(promises[i], i) : promises[i]; + PromisePrototypeThen(PromiseResolve(promise), onFulfilled, reject); + } + }); + +primordials.SafePromiseAllSettledReturnVoid = (promises, mapFn) => + new Promise(resolve => { + let pending = promises.length; + if (pending === 0) resolve(); + const onSettled = () => { + if (--pending === 0) resolve(); + }; + for (let i = 0; i < promises.length; i++) { + const promise = mapFn != null ? mapFn(promises[i], i) : promises[i]; + PromisePrototypeThen(PromiseResolve(promise), onSettled, onSettled); + } + }); + +// The raw (this-taking) originals: hardenRegExp installs them on the pattern +// itself. They come from the pristine constants, not the live RegExp.prototype, +// because this module can load after user code has replaced those properties. +const OriginalRegExpPrototypeExec = $RegExpPrototypeExec; +const OriginalRegExpPrototypeSymbolMatch = $RegExpPrototypeSymbolMatch; +const OriginalRegExpPrototypeSymbolMatchAll = $RegExpPrototypeSymbolMatchAll; +const OriginalRegExpPrototypeSymbolReplace = $RegExpPrototypeSymbolReplace; +const OriginalRegExpPrototypeSymbolSearch = $RegExpPrototypeSymbolSearch; +const OriginalRegExpPrototypeSymbolSplit = $RegExpPrototypeSymbolSplit; + +// The species String.prototype.split uses on a hardened pattern: only lastIndex +// and exec are ever consulted, and the inner pattern is a real, private RegExp. +class RegExpLikeForStringSplitting { + #regex; + constructor() { + this.#regex = ReflectConstruct(RegExp, arguments); + } + get lastIndex() { + return ReflectGet(this.#regex, "lastIndex"); + } + set lastIndex(value) { + ReflectSet(this.#regex, "lastIndex", value); + } + exec() { + return ReflectApply(OriginalRegExpPrototypeExec, this.#regex, arguments); + } +} +ObjectSetPrototypeOf(RegExpLikeForStringSplitting.prototype, null); + +// Freezes a pattern's observable protocol (Symbol.match/replace/..., exec, flags, +// species) to the original algorithms so String methods can use it after user code ran. +primordials.hardenRegExp = function hardenRegExp(pattern) { + ObjectDefineProperties(pattern, { + [SymbolMatch]: { __proto__: null, configurable: true, value: OriginalRegExpPrototypeSymbolMatch }, + [SymbolMatchAll]: { __proto__: null, configurable: true, value: OriginalRegExpPrototypeSymbolMatchAll }, + [SymbolReplace]: { __proto__: null, configurable: true, value: OriginalRegExpPrototypeSymbolReplace }, + [SymbolSearch]: { __proto__: null, configurable: true, value: OriginalRegExpPrototypeSymbolSearch }, + [SymbolSplit]: { __proto__: null, configurable: true, value: OriginalRegExpPrototypeSymbolSplit }, + constructor: { __proto__: null, configurable: true, value: { [SymbolSpecies]: RegExpLikeForStringSplitting } }, + dotAll: { __proto__: null, configurable: true, value: RegExpPrototypeGetDotAll(pattern) }, + exec: { __proto__: null, configurable: true, value: OriginalRegExpPrototypeExec }, + global: { __proto__: null, configurable: true, value: RegExpPrototypeGetGlobal(pattern) }, + hasIndices: { __proto__: null, configurable: true, value: RegExpPrototypeGetHasIndices(pattern) }, + ignoreCase: { __proto__: null, configurable: true, value: RegExpPrototypeGetIgnoreCase(pattern) }, + multiline: { __proto__: null, configurable: true, value: RegExpPrototypeGetMultiline(pattern) }, + source: { __proto__: null, configurable: true, value: RegExpPrototypeGetSource(pattern) }, + sticky: { __proto__: null, configurable: true, value: RegExpPrototypeGetSticky(pattern) }, + unicode: { __proto__: null, configurable: true, value: RegExpPrototypeGetUnicode(pattern) }, + }); + ObjectDefineProperty(pattern, "flags", { + __proto__: null, + configurable: true, + value: RegExpPrototypeGetFlags(pattern), + }); + return pattern; +}; + +primordials.SafeStringPrototypeSearch = (str, regexp) => { + regexp.lastIndex = 0; + const match = RegExpPrototypeExec(regexp, str); + return match ? match.index : -1; }; + +// Chunked push.apply so arbitrarily large arrays don't exhaust the stack. +primordials.SafeArrayPrototypePushApply = (array, items) => { + const { length } = items; + let end = 0x10000; + if (end < length) { + let start = 0; + do { + ArrayPrototypePushApply(array, ArrayPrototypeSlice(items, start, (start = end))); + end += 0x10000; + } while (end < length); + items = ArrayPrototypeSlice(items, start); + } + return ArrayPrototypePushApply(array, items); +}; + +ObjectSetPrototypeOf(primordials, null); +ObjectFreeze(primordials); + +export default primordials; diff --git a/src/js/primordials.d.ts b/src/js/primordials.d.ts new file mode 100644 index 000000000000..0f1b87c8cd8d --- /dev/null +++ b/src/js/primordials.d.ts @@ -0,0 +1,677 @@ +// GENERATED FILE — do not edit. Regenerate with: +// bun src/codegen/generate-primordials.ts --bun= --webkit= +// oxlint-disable typescript/no-wrapper-object-types -- wrapper types model real prototype receivers +// +// Tamper-proof references to the original ECMAScript builtins, exposed by JSC +// (JSCPrimordials.h) as link-time constants and named after Node.js's primordials. +// Prototype methods, getters, and setters take the receiver via .$call/.$apply: +// +// $ArrayPrototypePush.$call(array, value); +// $MapPrototypeGetSize.$call(map); +// $ObjectDefineProperty(target, key, descriptor); + +type PrimordialMethod = + Holder extends Record + ? Method extends (...args: infer Args) => infer Return + ? (this: Holder, ...args: Args) => Return + : Function + : Function; +type PrimordialGetter = + Holder extends Record ? (this: Holder) => Value : Function; +type PrimordialSetter = + Holder extends Record ? (this: Holder, value: Value) => void : Function; +type PrimordialValue = Holder extends Record ? Value : unknown; + +declare const $Proxy: ProxyConstructor; +declare const $globalThis: PrimordialValue; +declare const $decodeURI: PrimordialMethod; +declare const $decodeURIComponent: PrimordialMethod; +declare const $encodeURI: PrimordialMethod; +declare const $encodeURIComponent: PrimordialMethod; +declare const $escape: PrimordialMethod; +declare const $eval: PrimordialMethod; +declare const $unescape: PrimordialMethod; +declare const $AtomicsAdd: PrimordialMethod; +declare const $AtomicsAnd: PrimordialMethod; +declare const $AtomicsCompareExchange: PrimordialMethod; +declare const $AtomicsExchange: PrimordialMethod; +declare const $AtomicsIsLockFree: PrimordialMethod; +declare const $AtomicsLoad: PrimordialMethod; +declare const $AtomicsNotify: PrimordialMethod; +declare const $AtomicsOr: PrimordialMethod; +declare const $AtomicsStore: PrimordialMethod; +declare const $AtomicsSub: PrimordialMethod; +declare const $AtomicsWait: PrimordialMethod; +declare const $AtomicsXor: PrimordialMethod; +declare const $AtomicsPause: PrimordialMethod; +declare const $AtomicsWaitAsync: PrimordialMethod; +declare const $JSONParse: PrimordialMethod; +declare const $JSONStringify: PrimordialMethod; +declare const $JSONIsRawJSON: PrimordialMethod; +declare const $JSONRawJSON: PrimordialMethod; +declare const $MathAbs: PrimordialMethod; +declare const $MathAcos: PrimordialMethod; +declare const $MathAsin: PrimordialMethod; +declare const $MathAtan: PrimordialMethod; +declare const $MathAcosh: PrimordialMethod; +declare const $MathAsinh: PrimordialMethod; +declare const $MathAtanh: PrimordialMethod; +declare const $MathAtan2: PrimordialMethod; +declare const $MathCbrt: PrimordialMethod; +declare const $MathCeil: PrimordialMethod; +declare const $MathClz32: PrimordialMethod; +declare const $MathCos: PrimordialMethod; +declare const $MathCosh: PrimordialMethod; +declare const $MathExp: PrimordialMethod; +declare const $MathExpm1: PrimordialMethod; +declare const $MathFloor: PrimordialMethod; +declare const $MathFround: PrimordialMethod; +declare const $MathHypot: PrimordialMethod; +declare const $MathLog: PrimordialMethod; +declare const $MathLog10: PrimordialMethod; +declare const $MathLog1p: PrimordialMethod; +declare const $MathLog2: PrimordialMethod; +declare const $MathMax: PrimordialMethod; +declare const $MathMin: PrimordialMethod; +declare const $MathPow: PrimordialMethod; +declare const $MathRandom: PrimordialMethod; +declare const $MathRound: PrimordialMethod; +declare const $MathSign: PrimordialMethod; +declare const $MathSin: PrimordialMethod; +declare const $MathSinh: PrimordialMethod; +declare const $MathSqrt: PrimordialMethod; +declare const $MathTan: PrimordialMethod; +declare const $MathTanh: PrimordialMethod; +declare const $MathTrunc: PrimordialMethod; +declare const $MathImul: PrimordialMethod; +declare const $MathF16round: PrimordialMethod; +declare const $MathSumPrecise: PrimordialMethod; +declare const $ReflectApply: PrimordialMethod; +declare const $ReflectConstruct: PrimordialMethod; +declare const $ReflectDefineProperty: PrimordialMethod; +declare const $ReflectDeleteProperty: PrimordialMethod; +declare const $ReflectGet: PrimordialMethod; +declare const $ReflectGetOwnPropertyDescriptor: PrimordialMethod; +declare const $ReflectGetPrototypeOf: PrimordialMethod; +declare const $ReflectHas: PrimordialMethod; +declare const $ReflectIsExtensible: PrimordialMethod; +declare const $ReflectOwnKeys: PrimordialMethod; +declare const $ReflectPreventExtensions: PrimordialMethod; +declare const $ReflectSet: PrimordialMethod; +declare const $ReflectSetPrototypeOf: PrimordialMethod; +declare const $ProxyRevocable: PrimordialMethod; +declare const $AggregateErrorPrototype: Error; +declare const $AggregateErrorPrototypeConstructor: PrimordialMethod; +declare const $ArrayFrom: PrimordialMethod; +declare const $ArrayPrototype: Array; +declare const $ArrayOf: PrimordialMethod; +declare const $ArrayIsArray: PrimordialMethod; +declare const $ArrayFromAsync: PrimordialMethod; +declare const $ArrayGetSymbolSpecies: PrimordialGetter; +declare const $ArrayPrototypeToString: PrimordialMethod, "toString">; +declare const $ArrayPrototypeValues: PrimordialMethod, "values">; +declare const $ArrayPrototypeToLocaleString: PrimordialMethod, "toLocaleString">; +declare const $ArrayPrototypeConcat: PrimordialMethod, "concat">; +declare const $ArrayPrototypeFill: PrimordialMethod, "fill">; +declare const $ArrayPrototypeJoin: PrimordialMethod, "join">; +declare const $ArrayPrototypePop: PrimordialMethod, "pop">; +declare const $ArrayPrototypePush: PrimordialMethod, "push">; +declare const $ArrayPrototypeReverse: PrimordialMethod, "reverse">; +declare const $ArrayPrototypeShift: PrimordialMethod, "shift">; +declare const $ArrayPrototypeSlice: PrimordialMethod, "slice">; +declare const $ArrayPrototypeSort: PrimordialMethod, "sort">; +declare const $ArrayPrototypeSplice: PrimordialMethod, "splice">; +declare const $ArrayPrototypeUnshift: PrimordialMethod, "unshift">; +declare const $ArrayPrototypeEvery: PrimordialMethod, "every">; +declare const $ArrayPrototypeForEach: PrimordialMethod, "forEach">; +declare const $ArrayPrototypeSome: PrimordialMethod, "some">; +declare const $ArrayPrototypeIndexOf: PrimordialMethod, "indexOf">; +declare const $ArrayPrototypeLastIndexOf: PrimordialMethod, "lastIndexOf">; +declare const $ArrayPrototypeFilter: PrimordialMethod, "filter">; +declare const $ArrayPrototypeFlat: PrimordialMethod, "flat">; +declare const $ArrayPrototypeFlatMap: PrimordialMethod, "flatMap">; +declare const $ArrayPrototypeReduce: PrimordialMethod, "reduce">; +declare const $ArrayPrototypeReduceRight: PrimordialMethod, "reduceRight">; +declare const $ArrayPrototypeMap: PrimordialMethod, "map">; +declare const $ArrayPrototypeKeys: PrimordialMethod, "keys">; +declare const $ArrayPrototypeEntries: PrimordialMethod, "entries">; +declare const $ArrayPrototypeFind: PrimordialMethod, "find">; +declare const $ArrayPrototypeFindLast: PrimordialMethod, "findLast">; +declare const $ArrayPrototypeFindIndex: PrimordialMethod, "findIndex">; +declare const $ArrayPrototypeFindLastIndex: PrimordialMethod, "findLastIndex">; +declare const $ArrayPrototypeIncludes: PrimordialMethod, "includes">; +declare const $ArrayPrototypeCopyWithin: PrimordialMethod, "copyWithin">; +declare const $ArrayPrototypeAt: PrimordialMethod, "at">; +declare const $ArrayPrototypeToReversed: PrimordialMethod, "toReversed">; +declare const $ArrayPrototypeToSorted: PrimordialMethod, "toSorted">; +declare const $ArrayPrototypeToSpliced: PrimordialMethod, "toSpliced">; +declare const $ArrayPrototypeWith: PrimordialMethod, "with">; +declare const $ArrayPrototypeConstructor: PrimordialMethod, "constructor">; +declare const $ArrayPrototypeSymbolIterator: PrimordialMethod, typeof Symbol.iterator>; +declare const $ArrayPrototypeSymbolUnscopables: PrimordialValue, typeof Symbol.unscopables>; +declare const $ArrayBufferPrimordial: ArrayBufferConstructor; +declare const $ArrayBufferPrototype: ArrayBuffer; +declare const $ArrayBufferIsView: PrimordialMethod; +declare const $ArrayBufferGetSymbolSpecies: PrimordialGetter; +declare const $ArrayBufferPrototypeSlice: PrimordialMethod; +declare const $ArrayBufferPrototypeGetByteLength: PrimordialGetter; +declare const $ArrayBufferPrototypeResize: PrimordialMethod; +declare const $ArrayBufferPrototypeTransfer: PrimordialMethod; +declare const $ArrayBufferPrototypeTransferToFixedLength: PrimordialMethod; +declare const $ArrayBufferPrototypeGetResizable: PrimordialGetter; +declare const $ArrayBufferPrototypeGetMaxByteLength: PrimordialGetter; +declare const $ArrayBufferPrototypeGetDetached: PrimordialGetter; +declare const $ArrayBufferPrototypeConstructor: PrimordialMethod; +declare const $BigInt: BigIntConstructor; +declare const $BigIntAsUintN: PrimordialMethod; +declare const $BigIntAsIntN: PrimordialMethod; +declare const $BigIntPrototype: BigInt; +declare const $BigIntPrototypeToString: PrimordialMethod; +declare const $BigIntPrototypeToLocaleString: PrimordialMethod; +declare const $BigIntPrototypeValueOf: PrimordialMethod; +declare const $BigIntPrototypeConstructor: PrimordialMethod; +declare const $BigInt64ArrayPrototype: BigInt64Array; +declare const $BigInt64ArrayPrototypeConstructor: PrimordialMethod; +declare const $BigUint64ArrayPrototype: BigUint64Array; +declare const $BigUint64ArrayPrototypeConstructor: PrimordialMethod; +declare const $Boolean: BooleanConstructor; +declare const $BooleanPrototype: Boolean; +declare const $BooleanPrototypeToString: PrimordialMethod; +declare const $BooleanPrototypeValueOf: PrimordialMethod; +declare const $BooleanPrototypeConstructor: PrimordialMethod; +declare const $DataView: DataViewConstructor; +declare const $DataViewPrototype: DataView; +declare const $DataViewPrototypeGetInt8: PrimordialMethod; +declare const $DataViewPrototypeGetUint8: PrimordialMethod; +declare const $DataViewPrototypeGetInt16: PrimordialMethod; +declare const $DataViewPrototypeGetUint16: PrimordialMethod; +declare const $DataViewPrototypeGetInt32: PrimordialMethod; +declare const $DataViewPrototypeGetUint32: PrimordialMethod; +declare const $DataViewPrototypeGetFloat16: PrimordialMethod; +declare const $DataViewPrototypeGetFloat32: PrimordialMethod; +declare const $DataViewPrototypeGetFloat64: PrimordialMethod; +declare const $DataViewPrototypeGetBigInt64: PrimordialMethod; +declare const $DataViewPrototypeGetBigUint64: PrimordialMethod; +declare const $DataViewPrototypeSetInt8: PrimordialMethod; +declare const $DataViewPrototypeSetUint8: PrimordialMethod; +declare const $DataViewPrototypeSetInt16: PrimordialMethod; +declare const $DataViewPrototypeSetUint16: PrimordialMethod; +declare const $DataViewPrototypeSetInt32: PrimordialMethod; +declare const $DataViewPrototypeSetUint32: PrimordialMethod; +declare const $DataViewPrototypeSetFloat16: PrimordialMethod; +declare const $DataViewPrototypeSetFloat32: PrimordialMethod; +declare const $DataViewPrototypeSetFloat64: PrimordialMethod; +declare const $DataViewPrototypeSetBigInt64: PrimordialMethod; +declare const $DataViewPrototypeSetBigUint64: PrimordialMethod; +declare const $DataViewPrototypeGetBuffer: PrimordialGetter; +declare const $DataViewPrototypeGetByteOffset: PrimordialGetter; +declare const $DataViewPrototypeGetByteLength: PrimordialGetter; +declare const $DataViewPrototypeConstructor: PrimordialMethod; +declare const $Date: DateConstructor; +declare const $DateParse: PrimordialMethod; +declare const $DateUTC: PrimordialMethod; +declare const $DateNow: PrimordialMethod; +declare const $DatePrototype: Date; +declare const $DatePrototypeToString: PrimordialMethod; +declare const $DatePrototypeToISOString: PrimordialMethod; +declare const $DatePrototypeToDateString: PrimordialMethod; +declare const $DatePrototypeToTimeString: PrimordialMethod; +declare const $DatePrototypeToLocaleString: PrimordialMethod; +declare const $DatePrototypeToLocaleDateString: PrimordialMethod; +declare const $DatePrototypeToLocaleTimeString: PrimordialMethod; +declare const $DatePrototypeValueOf: PrimordialMethod; +declare const $DatePrototypeGetTime: PrimordialMethod; +declare const $DatePrototypeGetFullYear: PrimordialMethod; +declare const $DatePrototypeGetUTCFullYear: PrimordialMethod; +declare const $DatePrototypeGetMonth: PrimordialMethod; +declare const $DatePrototypeGetUTCMonth: PrimordialMethod; +declare const $DatePrototypeGetDate: PrimordialMethod; +declare const $DatePrototypeGetUTCDate: PrimordialMethod; +declare const $DatePrototypeGetDay: PrimordialMethod; +declare const $DatePrototypeGetUTCDay: PrimordialMethod; +declare const $DatePrototypeGetHours: PrimordialMethod; +declare const $DatePrototypeGetUTCHours: PrimordialMethod; +declare const $DatePrototypeGetMinutes: PrimordialMethod; +declare const $DatePrototypeGetUTCMinutes: PrimordialMethod; +declare const $DatePrototypeGetSeconds: PrimordialMethod; +declare const $DatePrototypeGetUTCSeconds: PrimordialMethod; +declare const $DatePrototypeGetMilliseconds: PrimordialMethod; +declare const $DatePrototypeGetUTCMilliseconds: PrimordialMethod; +declare const $DatePrototypeGetTimezoneOffset: PrimordialMethod; +declare const $DatePrototypeGetYear: PrimordialMethod; +declare const $DatePrototypeSetTime: PrimordialMethod; +declare const $DatePrototypeSetMilliseconds: PrimordialMethod; +declare const $DatePrototypeSetUTCMilliseconds: PrimordialMethod; +declare const $DatePrototypeSetSeconds: PrimordialMethod; +declare const $DatePrototypeSetUTCSeconds: PrimordialMethod; +declare const $DatePrototypeSetMinutes: PrimordialMethod; +declare const $DatePrototypeSetUTCMinutes: PrimordialMethod; +declare const $DatePrototypeSetHours: PrimordialMethod; +declare const $DatePrototypeSetUTCHours: PrimordialMethod; +declare const $DatePrototypeSetDate: PrimordialMethod; +declare const $DatePrototypeSetUTCDate: PrimordialMethod; +declare const $DatePrototypeSetMonth: PrimordialMethod; +declare const $DatePrototypeSetUTCMonth: PrimordialMethod; +declare const $DatePrototypeSetFullYear: PrimordialMethod; +declare const $DatePrototypeSetUTCFullYear: PrimordialMethod; +declare const $DatePrototypeSetYear: PrimordialMethod; +declare const $DatePrototypeToJSON: PrimordialMethod; +declare const $DatePrototypeToUTCString: PrimordialMethod; +declare const $DatePrototypeToGMTString: PrimordialMethod; +declare const $DatePrototypeConstructor: PrimordialMethod; +declare const $DatePrototypeSymbolToPrimitive: PrimordialMethod; +declare const $Error: ErrorConstructor; +declare const $ErrorPrototype: Error; +declare const $ErrorCaptureStackTrace: PrimordialMethod; +declare const $ErrorIsError: PrimordialMethod; +declare const $ErrorAppendStackTrace: PrimordialMethod; +declare const $ErrorPrepareStackTrace: PrimordialMethod; +declare const $ErrorPrototypeToString: PrimordialMethod; +declare const $ErrorPrototypeConstructor: PrimordialMethod; +declare const $EvalError: ErrorConstructor; +declare const $EvalErrorPrototype: Error; +declare const $EvalErrorPrototypeConstructor: PrimordialMethod; +declare const $FinalizationRegistry: FinalizationRegistryConstructor; +declare const $FinalizationRegistryPrototype: FinalizationRegistry; +declare const $FinalizationRegistryPrototypeRegister: PrimordialMethod, "register">; +declare const $FinalizationRegistryPrototypeUnregister: PrimordialMethod, "unregister">; +declare const $FinalizationRegistryPrototypeConstructor: PrimordialMethod, "constructor">; +declare const $Float16ArrayPrototype: Float16Array; +declare const $Float16ArrayPrototypeConstructor: PrimordialMethod; +declare const $Float32ArrayPrototype: Float32Array; +declare const $Float32ArrayPrototypeConstructor: PrimordialMethod; +declare const $Float64ArrayPrototype: Float64Array; +declare const $Float64ArrayPrototypeConstructor: PrimordialMethod; +declare const $Function: FunctionConstructor; +declare const $FunctionPrototype: PrimordialMethod; +declare const $FunctionPrototypeToString: PrimordialMethod; +declare const $FunctionPrototypeApply: PrimordialMethod; +declare const $FunctionPrototypeCall: PrimordialMethod; +declare const $FunctionPrototypeBind: PrimordialMethod; +declare const $FunctionPrototypeGetArguments: PrimordialGetter; +declare const $FunctionPrototypeSetArguments: PrimordialSetter; +declare const $FunctionPrototypeGetCaller: PrimordialGetter; +declare const $FunctionPrototypeSetCaller: PrimordialSetter; +declare const $FunctionPrototypeConstructor: PrimordialMethod; +declare const $FunctionPrototypeSymbolHasInstance: PrimordialMethod; +declare const $Int16ArrayPrototype: Int16Array; +declare const $Int16ArrayPrototypeConstructor: PrimordialMethod; +declare const $Int32ArrayPrototype: Int32Array; +declare const $Int32ArrayPrototypeConstructor: PrimordialMethod; +declare const $Int8ArrayPrototype: Int8Array; +declare const $Int8ArrayPrototypeConstructor: PrimordialMethod; +declare const $IteratorPrototype: IteratorObject; +declare const $IteratorFrom: PrimordialMethod; +declare const $IteratorConcat: PrimordialMethod; +declare const $IteratorPrototypeGetConstructor: PrimordialGetter, "constructor">; +declare const $IteratorPrototypeSetConstructor: PrimordialSetter, "constructor">; +declare const $IteratorPrototypeToArray: PrimordialMethod, "toArray">; +declare const $IteratorPrototypeForEach: PrimordialMethod, "forEach">; +declare const $IteratorPrototypeSome: PrimordialMethod, "some">; +declare const $IteratorPrototypeEvery: PrimordialMethod, "every">; +declare const $IteratorPrototypeFind: PrimordialMethod, "find">; +declare const $IteratorPrototypeReduce: PrimordialMethod, "reduce">; +declare const $IteratorPrototypeMap: PrimordialMethod, "map">; +declare const $IteratorPrototypeFilter: PrimordialMethod, "filter">; +declare const $IteratorPrototypeTake: PrimordialMethod, "take">; +declare const $IteratorPrototypeDrop: PrimordialMethod, "drop">; +declare const $IteratorPrototypeFlatMap: PrimordialMethod, "flatMap">; +declare const $IteratorPrototypeIncludes: PrimordialMethod, "includes">; +declare const $IteratorPrototypeSymbolIterator: PrimordialMethod, typeof Symbol.iterator>; +declare const $IteratorPrototypeGetSymbolToStringTag: PrimordialGetter, typeof Symbol.toStringTag>; +declare const $IteratorPrototypeSetSymbolToStringTag: PrimordialSetter, typeof Symbol.toStringTag>; +declare const $IteratorPrototypeSymbolDispose: PrimordialMethod, typeof Symbol.dispose>; +declare const $MapPrototype: Map; +declare const $MapGroupBy: PrimordialMethod; +declare const $MapGetSymbolSpecies: PrimordialGetter; +declare const $MapPrototypeClear: PrimordialMethod, "clear">; +declare const $MapPrototypeDelete: PrimordialMethod, "delete">; +declare const $MapPrototypeEntries: PrimordialMethod, "entries">; +declare const $MapPrototypeForEach: PrimordialMethod, "forEach">; +declare const $MapPrototypeGet: PrimordialMethod, "get">; +declare const $MapPrototypeHas: PrimordialMethod, "has">; +declare const $MapPrototypeKeys: PrimordialMethod, "keys">; +declare const $MapPrototypeSet: PrimordialMethod, "set">; +declare const $MapPrototypeGetOrInsert: PrimordialMethod, "getOrInsert">; +declare const $MapPrototypeGetOrInsertComputed: PrimordialMethod, "getOrInsertComputed">; +declare const $MapPrototypeGetSize: PrimordialGetter, "size">; +declare const $MapPrototypeValues: PrimordialMethod, "values">; +declare const $MapPrototypeConstructor: PrimordialMethod, "constructor">; +declare const $MapPrototypeSymbolIterator: PrimordialMethod, typeof Symbol.iterator>; +declare const $NumberPrimordial: NumberConstructor; +declare const $NumberIsFinite: PrimordialMethod; +declare const $NumberIsNaN: PrimordialMethod; +declare const $NumberIsSafeInteger: PrimordialMethod; +declare const $NumberPrototype: Number; +declare const $NumberParseInt: PrimordialMethod; +declare const $NumberParseFloat: PrimordialMethod; +declare const $NumberIsInteger: PrimordialMethod; +declare const $NumberPrototypeToLocaleString: PrimordialMethod; +declare const $NumberPrototypeValueOf: PrimordialMethod; +declare const $NumberPrototypeToFixed: PrimordialMethod; +declare const $NumberPrototypeToExponential: PrimordialMethod; +declare const $NumberPrototypeToPrecision: PrimordialMethod; +declare const $NumberPrototypeToString: PrimordialMethod; +declare const $NumberPrototypeConstructor: PrimordialMethod; +declare const $ObjectGetPrototypeOf: PrimordialMethod; +declare const $ObjectSetPrototypeOf: PrimordialMethod; +declare const $ObjectGetOwnPropertyDescriptor: PrimordialMethod; +declare const $ObjectGetOwnPropertyDescriptors: PrimordialMethod; +declare const $ObjectGetOwnPropertyNames: PrimordialMethod; +declare const $ObjectGetOwnPropertySymbols: PrimordialMethod; +declare const $ObjectKeys: PrimordialMethod; +declare const $ObjectDefineProperty: PrimordialMethod; +declare const $ObjectDefineProperties: PrimordialMethod; +declare const $ObjectCreate: PrimordialMethod; +declare const $ObjectSeal: PrimordialMethod; +declare const $ObjectFreeze: PrimordialMethod; +declare const $ObjectPreventExtensions: PrimordialMethod; +declare const $ObjectIsSealed: PrimordialMethod; +declare const $ObjectIsFrozen: PrimordialMethod; +declare const $ObjectIsExtensible: PrimordialMethod; +declare const $ObjectIs: PrimordialMethod; +declare const $ObjectAssign: PrimordialMethod; +declare const $ObjectValues: PrimordialMethod; +declare const $ObjectEntries: PrimordialMethod; +declare const $ObjectFromEntries: PrimordialMethod; +declare const $ObjectPrototype: Object; +declare const $ObjectHasOwn: PrimordialMethod; +declare const $ObjectGroupBy: PrimordialMethod; +declare const $ObjectPrototypeToString: PrimordialMethod; +declare const $ObjectPrototypeToLocaleString: PrimordialMethod; +declare const $ObjectPrototypeValueOf: PrimordialMethod; +declare const $ObjectPrototypeHasOwnProperty: PrimordialMethod; +declare const $ObjectPrototypePropertyIsEnumerable: PrimordialMethod; +declare const $ObjectPrototypeIsPrototypeOf: PrimordialMethod; +declare const $ObjectPrototype__defineGetter__: PrimordialMethod; +declare const $ObjectPrototype__defineSetter__: PrimordialMethod; +declare const $ObjectPrototype__lookupGetter__: PrimordialMethod; +declare const $ObjectPrototype__lookupSetter__: PrimordialMethod; +declare const $ObjectPrototypeGet__proto__: PrimordialGetter; +declare const $ObjectPrototypeSet__proto__: PrimordialSetter; +declare const $ObjectPrototypeConstructor: PrimordialMethod; +declare const $RangeError: ErrorConstructor; +declare const $RangeErrorPrototype: Error; +declare const $RangeErrorPrototypeConstructor: PrimordialMethod; +declare const $ReferenceErrorPrototype: Error; +declare const $ReferenceErrorPrototypeConstructor: PrimordialMethod; +declare const $RegExpGetInput: PrimordialGetter; +declare const $RegExpSetInput: PrimordialSetter; +declare const $RegExpGetDollarUnderscore: PrimordialGetter; +declare const $RegExpSetDollarUnderscore: PrimordialSetter; +declare const $RegExpGetMultiline: PrimordialGetter; +declare const $RegExpSetMultiline: PrimordialSetter; +declare const $RegExpGetDollarAsterisk: PrimordialGetter; +declare const $RegExpSetDollarAsterisk: PrimordialSetter; +declare const $RegExpGetLastMatch: PrimordialGetter; +declare const $RegExpGetDollarAmpersand: PrimordialGetter; +declare const $RegExpGetLastParen: PrimordialGetter; +declare const $RegExpGetDollarPlus: PrimordialGetter; +declare const $RegExpGetLeftContext: PrimordialGetter; +declare const $RegExpGetDollarBacktick: PrimordialGetter; +declare const $RegExpGetRightContext: PrimordialGetter; +declare const $RegExpGetDollarApostrophe: PrimordialGetter; +declare const $RegExpGetDollar1: PrimordialGetter; +declare const $RegExpGetDollar2: PrimordialGetter; +declare const $RegExpGetDollar3: PrimordialGetter; +declare const $RegExpGetDollar4: PrimordialGetter; +declare const $RegExpGetDollar5: PrimordialGetter; +declare const $RegExpGetDollar6: PrimordialGetter; +declare const $RegExpGetDollar7: PrimordialGetter; +declare const $RegExpGetDollar8: PrimordialGetter; +declare const $RegExpGetDollar9: PrimordialGetter; +declare const $RegExpPrototype: RegExp; +declare const $RegExpEscape: PrimordialMethod; +declare const $RegExpGetSymbolSpecies: PrimordialGetter; +declare const $RegExpPrototypeCompile: PrimordialMethod; +declare const $RegExpPrototypeExec: PrimordialMethod; +declare const $RegExpPrototypeToString: PrimordialMethod; +declare const $RegExpPrototypeGetGlobal: PrimordialGetter; +declare const $RegExpPrototypeGetDotAll: PrimordialGetter; +declare const $RegExpPrototypeGetHasIndices: PrimordialGetter; +declare const $RegExpPrototypeGetIgnoreCase: PrimordialGetter; +declare const $RegExpPrototypeGetMultiline: PrimordialGetter; +declare const $RegExpPrototypeGetSticky: PrimordialGetter; +declare const $RegExpPrototypeGetUnicode: PrimordialGetter; +declare const $RegExpPrototypeGetUnicodeSets: PrimordialGetter; +declare const $RegExpPrototypeGetSource: PrimordialGetter; +declare const $RegExpPrototypeGetFlags: PrimordialGetter; +declare const $RegExpPrototypeTest: PrimordialMethod; +declare const $RegExpPrototypeConstructor: PrimordialMethod; +declare const $RegExpPrototypeSymbolMatch: PrimordialMethod; +declare const $RegExpPrototypeSymbolMatchAll: PrimordialMethod; +declare const $RegExpPrototypeSymbolReplace: PrimordialMethod; +declare const $RegExpPrototypeSymbolSearch: PrimordialMethod; +declare const $RegExpPrototypeSymbolSplit: PrimordialMethod; +declare const $SetPrototype: Set; +declare const $SetGetSymbolSpecies: PrimordialGetter; +declare const $SetPrototypeAdd: PrimordialMethod, "add">; +declare const $SetPrototypeClear: PrimordialMethod, "clear">; +declare const $SetPrototypeDelete: PrimordialMethod, "delete">; +declare const $SetPrototypeEntries: PrimordialMethod, "entries">; +declare const $SetPrototypeForEach: PrimordialMethod, "forEach">; +declare const $SetPrototypeHas: PrimordialMethod, "has">; +declare const $SetPrototypeKeys: PrimordialMethod, "keys">; +declare const $SetPrototypeGetSize: PrimordialGetter, "size">; +declare const $SetPrototypeValues: PrimordialMethod, "values">; +declare const $SetPrototypeUnion: PrimordialMethod, "union">; +declare const $SetPrototypeIntersection: PrimordialMethod, "intersection">; +declare const $SetPrototypeDifference: PrimordialMethod, "difference">; +declare const $SetPrototypeSymmetricDifference: PrimordialMethod, "symmetricDifference">; +declare const $SetPrototypeIsSubsetOf: PrimordialMethod, "isSubsetOf">; +declare const $SetPrototypeIsSupersetOf: PrimordialMethod, "isSupersetOf">; +declare const $SetPrototypeIsDisjointFrom: PrimordialMethod, "isDisjointFrom">; +declare const $SetPrototypeConstructor: PrimordialMethod, "constructor">; +declare const $SetPrototypeSymbolIterator: PrimordialMethod, typeof Symbol.iterator>; +declare const $StringFromCharCode: PrimordialMethod; +declare const $StringFromCodePoint: PrimordialMethod; +declare const $StringRaw: PrimordialMethod; +declare const $StringPrototype: String; +declare const $StringPrototypeAnchor: PrimordialMethod; +declare const $StringPrototypeBig: PrimordialMethod; +declare const $StringPrototypeBold: PrimordialMethod; +declare const $StringPrototypeBlink: PrimordialMethod; +declare const $StringPrototypeFixed: PrimordialMethod; +declare const $StringPrototypeFontcolor: PrimordialMethod; +declare const $StringPrototypeFontsize: PrimordialMethod; +declare const $StringPrototypeItalics: PrimordialMethod; +declare const $StringPrototypeLink: PrimordialMethod; +declare const $StringPrototypeSmall: PrimordialMethod; +declare const $StringPrototypeStrike: PrimordialMethod; +declare const $StringPrototypeSub: PrimordialMethod; +declare const $StringPrototypeSup: PrimordialMethod; +declare const $StringPrototypeToString: PrimordialMethod; +declare const $StringPrototypeValueOf: PrimordialMethod; +declare const $StringPrototypeCharAt: PrimordialMethod; +declare const $StringPrototypeCharCodeAt: PrimordialMethod; +declare const $StringPrototypeCodePointAt: PrimordialMethod; +declare const $StringPrototypeConcat: PrimordialMethod; +declare const $StringPrototypeIndexOf: PrimordialMethod; +declare const $StringPrototypeLastIndexOf: PrimordialMethod; +declare const $StringPrototypeReplace: PrimordialMethod; +declare const $StringPrototypeReplaceAll: PrimordialMethod; +declare const $StringPrototypeRepeat: PrimordialMethod; +declare const $StringPrototypePadStart: PrimordialMethod; +declare const $StringPrototypePadEnd: PrimordialMethod; +declare const $StringPrototypeSlice: PrimordialMethod; +declare const $StringPrototypeSubstr: PrimordialMethod; +declare const $StringPrototypeAt: PrimordialMethod; +declare const $StringPrototypeSubstring: PrimordialMethod; +declare const $StringPrototypeToLowerCase: PrimordialMethod; +declare const $StringPrototypeToUpperCase: PrimordialMethod; +declare const $StringPrototypeLocaleCompare: PrimordialMethod; +declare const $StringPrototypeToLocaleLowerCase: PrimordialMethod; +declare const $StringPrototypeToLocaleUpperCase: PrimordialMethod; +declare const $StringPrototypeTrim: PrimordialMethod; +declare const $StringPrototypeStartsWith: PrimordialMethod; +declare const $StringPrototypeEndsWith: PrimordialMethod; +declare const $StringPrototypeIncludes: PrimordialMethod; +declare const $StringPrototypeMatch: PrimordialMethod; +declare const $StringPrototypeSearch: PrimordialMethod; +declare const $StringPrototypeMatchAll: PrimordialMethod; +declare const $StringPrototypeSplit: PrimordialMethod; +declare const $StringPrototypeNormalize: PrimordialMethod; +declare const $StringPrototypeTrimStart: PrimordialMethod; +declare const $StringPrototypeTrimLeft: PrimordialMethod; +declare const $StringPrototypeTrimEnd: PrimordialMethod; +declare const $StringPrototypeTrimRight: PrimordialMethod; +declare const $StringPrototypeIsWellFormed: PrimordialMethod; +declare const $StringPrototypeToWellFormed: PrimordialMethod; +declare const $StringPrototypeConstructor: PrimordialMethod; +declare const $StringPrototypeSymbolIterator: PrimordialMethod; +declare const $Symbol: SymbolConstructor; +declare const $SymbolFor: PrimordialMethod; +declare const $SymbolKeyFor: PrimordialMethod; +declare const $SymbolPrototype: Symbol; +declare const $SymbolHasInstance: PrimordialValue; +declare const $SymbolIsConcatSpreadable: PrimordialValue; +declare const $SymbolAsyncIterator: PrimordialValue; +declare const $SymbolIterator: PrimordialValue; +declare const $SymbolMatch: PrimordialValue; +declare const $SymbolMatchAll: PrimordialValue; +declare const $SymbolReplace: PrimordialValue; +declare const $SymbolSearch: PrimordialValue; +declare const $SymbolSpecies: PrimordialValue; +declare const $SymbolSplit: PrimordialValue; +declare const $SymbolToPrimitive: PrimordialValue; +declare const $SymbolToStringTag: PrimordialValue; +declare const $SymbolUnscopables: PrimordialValue; +declare const $SymbolDispose: PrimordialValue; +declare const $SymbolAsyncDispose: PrimordialValue; +declare const $SymbolPrototypeGetDescription: PrimordialGetter; +declare const $SymbolPrototypeToString: PrimordialMethod; +declare const $SymbolPrototypeValueOf: PrimordialMethod; +declare const $SymbolPrototypeConstructor: PrimordialMethod; +declare const $SymbolPrototypeSymbolToPrimitive: PrimordialMethod; +declare const $SyntaxError: ErrorConstructor; +declare const $SyntaxErrorPrototype: Error; +declare const $SyntaxErrorPrototypeConstructor: PrimordialMethod; +declare const $TypeError: ErrorConstructor; +declare const $TypeErrorPrototype: Error; +declare const $TypeErrorPrototypeConstructor: PrimordialMethod; +declare const $URIError: ErrorConstructor; +declare const $URIErrorPrototype: Error; +declare const $URIErrorPrototypeConstructor: PrimordialMethod; +declare const $Uint16ArrayPrototype: Uint16Array; +declare const $Uint16ArrayPrototypeConstructor: PrimordialMethod; +declare const $Uint32ArrayPrototype: Uint32Array; +declare const $Uint32ArrayPrototypeConstructor: PrimordialMethod; +declare const $Uint8ArrayPrototype: Uint8Array; +declare const $Uint8ArrayFromBase64: PrimordialMethod; +declare const $Uint8ArrayFromHex: PrimordialMethod; +declare const $Uint8ArrayPrototypeSetFromBase64: PrimordialMethod; +declare const $Uint8ArrayPrototypeSetFromHex: PrimordialMethod; +declare const $Uint8ArrayPrototypeToBase64: PrimordialMethod; +declare const $Uint8ArrayPrototypeToHex: PrimordialMethod; +declare const $Uint8ArrayPrototypeConstructor: PrimordialMethod; +declare const $Uint8ClampedArrayPrototype: Uint8ClampedArray; +declare const $Uint8ClampedArrayPrototypeConstructor: PrimordialMethod; +declare const $WeakMap: WeakMapConstructor; +declare const $WeakMapPrototype: WeakMap; +declare const $WeakMapPrototypeDelete: PrimordialMethod, "delete">; +declare const $WeakMapPrototypeGet: PrimordialMethod, "get">; +declare const $WeakMapPrototypeHas: PrimordialMethod, "has">; +declare const $WeakMapPrototypeSet: PrimordialMethod, "set">; +declare const $WeakMapPrototypeGetOrInsert: PrimordialMethod, "getOrInsert">; +declare const $WeakMapPrototypeGetOrInsertComputed: PrimordialMethod, "getOrInsertComputed">; +declare const $WeakMapPrototypeConstructor: PrimordialMethod, "constructor">; +declare const $WeakRef: WeakRefConstructor; +declare const $WeakRefPrototype: WeakRef; +declare const $WeakRefPrototypeDeref: PrimordialMethod, "deref">; +declare const $WeakRefPrototypeConstructor: PrimordialMethod, "constructor">; +declare const $WeakSet: WeakSetConstructor; +declare const $WeakSetPrototype: WeakSet; +declare const $WeakSetPrototypeDelete: PrimordialMethod, "delete">; +declare const $WeakSetPrototypeHas: PrimordialMethod, "has">; +declare const $WeakSetPrototypeAdd: PrimordialMethod, "add">; +declare const $WeakSetPrototypeConstructor: PrimordialMethod, "constructor">; +declare const $PromiseResolve: PrimordialMethod; +declare const $PromiseReject: PrimordialMethod; +declare const $PromiseRace: PrimordialMethod; +declare const $PromiseAll: PrimordialMethod; +declare const $PromiseAllSettled: PrimordialMethod; +declare const $PromiseAny: PrimordialMethod; +declare const $PromiseWithResolvers: PrimordialMethod; +declare const $PromisePrototype: Promise; +declare const $PromiseTry: PrimordialMethod; +declare const $PromiseGetSymbolSpecies: PrimordialGetter; +declare const $PromisePrototypeFinally: PrimordialMethod, "finally">; +declare const $PromisePrototypeThen: PrimordialMethod, "then">; +declare const $PromisePrototypeCatch: PrimordialMethod, "catch">; +declare const $PromisePrototypeConstructor: PrimordialMethod, "constructor">; +declare const $TypedArray: Uint8ArrayConstructor; +declare const $TypedArrayPrototype: Uint8Array; +declare const $TypedArrayOf: PrimordialMethod; +declare const $TypedArrayFrom: PrimordialMethod; +declare const $TypedArrayGetSymbolSpecies: PrimordialGetter; +declare const $TypedArrayPrototypeToString: PrimordialMethod; +declare const $TypedArrayPrototypeGetBuffer: PrimordialGetter; +declare const $TypedArrayPrototypeGetByteLength: PrimordialGetter; +declare const $TypedArrayPrototypeGetByteOffset: PrimordialGetter; +declare const $TypedArrayPrototypeCopyWithin: PrimordialMethod; +declare const $TypedArrayPrototypeSort: PrimordialMethod; +declare const $TypedArrayPrototypeEvery: PrimordialMethod; +declare const $TypedArrayPrototypeFilter: PrimordialMethod; +declare const $TypedArrayPrototypeEntries: PrimordialMethod; +declare const $TypedArrayPrototypeIncludes: PrimordialMethod; +declare const $TypedArrayPrototypeFill: PrimordialMethod; +declare const $TypedArrayPrototypeFind: PrimordialMethod; +declare const $TypedArrayPrototypeFindLast: PrimordialMethod; +declare const $TypedArrayPrototypeFindIndex: PrimordialMethod; +declare const $TypedArrayPrototypeFindLastIndex: PrimordialMethod; +declare const $TypedArrayPrototypeForEach: PrimordialMethod; +declare const $TypedArrayPrototypeIndexOf: PrimordialMethod; +declare const $TypedArrayPrototypeJoin: PrimordialMethod; +declare const $TypedArrayPrototypeKeys: PrimordialMethod; +declare const $TypedArrayPrototypeLastIndexOf: PrimordialMethod; +declare const $TypedArrayPrototypeGetLength: PrimordialGetter; +declare const $TypedArrayPrototypeMap: PrimordialMethod; +declare const $TypedArrayPrototypeReduce: PrimordialMethod; +declare const $TypedArrayPrototypeReduceRight: PrimordialMethod; +declare const $TypedArrayPrototypeReverse: PrimordialMethod; +declare const $TypedArrayPrototypeSet: PrimordialMethod; +declare const $TypedArrayPrototypeSlice: PrimordialMethod; +declare const $TypedArrayPrototypeSome: PrimordialMethod; +declare const $TypedArrayPrototypeSubarray: PrimordialMethod; +declare const $TypedArrayPrototypeToLocaleString: PrimordialMethod; +declare const $TypedArrayPrototypeToReversed: PrimordialMethod; +declare const $TypedArrayPrototypeToSorted: PrimordialMethod; +declare const $TypedArrayPrototypeWith: PrimordialMethod; +declare const $TypedArrayPrototypeAt: PrimordialMethod; +declare const $TypedArrayPrototypeValues: PrimordialMethod; +declare const $TypedArrayPrototypeConstructor: PrimordialMethod; +declare const $TypedArrayPrototypeGetSymbolToStringTag: PrimordialGetter; +declare const $TypedArrayPrototypeSymbolIterator: PrimordialMethod; +declare const $ArrayIteratorPrototype: ArrayIterator; +declare const $ArrayIteratorPrototypeNext: PrimordialMethod, "next">; +declare const $AsyncFunctionPrototype: Function; +declare const $AsyncFunctionPrototypeConstructor: PrimordialMethod; +declare const $AsyncGeneratorFunctionPrototype: AsyncGeneratorFunction; +declare const $AsyncGeneratorFunctionPrototypeConstructor: PrimordialMethod; +declare const $AsyncGeneratorFunctionPrototypePrototype: PrimordialValue; +declare const $AsyncIteratorPrototype: AsyncIteratorObject; +declare const $AsyncIteratorPrototypeSymbolAsyncIterator: PrimordialMethod< + AsyncIteratorObject, + typeof Symbol.asyncIterator +>; +declare const $AsyncIteratorPrototypeSymbolAsyncDispose: PrimordialMethod< + AsyncIteratorObject, + typeof Symbol.asyncDispose +>; +declare const $GeneratorFunctionPrototype: GeneratorFunction; +declare const $GeneratorFunctionPrototypeConstructor: PrimordialMethod; +declare const $GeneratorFunctionPrototypePrototype: PrimordialValue; +declare const $IteratorHelperPrototype: IteratorObject; +declare const $IteratorHelperPrototypeNext: PrimordialMethod, "next">; +declare const $IteratorHelperPrototypeReturn: PrimordialMethod, "return">; +declare const $MapIteratorPrototype: MapIterator; +declare const $MapIteratorPrototypeNext: PrimordialMethod, "next">; +declare const $RegExpStringIteratorPrototype: RegExpStringIterator; +declare const $RegExpStringIteratorPrototypeNext: PrimordialMethod, "next">; +declare const $SetIteratorPrototype: SetIterator; +declare const $SetIteratorPrototypeNext: PrimordialMethod, "next">; +declare const $StringIteratorPrototype: StringIterator; +declare const $StringIteratorPrototypeNext: PrimordialMethod, "next">; +declare const $WrapForValidIteratorPrototype: IteratorObject; +declare const $WrapForValidIteratorPrototypeNext: PrimordialMethod, "next">; +declare const $WrapForValidIteratorPrototypeReturn: PrimordialMethod, "return">; diff --git a/src/jsc/bindings/PrimordialsAudit.cpp b/src/jsc/bindings/PrimordialsAudit.cpp new file mode 100644 index 000000000000..db52e04a5b29 --- /dev/null +++ b/src/jsc/bindings/PrimordialsAudit.cpp @@ -0,0 +1,14 @@ +#include "root.h" + +#include "PrimordialsAudit.h" + +#include + +namespace Bun { + +BUN_DEFINE_HOST_FUNCTION(Bun__primordialsAudit, (JSC::JSGlobalObject * globalObject, JSC::CallFrame*)) +{ + return JSC::JSValue::encode(JSC::JSGlobalObject::auditPrimordials(globalObject)); +} + +} // namespace Bun diff --git a/src/jsc/bindings/PrimordialsAudit.h b/src/jsc/bindings/PrimordialsAudit.h new file mode 100644 index 000000000000..b1d60e4ca504 --- /dev/null +++ b/src/jsc/bindings/PrimordialsAudit.h @@ -0,0 +1,11 @@ +#pragma once + +#include "root.h" + +namespace Bun { + +// Exposed through `bun:internal-for-testing`: materializes every JSC +// primordial link-time constant and returns their manifest and values. +BUN_DECLARE_HOST_FUNCTION(Bun__primordialsAudit); + +} // namespace Bun diff --git a/src/jsc/bindings/ZigGlobalObject.cpp b/src/jsc/bindings/ZigGlobalObject.cpp index a3aa700f0fbe..35b69e2e8f1e 100644 --- a/src/jsc/bindings/ZigGlobalObject.cpp +++ b/src/jsc/bindings/ZigGlobalObject.cpp @@ -6,6 +6,7 @@ #include "JavaScriptCore/JSCellButterfly.h" #include "wtf/text/Base64.h" #include "JavaScriptCore/BuiltinNames.h" +#include "JavaScriptCore/JSCPrimordials.h" #include "JavaScriptCore/CallData.h" #include "JavaScriptCore/TopExceptionScope.h" #include "JavaScriptCore/ClassInfo.h" @@ -3197,6 +3198,8 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) errorConstructor->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "captureStackTrace"_s), 2, errorConstructorFuncCaptureStackTrace, ImplementationVisibility::Public, JSC::NoIntrinsic, PropertyAttribute::DontEnum | 0); errorConstructor->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "appendStackTrace"_s), 2, errorConstructorFuncAppendStackTrace, ImplementationVisibility::Private, JSC::NoIntrinsic, PropertyAttribute::DontEnum | 0); errorConstructor->putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "prepareStackTrace"_s), JSC::CustomGetterSetter::create(vm, errorConstructorPrepareStackTraceGetter, errorConstructorPrepareStackTraceSetter), PropertyAttribute::DontEnum | PropertyAttribute::CustomValue); + // Error.captureStackTrace was replaced above; the primordial should be what user code sees. + this->overridePrimordialsFromHolder(vm, errorConstructor, JSC::PrimordialHolder::ErrorConstructor); JSC::JSObject* consoleObject = this->get(this, JSC::Identifier::fromString(vm, "console"_s)).getObject(); scope.assertNoExceptionExceptTermination(); diff --git a/test/js/bun/util/primordials.test.ts b/test/js/bun/util/primordials.test.ts new file mode 100644 index 000000000000..eaf105bd0010 --- /dev/null +++ b/test/js/bun/util/primordials.test.ts @@ -0,0 +1,991 @@ +import { describe, expect, test } from "bun:test"; +import { bunEnv, bunExe } from "harness"; + +// JSC exposes tamper-proof references to the original builtins ("primordials", +// JSCPrimordials.h, generated by src/codegen/generate-primordials.ts) to Bun's +// builtin JavaScript as `$Name` link-time constants, and internal/primordials +// assembles them into Node's `primordials` object for ported lib/ code. +// +// `bun:internal-for-testing` exposes both for tests: primordials.audit() returns +// { name, holder, kind, key, value, available } for every engine entry, straight +// from JSC, and primordials.object is the module object. Every check below iterates +// the whole manifest instead of a hand-picked subset. +// +// Everything a child script does after it starts tampering must itself be immune +// to the tampering: helpers are captured in the prelude, loops are index-based (no +// array iterators), descriptors are null-prototype objects, and reports are built +// with the captured JSON.stringify. + +const prelude = /* js */ ` + const { primordials } = require("bun:internal-for-testing"); + const audit = primordials.audit; + const write = process.stdout.write.bind(process.stdout); + const exit = process.exit.bind(process); + const stringify = JSON.stringify; + const report = (obj) => write(stringify(obj) + "\\n"); + // For the tampering scenarios: Bun's own builtin JS is not primordial-hardened + // yet, so a normal shutdown after tampering can throw; report, then exit. + const reportAndExit = (obj) => { report(obj); exit(0); }; + const globalObject = globalThis; + const ownDesc = Object.getOwnPropertyDescriptor; + const getProto = Object.getPrototypeOf; + const setProto = Object.setPrototypeOf; + const defineProperty = Object.defineProperty; + const seal = Object.seal; + const freeze = Object.freeze; + const objectKeys = Object.keys; + const ownKeys = Reflect.ownKeys; + const reflectSet = Reflect.set; + const $apply = Reflect.apply; + const protoOf = f => getProto(f()); + const TypedArray = getProto(Uint8Array); + const holderFactories = { + GlobalObject: () => globalObject, + ObjectPrototype: () => Object.prototype, + ObjectConstructor: () => Object, + FunctionPrototype: () => Function.prototype, + FunctionConstructor: () => Function, + ArrayPrototype: () => Array.prototype, + ArrayConstructor: () => Array, + StringPrototype: () => String.prototype, + StringConstructor: () => String, + RegExpPrototype: () => RegExp.prototype, + RegExpConstructor: () => RegExp, + SymbolPrototype: () => Symbol.prototype, + SymbolConstructor: () => Symbol, + BigIntPrototype: () => BigInt.prototype, + BigIntConstructor: () => BigInt, + PromisePrototype: () => Promise.prototype, + PromiseConstructor: () => Promise, + IteratorPrototype: () => Iterator.prototype, + IteratorConstructor: () => Iterator, + ArrayIteratorPrototype: () => protoOf(() => [][Symbol.iterator]()), + StringIteratorPrototype: () => protoOf(() => ""[Symbol.iterator]()), + MapIteratorPrototype: () => protoOf(() => new Map()[Symbol.iterator]()), + SetIteratorPrototype: () => protoOf(() => new Set()[Symbol.iterator]()), + RegExpStringIteratorPrototype: () => protoOf(() => "a".matchAll(/a/g)), + IteratorHelperPrototype: () => protoOf(() => [].values().map(x => x)), + WrapForValidIteratorPrototype: () => protoOf(() => Iterator.from({ next() { return { done: true }; } })), + AsyncIteratorPrototype: () => getProto(getProto(async function* () {}).prototype), + GeneratorFunctionPrototype: () => getProto(function* () {}), + AsyncFunctionPrototype: () => getProto(async function () {}), + AsyncGeneratorFunctionPrototype: () => getProto(async function* () {}), + WeakRefPrototype: () => WeakRef.prototype, + WeakRefConstructor: () => WeakRef, + FinalizationRegistryPrototype: () => FinalizationRegistry.prototype, + FinalizationRegistryConstructor: () => FinalizationRegistry, + BooleanPrototype: () => Boolean.prototype, + BooleanConstructor: () => Boolean, + NumberPrototype: () => Number.prototype, + NumberConstructor: () => Number, + DatePrototype: () => Date.prototype, + DateConstructor: () => Date, + ErrorPrototype: () => Error.prototype, + ErrorConstructor: () => Error, + MapPrototype: () => Map.prototype, + MapConstructor: () => Map, + SetPrototype: () => Set.prototype, + SetConstructor: () => Set, + WeakMapPrototype: () => WeakMap.prototype, + WeakMapConstructor: () => WeakMap, + WeakSetPrototype: () => WeakSet.prototype, + WeakSetConstructor: () => WeakSet, + ArrayBufferPrototype: () => ArrayBuffer.prototype, + ArrayBufferConstructor: () => ArrayBuffer, + TypedArrayPrototype: () => TypedArray.prototype, + TypedArrayConstructor: () => TypedArray, + DataViewPrototype: () => DataView.prototype, + DataViewConstructor: () => DataView, + MathObject: () => Math, + JSONObject: () => JSON, + ReflectObject: () => Reflect, + AtomicsObject: () => Atomics, + ProxyObject: () => Proxy, + }; + const nativeErrors = ["AggregateError","EvalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]; + const typedArrays = ["Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Uint16Array","Int32Array","Uint32Array","Float16Array","Float32Array","Float64Array","BigInt64Array","BigUint64Array"]; + // Read the constructors when a factory runs, not now: reading them here would + // create these lazy holders before the tests that must plant pollution first. + for (let i = 0; i < nativeErrors.length; i++) { + const name = nativeErrors[i]; + holderFactories[name + "Constructor"] = () => globalObject[name]; + holderFactories[name + "Prototype"] = () => globalObject[name].prototype; + } + for (let i = 0; i < typedArrays.length; i++) { + const name = typedArrays[i]; + holderFactories[name + "Constructor"] = () => globalObject[name]; + holderFactories[name + "Prototype"] = () => globalObject[name].prototype; + } + const holderNames = objectKeys(holderFactories); + // Resolved lazily (some tests must not touch holders early) and memoized. + const holderObjects = { __proto__: null }; + function resolveHolder(name) { + if (!(name in holderObjects)) holderObjects[name] = holderFactories[name](); + return holderObjects[name]; + } + function resolveAllHolders() { for (let i = 0; i < holderNames.length; i++) resolveHolder(holderNames[i]); } + // The entry's current value read the way user code reads it. + function liveValue(row) { + const holder = resolveHolder(row.holder); + if (row.kind === "Self") return holder; + const desc = ownDesc(holder, row.key); + if (!desc) return undefined; + return row.kind === "Getter" ? desc.get : row.kind === "Setter" ? desc.set : desc.value; + } +`; + +// Node's per-context primordials construction algorithm, by value, for a fresh +// realm (mirrors lib/internal/per_context/primordials.js). Evaluating it in a +// pristine vm context yields a reference object built Node's way; the differential +// test compares every member of the generated module against it. +const referenceBuilderSource = /* js */ ` + "use strict"; + const primordials = { __proto__: null }; + const { defineProperty, getOwnPropertyDescriptor, ownKeys, getPrototypeOf } = Reflect; + const { apply, bind, call } = Function.prototype; + const uncurryThis = bind.bind(call); + primordials.uncurryThis = uncurryThis; + const applyBind = bind.bind(apply); + primordials.applyBind = applyBind; + const varargsMethods = ["ArrayOf","ArrayPrototypePush","ArrayPrototypeUnshift","MathHypot","MathMax","MathMin","StringFromCharCode","StringFromCodePoint","StringPrototypeConcat","TypedArrayOf"]; + const getNewKey = key => typeof key === "symbol" + ? "Symbol" + key.description[7].toUpperCase() + key.description.slice(8) + : key[0].toUpperCase() + key.slice(1); + const copyAccessor = (dest, prefix, key, { enumerable, get, set }) => { + defineProperty(dest, prefix + "Get" + key, { __proto__: null, value: uncurryThis(get), enumerable }); + if (set !== undefined) defineProperty(dest, prefix + "Set" + key, { __proto__: null, value: uncurryThis(set), enumerable }); + }; + const copyPropsRenamed = (src, dest, prefix) => { + for (const key of ownKeys(src)) { + const newKey = getNewKey(key); + const desc = getOwnPropertyDescriptor(src, key); + if ("get" in desc) copyAccessor(dest, prefix, newKey, desc); + else { + const name = prefix + newKey; + defineProperty(dest, name, { __proto__: null, ...desc }); + if (varargsMethods.includes(name)) defineProperty(dest, name + "Apply", { __proto__: null, value: applyBind(desc.value, src) }); + } + } + }; + const copyPropsRenamedBound = (src, dest, prefix) => { + for (const key of ownKeys(src)) { + const newKey = getNewKey(key); + const desc = getOwnPropertyDescriptor(src, key); + if ("get" in desc) copyAccessor(dest, prefix, newKey, desc); + else { + const { value } = desc; + if (typeof value === "function") desc.value = value.bind(src); + const name = prefix + newKey; + defineProperty(dest, name, { __proto__: null, ...desc }); + if (varargsMethods.includes(name)) defineProperty(dest, name + "Apply", { __proto__: null, value: applyBind(value, src) }); + } + } + }; + const copyPrototype = (src, dest, prefix) => { + for (const key of ownKeys(src)) { + const newKey = getNewKey(key); + const desc = getOwnPropertyDescriptor(src, key); + if ("get" in desc) copyAccessor(dest, prefix, newKey, desc); + else { + const { value } = desc; + if (typeof value === "function") desc.value = uncurryThis(value); + const name = prefix + newKey; + defineProperty(dest, name, { __proto__: null, ...desc }); + if (varargsMethods.includes(name)) defineProperty(dest, name + "Apply", { __proto__: null, value: applyBind(value) }); + } + } + }; + ["Proxy", "globalThis"].forEach(name => { primordials[name] = globalThis[name]; }); + [decodeURI, decodeURIComponent, encodeURI, encodeURIComponent, escape, eval, unescape].forEach(fn => { primordials[fn.name] = fn; }); + ["Atomics", "JSON", "Math", "Proxy", "Reflect"].forEach(name => { copyPropsRenamed(globalThis[name], primordials, name); }); + __CONSTRUCTORS__.forEach(name => { + const original = globalThis[name]; + primordials[name] = original; + copyPropsRenamed(original, primordials, name); + copyPrototype(original.prototype, primordials, name + "Prototype"); + }); + ["Promise"].forEach(name => { + const original = globalThis[name]; + primordials[name] = original; + copyPropsRenamedBound(original, primordials, name); + copyPrototype(original.prototype, primordials, name + "Prototype"); + }); + [{ name: "TypedArray", original: getPrototypeOf(Uint8Array) }].forEach(({ name, original }) => { + primordials[name] = original; + copyPrototype(original, primordials, name); + copyPrototype(original.prototype, primordials, name + "Prototype"); + }); + [ + { name: "ArrayIteratorPrototype", original: getPrototypeOf(Array.prototype[Symbol.iterator]()) }, + { name: "AsyncFunctionPrototype", original: getPrototypeOf(async function () {}) }, + { name: "AsyncGeneratorFunctionPrototype", original: getPrototypeOf(async function* () {}) }, + { name: "AsyncIteratorPrototype", original: getPrototypeOf(getPrototypeOf(async function* () {}).prototype) }, + { name: "GeneratorFunctionPrototype", original: getPrototypeOf(function* () {}) }, + { name: "IteratorHelperPrototype", original: getPrototypeOf(primordials.IteratorPrototypeDrop({ __proto__: null }, null)) }, + { name: "MapIteratorPrototype", original: getPrototypeOf(new primordials.Map()[Symbol.iterator]()) }, + { name: "RegExpStringIteratorPrototype", original: getPrototypeOf(primordials.RegExp.prototype[Symbol.matchAll]()) }, + { name: "SetIteratorPrototype", original: getPrototypeOf(new primordials.Set()[Symbol.iterator]()) }, + { name: "StringIteratorPrototype", original: getPrototypeOf(String.prototype[Symbol.iterator]()) }, + { name: "WrapForValidIteratorPrototype", original: getPrototypeOf(primordials.IteratorFrom({ __proto__: null })) }, + ].forEach(({ name, original }) => { + primordials[name] = original; + copyPrototype(original, primordials, name); + }); + primordials +`; + +async function runChild(body: string, env: Record = {}) { + await using proc = Bun.spawn({ + cmd: [bunExe(), "-e", prelude + body], + env: { ...bunEnv, ...env }, + stdout: "pipe", + stderr: "pipe", + }); + const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); + return { stdout, stderr, exitCode }; +} + +describe.concurrent("primordials manifest", () => { + test("engine table covers every holder, materializes every entry", async () => { + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + const rows = audit(); + const unknownHolders = [], unavailable = [], missingKeys = []; + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + if (!(row.holder in holderFactories)) unknownHolders[unknownHolders.length] = row.holder; + if (!row.available) unavailable[unavailable.length] = row.name; + if (row.kind !== "Self" && row.key === null) missingKeys[missingKeys.length] = row.name; + } + report({ count: rows.length, unknownHolders, unavailable, missingKeys }); + `); + expect(stderr).toBe(""); + const report = JSON.parse(stdout); + expect(report).toEqual({ count: report.count, unknownHolders: [], unavailable: [], missingKeys: [] }); + expect(report.count).toBeGreaterThan(600); + expect(exitCode).toBe(0); + }); + + test("src/js/primordials.d.ts is in sync with the engine's entries", async () => { + // The .d.ts is generated (src/codegen/generate-primordials.ts); this catches a + // WebKit upgrade whose builtin surface changed without a regeneration. + const dts = await Bun.file(new URL("../../../../src/js/primordials.d.ts", import.meta.url)).text(); + const declared = [...dts.matchAll(/^declare const \$(\w+):/gm)].map(m => m[1]).sort(); + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + const rows = audit(); + const names = []; + for (let i = 0; i < rows.length; i++) names[i] = rows[i].name; + names.sort(); + report({ names }); + `); + expect(stderr).toBe(""); + expect(JSON.parse(stdout).names).toEqual(declared); + expect(exitCode).toBe(0); + }); + + test("internal/primordials has exactly Node's members for this engine", async () => { + // Run Node's construction algorithm against this engine's pristine intrinsics + // (the generator's probe) and require the module's member set to equal it. + const probe = await Bun.file( + new URL("../../../../src/codegen/generate-primordials-probe.js", import.meta.url), + ).text(); + await using probeProc = Bun.spawn({ + cmd: [bunExe(), "-e", probe], + env: bunEnv, + stdout: "pipe", + stderr: "pipe", + }); + const [probeOut, probeErr, probeExit] = await Promise.all([ + probeProc.stdout.text(), + probeProc.stderr.text(), + probeProc.exited, + ]); + expect(probeErr).toBe(""); + expect(probeExit).toBe(0); + // The helper members are exactly the `primordials.X = ...` assignments in the + // module epilogue; read them from source instead of a hand-maintained list. + const epilogue = await Bun.file( + new URL("../../../../src/codegen/primordials-module-epilogue.js", import.meta.url), + ).text(); + const helpers = [...epilogue.matchAll(/^primordials\.(\w+) = /gm)].map(m => m[1]); + expect(helpers.length).toBeGreaterThan(15); + const expected = new Set([...JSON.parse(probeOut).entries.map((e: { name: string }) => e.name), ...helpers]); + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + const names = ownKeys(primordials.object); + const list = []; + for (let i = 0; i < names.length; i++) list[i] = names[i]; + report({ list, frozen: Object.isFrozen(primordials.object), proto: getProto(primordials.object) === null }); + `); + expect(stderr).toBe(""); + const report = JSON.parse(stdout); + const actual = new Set(report.list); + expect({ + missing: [...expected].filter(n => !actual.has(n)), + extra: [...actual].filter(n => !expected.has(n)), + }).toEqual({ missing: [], extra: [] }); + expect(report.frozen).toBe(true); + expect(report.proto).toBe(true); + expect(exitCode).toBe(0); + }); + + test("every member matches a reference built the way Node builds it", async () => { + // Differential oracle: run Node's construction algorithm by value in a fresh + // realm and compare all members: presence, typeof, function .length (catches + // receiver-binding/uncurrying mistakes everywhere at once), literal equality. + // The reference's constructor list is the probe's own, so they can't drift. + const probeSource = await Bun.file( + new URL("../../../../src/codegen/generate-primordials-probe.js", import.meta.url), + ).text(); + const constructorList = probeSource.match(/prototype's\.\nfor \(const name of (\[[\s\S]*?\n\])\)/)?.[1]; + expect(constructorList).toBeString(); + const builder = referenceBuilderSource.replace("__CONSTRUCTORS__", constructorList!); + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + const vm = require("node:vm"); + const referenceBuilder = ${JSON.stringify(builder)}; + const reference = vm.runInNewContext(referenceBuilder); + // Bun customizes its own globals' Error statics (captureStackTrace, + // stackTraceLimit) at bootstrap and a bare realm doesn't: re-anchor those + // to this global's values, read here before anything runs. + const errorKeys = ownKeys(Error); + for (let i = 0; i < errorKeys.length; i++) { + const key = errorKeys[i]; + if (typeof key !== "string") continue; + const name = "Error" + key[0].toUpperCase() + key.slice(1); + const desc = ownDesc(Error, key); + if (name in reference && "value" in desc) reference[name] = desc.value; + } + const ours = primordials.object; + const names = ownKeys(reference); + const differences = []; + for (let i = 0; i < names.length; i++) { + const name = names[i]; + if (typeof name !== "string") continue; + const ref = reference[name], own = ours[name]; + const problem = + own === undefined && ref !== undefined ? "missing" + : typeof own !== typeof ref ? "typeof " + typeof own + " vs " + typeof ref + : typeof ref === "function" && own.length !== ref.length ? "length " + own.length + " vs " + ref.length + : (typeof ref !== "function" && typeof ref !== "object" && typeof ref !== "symbol" && !(own === ref || (own !== own && ref !== ref))) + ? "value " + String(own) + " vs " + String(ref) + : null; + if (problem) differences[differences.length] = name + ": " + problem; + } + report({ compared: names.length, differences }); + `); + expect(stderr).toBe(""); + const report = JSON.parse(stdout); + expect(report.differences).toEqual([]); + expect(report.compared).toBeGreaterThan(800); + expect(exitCode).toBe(0); + }); + + test("every engine entry is identical to the live builtin in an untouched global", async () => { + // Materialize first (nothing touched yet), then compare: exercises the lazy + // link-time path that reifies static properties for identity. + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + const rows = audit(); + const mismatched = []; + for (let i = 0; i < rows.length; i++) if (rows[i].value !== liveValue(rows[i])) mismatched[mismatched.length] = rows[i].name; + report({ mismatched }); + `); + expect(stderr).toBe(""); + expect(JSON.parse(stdout)).toEqual({ mismatched: [] }); + expect(exitCode).toBe(0); + }); + + test("identity also holds when the builtins were touched before any primordial linked", async () => { + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + // Read every own property of every holder first, like user code that ran earlier. + resolveAllHolders(); + for (let i = 0; i < holderNames.length; i++) { + const holder = holderObjects[holderNames[i]]; + const keys = ownKeys(holder); + for (let k = 0; k < keys.length; k++) ownDesc(holder, keys[k]); + } + const rows = audit(); + const mismatched = []; + for (let i = 0; i < rows.length; i++) if (rows[i].value !== liveValue(rows[i])) mismatched[mismatched.length] = rows[i].name; + report({ mismatched }); + `); + expect(stderr).toBe(""); + expect(JSON.parse(stdout)).toEqual({ mismatched: [] }); + expect(exitCode).toBe(0); + }); +}); + +describe.concurrent("primordials survive tampering", () => { + // Snapshot pristine values, tamper with every entry in every listed way, then + // audit: each primordial must still be the pristine value. + test("direct and roundabout tampering of every entry after the builtins exist", async () => { + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + const rows = audit(); + resolveAllHolders(); + const pristine = { __proto__: null }; + for (let i = 0; i < rows.length; i++) pristine[rows[i].name] = rows[i].value; + const poison = function poisoned() { return "poisoned"; }; + const canaryBefore = holderObjects.ArrayPrototype.push; + + // 1. Plain assignment, Reflect.set, and defineProperty (value + accessor) on every key. + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + if (row.kind === "Self") continue; + const holder = holderObjects[row.holder]; + const tagged = function tampered() { return "tampered " + row.name; }; + try { holder[row.key] = tagged; } catch {} + try { reflectSet(holder, row.key, tagged); } catch {} + try { defineProperty(holder, row.key, { __proto__: null, value: tagged, configurable: true, writable: true }); } catch {} + try { defineProperty(holder, row.key, { __proto__: null, get() { return "tampered getter " + row.name; }, set() {}, configurable: true }); } catch {} + } + // 2. Delete every key and plant the same names where a prototype-chain walk would find them. + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + if (row.kind === "Self") continue; + try { delete holderObjects[row.holder][row.key]; } catch {} + try { defineProperty(Object.prototype, row.key, { __proto__: null, value: poison, configurable: true, writable: true }); } catch {} + try { defineProperty(Function.prototype, row.key, { __proto__: null, value: poison, configurable: true, writable: true }); } catch {} + } + // 3. Structural attacks on the holders themselves. + for (let i = 0; i < holderNames.length; i++) { + const holder = holderObjects[holderNames[i]]; + if (holder === globalObject) continue; + try { setProto(holder, { __proto__: null, get poisonedProto() { return "poisoned proto"; } }); } catch {} + try { holder.constructor = poison; } catch {} + try { seal(holder); } catch {} + try { freeze(holder); } catch {} + } + // 4. Replace the global bindings themselves. + const globals = ["Object","Function","Array","String","RegExp","Symbol","BigInt","Promise","Iterator","WeakRef","FinalizationRegistry", + "Boolean","Date","Error","Map","Number","Set","WeakMap","WeakSet","ArrayBuffer","DataView","Uint8Array", + "Math","JSON","Reflect","Atomics","Proxy","AggregateError","TypeError","RangeError", + "escape","unescape","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","eval","globalThis"]; + for (let i = 0; i < globals.length; i++) { + try { defineProperty(globalThis, globals[i], { __proto__: null, value: poison, configurable: true, writable: true }); } catch {} + } + + const after = audit(); + // String accumulator + null-prototype report: JSON.stringify would otherwise + // observe the toJSON planted on Object.prototype (spec-correct behavior). + let changed = ""; + for (let i = 0; i < after.length; i++) if (after[i].value !== pristine[after[i].name]) changed += (changed ? "," : "") + after[i].name; + reportAndExit({ __proto__: null, changed, tampered: holderObjects.ArrayPrototype.push !== canaryBefore }); + `); + expect(stderr).toBe(""); + expect(JSON.parse(stdout)).toEqual({ changed: "", tampered: true }); + expect(exitCode).toBe(0); + }); + + test("pollution planted before any lazy holder exists is never captured", async () => { + // Nothing has touched Map/Set/Date/typed arrays/Math/JSON/... yet in this + // process, so this targets the lazy creation snapshots and the static-table + // materialization path. + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + const planted = []; + function plant(target, key, fn) { + planted[planted.length] = fn; + try { defineProperty(target, key, { __proto__: null, value: fn, configurable: true, writable: true }); } catch {} + } + // Every kind of primordial key, planted on the chain a naive lookup would walk. + const keys = ["hasOwnProperty","toString","valueOf","assign","keys","freeze","apply","bind","call","push","map","slice", + "charAt","split","exec","test","get","set","has","size","now","parse","stringify","abs","max","ownKeys", + "add","load","then","catch","from","of","for","keyFor","asIntN","next","register","deref","drop", + "toArray","getBigInt64","byteLength","buffer","length","subarray","escape","decodeURI", + "encodeURIComponent","description","isRawJSON","rawJSON","captureStackTrace","isError","groupBy", + "prototype","constructor","input","lastMatch","revocable","name","message"]; + for (let i = 0; i < keys.length; i++) { + plant(Object.prototype, keys[i], function plantedOnObject() { return "planted"; }); + plant(Function.prototype, keys[i], function plantedOnFunction() { return "planted"; }); + } + // Replace / redefine namespace and constructor bindings before their first use. + plant(globalThis, "Math", { max: () => "planted" }); + plant(globalThis, "Reflect", new Proxy({}, { get: () => () => "planted" })); + delete globalThis.JSON; + globalThis.Atomics = { load: () => "planted" }; + globalThis.Proxy = function planted() { return "planted"; }; + const ctors = ["Map","Set","WeakMap","WeakSet","Date","Error","TypeError","Number","Boolean","ArrayBuffer","DataView","WeakRef","FinalizationRegistry","Int8Array","Float32Array"]; + for (let i = 0; i < ctors.length; i++) plant(globalThis, ctors[i], function plantedCtor() { return "planted"; }); + + const rows = audit(); + const captured = [], unavailable = []; + for (let i = 0; i < rows.length; i++) { + if (!rows[i].available) unavailable[unavailable.length] = rows[i].name; + for (let p = 0; p < planted.length; p++) if (rows[i].value === planted[p]) captured[captured.length] = rows[i].name; + } + const value = { __proto__: null }; + for (let i = 0; i < rows.length; i++) value[rows[i].name] = rows[i].value; + // Behavioral spot checks on the lazily-created holders, using receivers that + // don't depend on the replaced globals. + const behavior = { + MathMax: value.MathMax(1, 5, 3), + ReflectOwnKeys: value.ReflectOwnKeys({ a: 1 }).length, + JSONStringify: value.JSONStringify({ a: 1 }), + AtomicsLoad: value.AtomicsLoad(new Int32Array(1), 0), + DateNow: typeof value.DateNow(), + NumberIsInteger: value.NumberIsInteger(3), + ErrorIsError: value.ErrorIsError(new (value.TypeError)("x")) === true && value.ErrorIsError({}) === false, + ProxyRevocable: typeof value.ProxyRevocable({}, {}).revoke, + MapRoundtrip: $apply(value.MapPrototypeGet, $apply(value.MapPrototypeSet, new (primordials.object.Map)(), ["k", "v"]), ["k"]), + }; + reportAndExit({ captured, unavailable, behavior }); + `); + expect(stderr).toBe(""); + const report = JSON.parse(stdout); + expect(report.captured).toEqual([]); + expect(report.unavailable).toEqual([]); + expect(report.behavior).toEqual({ + MathMax: 5, + ReflectOwnKeys: 1, + JSONStringify: '{"a":1}', + AtomicsLoad: 0, + DateNow: "number", + NumberIsInteger: true, + ErrorIsError: true, + ProxyRevocable: "function", + MapRoundtrip: "v", + }); + expect(exitCode).toBe(0); + }); + + test("primitive-valued global bindings before first use don't break materialization", async () => { + // Namespace/constructor bindings replaced with non-objects before anything links: + // the holders must be recreated pristine instead of downcasting a primitive. + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + globalThis.Math = 5; + globalThis.JSON = 0; + globalThis.Reflect = undefined; + globalThis.Atomics = "atomics"; + globalThis.Proxy = null; + globalThis.Map = false; + globalThis.Error = 1; + const rows = audit(); + const unavailable = []; + for (let i = 0; i < rows.length; i++) if (!rows[i].available) unavailable[unavailable.length] = rows[i].name; + const value = { __proto__: null }; + for (let i = 0; i < rows.length; i++) value[rows[i].name] = rows[i].value; + reportAndExit({ + unavailable, + MathMax: value.MathMax(1, 5, 3), + JSONStringify: value.JSONStringify({ a: 1 }), + ReflectHas: value.ReflectHas({ a: 1 }, "a"), + AtomicsLoad: value.AtomicsLoad(new Int32Array(1), 0), + ErrorIsError: value.ErrorIsError(new (value.TypeError)("x")), + ProxyRevocable: typeof value.ProxyRevocable, + }); + `); + expect(stderr).toBe(""); + expect(JSON.parse(stdout)).toEqual({ + unavailable: [], + MathMax: 5, + JSONStringify: '{"a":1}', + ReflectHas: true, + AtomicsLoad: 0, + ErrorIsError: true, + ProxyRevocable: "function", + }); + expect(exitCode).toBe(0); + }); + + test("a foreign realm's builtin functions are never adopted, even installed before first link", async () => { + // Same builtin pointer, different global: the identity check for a reified + // static-table property must also compare realms. + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + const vm = require("node:vm"); + const foreign = vm.runInNewContext("({ push: Array.prototype.push, getTime: Date.prototype.getTime, mathMax: Math.max })"); + Array.prototype.push = foreign.push; + Date.prototype.getTime = foreign.getTime; + Math.max = foreign.mathMax; + const rows = audit(); + const byName = { __proto__: null }, unavailable = []; + for (let i = 0; i < rows.length; i++) { + byName[rows[i].name] = rows[i].value; + if (!rows[i].available) unavailable[unavailable.length] = rows[i].name; + } + const arr = []; + $apply(byName.ArrayPrototypePush, arr, [1]); + reportAndExit({ + unavailable, + pushForeign: byName.ArrayPrototypePush === foreign.push, + getTimeForeign: byName.DatePrototypeGetTime === foreign.getTime, + mathMaxForeign: byName.MathMax === foreign.mathMax, + pushWorks: arr.length, + mathMax: byName.MathMax(1, 5, 3), + }); + `); + expect(stderr).toBe(""); + expect(JSON.parse(stdout)).toEqual({ + unavailable: [], + pushForeign: false, + getTimeForeign: false, + mathMaxForeign: false, + pushWorks: 1, + mathMax: 5, + }); + expect(exitCode).toBe(0); + }); + + test("a foreign realm's namespace objects are never adopted as this realm's holders", async () => { + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + const vm = require("node:vm"); + const foreign = vm.runInNewContext("({ Math, JSON, Reflect, Atomics, Proxy })"); + globalThis.Math = foreign.Math; + globalThis.JSON = foreign.JSON; + globalThis.Reflect = foreign.Reflect; + globalThis.Atomics = foreign.Atomics; + globalThis.Proxy = foreign.Proxy; + const rows = audit(); + const value = { __proto__: null }; + const unavailable = []; + for (let i = 0; i < rows.length; i++) { + value[rows[i].name] = rows[i].value; + if (!rows[i].available) unavailable[unavailable.length] = rows[i].name; + } + reportAndExit({ + unavailable, + foreign: value.MathMax === foreign.Math.max || value.JSONStringify === foreign.JSON.stringify || value.Proxy === foreign.Proxy, + MathMax: value.MathMax(1, 5, 3), + JSONStringify: value.JSONStringify({ a: 1 }), + ReflectHas: value.ReflectHas({ a: 1 }, "a"), + AtomicsLoad: value.AtomicsLoad(new Int32Array(1), 0), + ProxyType: typeof new (value.Proxy)({}, {}), + }); + `); + expect(stderr).toBe(""); + expect(JSON.parse(stdout)).toEqual({ + unavailable: [], + foreign: false, + MathMax: 5, + JSONStringify: '{"a":1}', + ReflectHas: true, + AtomicsLoad: 0, + ProxyType: "object", + }); + expect(exitCode).toBe(0); + }); + + test("tampered builtins still work through the primordials module", async () => { + // Behavior, not just identity: use the module's uncurried methods, statics, + // getters, values, and Safe helpers on receivers created before tampering, + // after every primordial key on every holder has been replaced. + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + const p = primordials.object; + const map = new Map([["k", "v"]]); const set = new Set([1]); const u8 = new Uint8Array([1, 2, 3, 4]); + const dv = new DataView(u8.buffer); const date = new Date(0); const re = /b/g; const err = new Error("e"); + const wr = new WeakRef({}); const wm = new WeakMap(); const ws = new WeakSet(); const sym = Symbol("s"); + const promise = Promise.resolve(1); + // Safe collections take their contents up front too: constructing them from an + // iterable observes that iterable's protocol (per spec, same as Node). + const safeMap = new (p.SafeMap)([["a", 1]]); const safeSet = new (p.SafeSet)([1, 2]); const safeString = new (p.SafeStringIterator)("ab"); + const rows = audit(); + resolveAllHolders(); + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + if (row.kind === "Self") continue; + try { defineProperty(holderObjects[row.holder], row.key, { __proto__: null, value() { return "tampered " + row.name; }, configurable: true }); } catch {} + } + const results = { + ArrayPrototypeMap: p.ArrayPrototypeJoin(p.ArrayPrototypeMap([1, 2], x => x * 2), ","), + ArrayIteratorNext: p.ArrayIteratorPrototypeNext(p.ArrayPrototypeSymbolIterator([7])).value, + ArrayOfApply: p.ArrayPrototypeJoin(p.ArrayOfApply([1, 2]), "-"), + StringPrototypeSlice: p.StringPrototypeSlice("hello", 1, 3), + StringIteratorNext: p.StringIteratorPrototypeNext(p.StringPrototypeSymbolIterator("hi")).value, + StringPrototypeConcatApply: p.StringPrototypeConcatApply("a", ["b", "c"]), + ObjectKeys: p.ArrayPrototypeJoin(p.ObjectKeys({ a: 1, b: 2 }), ","), + ObjectPrototypeHasOwnProperty: p.ObjectPrototypeHasOwnProperty({ a: 1 }, "a"), + ObjectPrototypeGet__proto__: p.ObjectPrototypeGet__proto__({}) === p.ObjectPrototype, + FunctionPrototypeCall: p.FunctionPrototypeCall(function () { return this.x; }, { x: 42 }), + RegExpPrototypeExec: p.RegExpPrototypeExec(re, "abc")[0], + RegExpPrototypeGetGlobal: p.RegExpPrototypeGetGlobal(re), + RegExpGetLegacyInput: (p.RegExpPrototypeExec(/(x)/, "ax"), p["RegExpGet$1"](RegExp)), + SymbolPrototypeGetDescription: p.SymbolPrototypeGetDescription(sym), + SymbolFor: typeof p.SymbolFor("k"), + SymbolIteratorValue: typeof p.SymbolIterator, + BigIntPrototypeToString: p.BigIntPrototypeToString(255n, 16), + BigIntAsIntN: p.BigIntAsIntN(8, 255n) === -1n, + PromisePrototypeThen: typeof p.PromisePrototypeThen(promise, x => x), + PromiseResolveBound: typeof p.PromiseResolve(2), + MapPrototypeGet: p.MapPrototypeGet(map, "k"), + MapPrototypeGetSize: p.MapPrototypeGetSize(map), + SetPrototypeHas: p.SetPrototypeHas(set, 1), + WeakMapPrototypeHas: p.WeakMapPrototypeHas(wm, {}), + WeakSetPrototypeHas: p.WeakSetPrototypeHas(ws, {}), + WeakRefPrototypeDeref: typeof p.WeakRefPrototypeDeref(wr), + DatePrototypeGetTime: p.DatePrototypeGetTime(date), + DateNow: typeof p.DateNow(), + ErrorPrototypeToString: p.ErrorPrototypeToString(err), + ErrorCaptureStackTrace: (p.ErrorCaptureStackTrace(err), typeof err.stack), + ErrorIsError: p.ErrorIsError(err), + NumberPrototypeToFixed: p.NumberPrototypeToFixed(1.25, 1), + NumberParseInt: p.NumberParseInt("42px"), + NumberMAX_SAFE_INTEGER: p.NumberMAX_SAFE_INTEGER, + BooleanPrototypeToString: p.BooleanPrototypeToString(true), + TypedArrayPrototypeGetLength: p.TypedArrayPrototypeGetLength(u8), + TypedArrayPrototypeSubarray: p.TypedArrayPrototypeGetLength(p.TypedArrayPrototypeSubarray(u8, 1, 3)), + Uint8ArrayBYTES_PER_ELEMENT: p.Uint8ArrayBYTES_PER_ELEMENT, + ArrayBufferPrototypeGetByteLength: p.ArrayBufferPrototypeGetByteLength(p.TypedArrayPrototypeGetBuffer(u8)), + DataViewPrototypeGetUint8: p.DataViewPrototypeGetUint8(dv, 2), + MathMax: p.MathMax(1, 5, 3), + MathMaxApply: p.MathMaxApply([1, 9]), + MathPI: p.MathPI > 3.14 && p.MathPI < 3.15, + JSONParse: p.JSONParse("[1,2]").length, + JSONStringify: p.JSONStringify({ a: 1 }), + ReflectHas: p.ReflectHas({ a: 1 }, "a"), + AtomicsAdd: p.AtomicsAdd(new (p.Int32Array)(2), 0, 5), + encodeURIComponent: p.encodeURIComponent("a b"), + StringFromCharCode: p.StringFromCharCode(104, 105), + FinalizationRegistryPrototypeRegister: typeof p.FinalizationRegistryPrototypeRegister(new (p.FinalizationRegistry)(() => {}), {}, 1), + SafeMapGet: safeMap.get("a"), + SafeSetHas: safeSet.has(2) && safeSet.size === 2, + // Safe collections hand out captured safe iterators (Node's intended + // makeSafe behavior; Node master's wrap condition is dead code), so + // iterating a SafeSet survives %SetIteratorPrototype%.next tampering. + SafeSetIterationSurvivesTamper: (() => { try { return [...safeSet].length; } catch { return "threw"; } })(), + SafeStringIterator: [...safeString].length, + hardenRegExpSplit: p.ArrayPrototypeJoin(p.StringPrototypeSplit("a-b-c", p.hardenRegExp(/-/)), "|"), + SafeStringPrototypeSearch: p.SafeStringPrototypeSearch("xyz", /z/), + uncurryThis: p.uncurryThis(function (a, b) { return this.n * a + b; })({ n: 3 }, 4, 2), + applyBind: p.applyBind(p.MathMax)(null, [2, 8]), + }; + let push = 0; const big = []; for (let i = 0; i < 70000; i++) big[i] = 1; + const dst = []; p.SafeArrayPrototypePushApply(dst, big); push = dst.length; + results.SafeArrayPrototypePushApply = push; + reportAndExit(results); + `); + expect(stderr).toBe(""); + expect(JSON.parse(stdout)).toEqual({ + ArrayPrototypeMap: "2,4", + ArrayIteratorNext: 7, + ArrayOfApply: "1-2", + StringPrototypeSlice: "el", + StringIteratorNext: "h", + StringPrototypeConcatApply: "abc", + ObjectKeys: "a,b", + ObjectPrototypeHasOwnProperty: true, + ObjectPrototypeGet__proto__: true, + FunctionPrototypeCall: 42, + RegExpPrototypeExec: "b", + RegExpPrototypeGetGlobal: true, + RegExpGetLegacyInput: "x", + SymbolPrototypeGetDescription: "s", + SymbolFor: "symbol", + SymbolIteratorValue: "symbol", + BigIntPrototypeToString: "ff", + BigIntAsIntN: true, + PromisePrototypeThen: "object", + PromiseResolveBound: "object", + MapPrototypeGet: "v", + MapPrototypeGetSize: 1, + SetPrototypeHas: true, + WeakMapPrototypeHas: false, + WeakSetPrototypeHas: false, + WeakRefPrototypeDeref: "object", + DatePrototypeGetTime: 0, + DateNow: "number", + ErrorPrototypeToString: "Error: e", + ErrorCaptureStackTrace: "string", + ErrorIsError: true, + NumberPrototypeToFixed: "1.3", + NumberParseInt: 42, + NumberMAX_SAFE_INTEGER: 9007199254740991, + BooleanPrototypeToString: "true", + TypedArrayPrototypeGetLength: 4, + TypedArrayPrototypeSubarray: 2, + Uint8ArrayBYTES_PER_ELEMENT: 1, + ArrayBufferPrototypeGetByteLength: 4, + DataViewPrototypeGetUint8: 3, + MathMax: 5, + MathMaxApply: 9, + MathPI: true, + JSONParse: 2, + JSONStringify: '{"a":1}', + ReflectHas: true, + AtomicsAdd: 0, + encodeURIComponent: "a%20b", + StringFromCharCode: "hi", + FinalizationRegistryPrototypeRegister: "undefined", + SafeMapGet: 1, + SafeSetHas: true, + SafeSetIterationSurvivesTamper: 2, + SafeStringIterator: 2, + hardenRegExpSplit: "a|b|c", + SafeStringPrototypeSearch: 2, + uncurryThis: 14, + applyBind: 8, + SafeArrayPrototypePushApply: 70000, + }); + expect(exitCode).toBe(0); + }); +}); + +describe.concurrent("primordials module load timing", () => { + // The module loads lazily (first internal require), which can be after user code. + // Nothing in it may read live objects at load time: the Safe* classes and the + // hardenRegExp originals must come from pristine constants, not the prototypes. + test("tampering planted before the module has ever loaded is not captured", async () => { + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + RegExp.prototype.exec = function evilExec() { return null; }; + Reflect.defineProperty(RegExp.prototype, Symbol.split, { __proto__: null, value: () => ["evil split"], configurable: true }); + Map.prototype.get = function evilGet() { return "evil get"; }; + Map.prototype.evilExtra = function () { return "evil extra"; }; + Set.prototype.has = () => "evil has"; + WeakMap.prototype.get = () => "evil weak"; + Promise.prototype.then = function () { throw new Error("evil then"); }; + Promise.prototype.finally = function () { throw new Error("evil finally"); }; + // First load of internal/primordials happens now, after the tampering. + const p = primordials.object; + const results = { + SafeMapGet: new p.SafeMap([[1, "ok"]]).get(1), + SafeMapNoExtra: !("evilExtra" in p.SafeMap.prototype), + SafeSetHas: new p.SafeSet([2]).has(2), + SafeWeakMapGet: (() => { const k = {}; return new p.SafeWeakMap([[k, "ok"]]).get(k); })(), + hardenedExec: p.hardenRegExp(/b/).exec("abc")?.[0], + hardenedSplit: p.ArrayPrototypeJoin(p.StringPrototypeSplit("a-b", p.hardenRegExp(/-/)), "|"), + }; + // The combinator drives its inputs and result through the pristine then, + // never the poisoned Promise.prototype.then. (Elements must be thenables, as + // in Node.) The result is consumed with the captured PromisePrototypeThen. + p.PromisePrototypeThen( + p.SafePromiseAll([p.PromiseResolve(1), p.PromiseResolve(2)]), + v => reportAndExit({ ...results, SafePromiseAll: v }), + e => reportAndExit({ ...results, SafePromiseAll: "threw: " + e.message }), + ); + `); + expect(stderr).toBe(""); + expect(JSON.parse(stdout)).toEqual({ + SafeMapGet: "ok", + SafeMapNoExtra: true, + SafeSetHas: true, + SafeWeakMapGet: "ok", + hardenedExec: "b", + hardenedSplit: "a|b", + SafePromiseAll: [1, 2], + }); + expect(exitCode).toBe(0); + }); +}); + +describe.concurrent("primordials configuration", () => { + test("option-gated builtins that don't exist become throwing placeholders, not crashes or pollution", async () => { + // JSON.isRawJSON / JSON.rawJSON only exist with --useJSONSourceTextAccess. + // Turn it off, plant the names on Object.prototype, and touch JSON: the + // primordials must be "unavailable" throwers rather than the planted functions. + const { stdout, stderr, exitCode } = await runChild( + /* js */ ` + const planted = function planted() { return "planted"; }; + Object.prototype.isRawJSON = planted; + Object.prototype.rawJSON = planted; + JSON.parse("1"); + const rows = audit(); + const unavailable = [], captured = []; + for (let i = 0; i < rows.length; i++) { + if (!rows[i].available) unavailable[unavailable.length] = rows[i].name; + if (rows[i].value === planted) captured[captured.length] = rows[i].name; + } + unavailable.sort(); + let threw = false; + for (let i = 0; i < rows.length; i++) { + if (rows[i].name !== "JSONIsRawJSON") continue; + try { rows[i].value(); } catch (e) { threw = /not available/.test(String(e)); } + } + report({ unavailable, captured, threw }); + `, + { BUN_JSC_useJSONSourceTextAccess: "0" }, + ); + expect(stderr).toBe(""); + expect(JSON.parse(stdout)).toEqual({ unavailable: ["JSONIsRawJSON", "JSONRawJSON"], captured: [], threw: true }); + expect(exitCode).toBe(0); + }); + + // Debug+ASAN Worker startup plus a full audit() regularly exceeds the 5 s default under describe.concurrent. + test("each Worker global materializes its own primordials", { timeout: 30_000 }, async () => { + const { stdout, stderr, exitCode } = await runChild(/* js */ ` + const { Worker } = require("node:worker_threads"); + const w = new Worker( + 'Array.prototype.push = () => { throw new Error("worker tampered"); };' + + 'const { primordials } = require("bun:internal-for-testing");' + + 'const rows = primordials.audit();' + + 'let push, unavailable = 0;' + + 'for (let i = 0; i < rows.length; i++) { if (rows[i].name === "ArrayPrototypePush") push = rows[i].value; if (!rows[i].available) unavailable++; }' + + 'const arr = []; push.call(arr, 1, 2);' + + 'require("node:worker_threads").parentPort.postMessage({ len: arr.length, unavailable });', + { eval: true } + ); + let posted = false; + w.on("message", m => { posted = true; write(stringify(m)); w.terminate(); }); + w.on("error", e => { process.stderr.write(String(e)); process.exit(1); }); + w.on("exit", code => { if (!posted) { process.stderr.write("worker exited " + code + " without posting"); process.exit(1); } }); + `); + expect(stderr).toBe(""); + expect(JSON.parse(stdout)).toEqual({ len: 2, unavailable: 0 }); + expect(exitCode).toBe(0); + }); +}); + +describe.concurrent("$Name link-time constants in builtin JavaScript", () => { + // The bundler rewrites $Name to @Name and .$call to a direct call; drive the + // checked-in probe through a poisoned global to make sure that path is used. + const probeBody = /* js */ ` + const map = new Map([["k", "v"]]); + const u8 = new Uint8Array([1, 2, 3, 4]); + const originalPush = Array.prototype.push; + if (process.env.TAMPER === "1") { + Array.prototype.push = () => { throw new Error("tampered"); }; + Array.prototype.slice = () => { throw new Error("tampered"); }; + Array.prototype[Symbol.iterator] = () => { throw new Error("tampered"); }; + String.prototype.slice = () => { throw new Error("tampered"); }; + String.prototype.split = () => { throw new Error("tampered"); }; + Object.keys = () => { throw new Error("tampered"); }; + Object.defineProperty = () => { throw new Error("tampered"); }; + Function.prototype.bind = () => { throw new Error("tampered"); }; + Function.prototype.call = () => { throw new Error("tampered"); }; + Function.prototype.apply = () => { throw new Error("tampered"); }; + RegExp.prototype.test = () => { throw new Error("tampered"); }; + Map.prototype.get = () => { throw new Error("tampered"); }; + Date.now = () => { throw new Error("tampered"); }; + Number.isInteger = () => { throw new Error("tampered"); }; + Math.max = () => { throw new Error("tampered"); }; + Reflect.ownKeys = () => { throw new Error("tampered"); }; + JSON.stringify = () => { throw new Error("tampered"); }; + const TA = Reflect.getPrototypeOf(Uint8Array.prototype); + TA.subarray = () => { throw new Error("tampered"); }; + defineProperty(Map.prototype, "size", { get() { throw new Error("tampered"); } }); + defineProperty(TA, "length", { get() { throw new Error("tampered"); } }); + defineProperty(DataView.prototype, "byteLength", { get() { throw new Error("tampered"); } }); + defineProperty(RegExp.prototype, "source", { get() { throw new Error("tampered"); } }); + Promise.resolve = () => { throw new Error("tampered"); }; + } + const out = primordials.run([], "hello", map, u8, /ell/); + out.tampered = Array.prototype.push !== originalPush; + reportAndExit(out); + `; + + const expected = { + ArrayPrototypePush: 2, + ArrayPrototypeSlice: [1, 2], + ArrayPrototypeSymbolIterator: 1, + StringPrototypeSlice: "el", + StringPrototypeSplit: ["h", "e", "l", "l", "o"], + ObjectKeys: ["a", "b"], + ObjectDefineProperty: 42, + FunctionPrototypeBind: 8, + RegExpPrototypeTest: true, + RegExpPrototypeGetSource: "ell", + MapPrototypeGet: "v", + MapPrototypeGetSize: 1, + DateNow: "number", + NumberIsInteger: true, + MathMax: 5, + ReflectOwnKeys: ["a"], + JSONStringify: '{"a":1}', + TypedArrayPrototypeGetLength: 4, + TypedArrayPrototypeSubarray: 2, + DataViewPrototypeGetByteLength: 4, + PromiseResolve: true, + }; + + for (const tamper of [false, true]) { + test(tamper ? "after tampering" : "untouched", async () => { + const { stdout, stderr, exitCode } = await runChild(probeBody, { TAMPER: tamper ? "1" : "0" }); + expect(stderr).toBe(""); + expect(JSON.parse(stdout)).toEqual({ ...expected, tampered: tamper }); + expect(exitCode).toBe(0); + }); + } +});