Built-in shapes for prototypes and constructors: composable storage, accessors, aliases#2580
Merged
Merged
Conversation
IntlInstance and TemporalInstance hand-registered their sub-namespace constructor references (Intl.Collator/.../Segmenter; Temporal.Duration/.../Now) with eager SetProperty(..., _realm.Intrinsics.X) calls plus [JsObject(ExtraCapacity)] presizing, documented as "not generator-friendly". They are exactly the lazy realm-intrinsic references [JsIntrinsicReference] already emits for globalThis's 56 constructor properties (GlobalObject.Properties.cs), so route them through the same generator surface: one mechanism, no hand-written tail, no ExtraCapacity. The references become lazy (resolved on first read) instead of eager, so touching one Intl/Temporal sub-namespace no longer instantiates all ~9 siblings. Benchmarks (BuiltinShapeBenchmark + IntlColdStartBenchmark, default job, vs base; EngineOnly control byte-identical at 13.69 KB): EngineInitTemporalNow 19.52 -> 17.41 KB (-10.8%; time -16.4%) IntlColdStart.NumberFormat 28.99 -> 26.27 KB ( -9.4%; time -13.5%) IntlColdStart.DateTimeFormat 27.49 -> 24.77 KB ( -9.9%; time -14.3%) IntlColdStart.ListFormat 25.40 -> 22.67 KB (-10.7%; time -14.2%) IntlColdStart.RelativeTimeFormat 27.52 -> 25.12 KB ( -8.7%; time -16.8%) IntlColdStart.LocaleCanonicalize 30.06 -> 27.34 KB ( -9.1%; time -14.1%) Conformance: Test262 Temporal+Intl 15808/0; Jint.Tests Intl/Temporal 88/0. Order-safe (namespace tests assert presence + non-enumerability, not order). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3
…BuiltinShaped Refactor the built-in shape store so its behavior lives on ObjectInstance behind a new InternalTypes.BuiltinShapeMode flag and is reached through an IBuiltinShaped storage interface, instead of being trapped in the BuiltinShapeObject base class. This is the enabler for shaping prototypes and constructors, which derive from Prototype / Constructor:Function / instance types and so cannot also derive from BuiltinShapeObject under single inheritance. - InternalTypes.BuiltinShapeMode: set when the shape is installed, cleared on deopt; mutually exclusive with ShapeMode. Folded into the existing ShapeMode flag test in the property virtuals so the common (non-shaped) path costs nothing extra. - IBuiltinShaped: exposes only per-host storage (BuiltinShape, the per-realm PropertyDescriptor?[], MakeBuiltinFunction) — no logic — so the mechanism composes across host base classes. The field stays off the million-population bases. - ObjectInstance.GetOwnProperty / SetOwnProperty / RemoveOwnProperty / GetOwnProperties / GetOwnPropertyKeys dispatch to shared private helpers (MaterializeBuiltinSlot / DeoptBuiltinShape / GetBuiltinShapeOwnPropertyKeys) via Unsafe.As<IBuiltinShaped>, mirroring how ShapeMode is already handled inline with Unsafe.As<JsObject>. Delete and DefineOwnProperty need no change (Delete routes through RemoveOwnProperty; DefineOwnProperty's deopt is ShapeMode-only, preserving redefine-in-place). Key enumeration prepends GetInitialOwnStringPropertyKeys() so Function-derived hosts surface length/name/prototype correctly (a no-op for today's hosts). - BuiltinShapeObject becomes a thin convenience base: implements IBuiltinShaped with a field, sets the flag in InitializeBuiltinShape, and drops its virtual overrides. No functional change. The 7 existing shaped hosts (Math, JSON, Reflect, Atomics, Temporal.Now, Generator/AsyncGenerator prototypes) now route through the base. Benchmarks (BuiltinShapeBenchmark + ObjectAccessBenchmark + PropertyAllocBenchmark, default job, vs base): allocation byte-identical on every scenario; time within noise (the EngineOnly control runs identical code yet varies +3% run-to-run, setting the floor). Ordinary-object property get/set/create unaffected. Conformance: full Test262 99260/0 (133 pre-existing skips). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3
…t-path integration
Extend built-in shape storage from the 7 BuiltinShapeObject namespaces to Prototype-
derived hosts, starting with the five function-only prototypes (Promise, WeakMap,
WeakSet, WeakRef, FinalizationRegistry). Each opts in with [JsObject(UseShape = true)]
and keeps deriving from Prototype; the generator emits the IBuiltinShaped storage onto
the host itself, so no shared base class is needed.
Generator (dual-mode):
- A host that does NOT derive from BuiltinShapeObject opts into shapes with an explicit
[JsObject(UseShape = true)] (deriving from BuiltinShapeObject stays the implicit opt-in).
- For such a host the emitter adds ': IBuiltinShaped' to the partial and emits the
per-realm __builtinDescriptors field plus explicit IBuiltinShaped implementations
(BuiltinShape / BuiltinDescriptors / MakeBuiltinFunction), instead of the abstract
overrides used for BuiltinShapeObject-derived hosts.
Runtime:
- InitializeBuiltinShape / SetBuiltinInstanceDescriptor moved to ObjectInstance
(private protected, IBuiltinShaped-based) so any shaped host can call them.
- The raw-_properties PlainObject fast paths in Get / Set / CreateDataProperty are gated
(_type & (PlainObject | BuiltinShapeMode)) == PlainObject so a shaped prototype (which
is PlainObject) routes to the virtual GetOwnProperty. The JintMemberExpression receiver
inline-cache gate is broadened to PlainObject | BuiltinShapeMode so shaped prototypes
(and, later, constructors) get the version-gated descriptor cache.
- Fix: those fast paths also require _initialized. The BuiltinShapeMode flag is set lazily
in Initialize, so a not-yet-initialized shaped prototype would otherwise pass the pre-init
flag gate, initialize inside the fast path, then read the (now shape-backed, empty)
_properties and fall through to the prototype chain — e.g. `typeof WeakMap.prototype.get`
wrongly === "undefined" on first access. Matches the existing CreateDataProperty guard.
Benchmarks (BuiltinShapeBenchmark + ObjectAccessBenchmark + PropertyAllocBenchmark,
default job, vs base; EngineOnly control byte-identical at 13.69 KB, EngineInitGenerators
byte-identical at 19.66 KB):
EngineInitPrototypes (the 5 shaped) 22.37 -> 20.77 KB (-1.60 KB; storage over
EngineOnly 8.68 -> 7.08 KB, -18.4%; time flat)
Ordinary-object get/set/create allocation byte-identical, time within noise.
Conformance: full Test262 99260/0; Jint.Tests 3210/0; Jint.Tests.SourceGenerators 30/0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3
…on shaped hosts Extend built-in shape storage to the remaining function-only Prototype-derived hosts: AggregateError, SuppressedError, BigInt, ShadowRealm, TypedArray (%TypedArray% per-type + Uint8Array), the three function-kind prototypes (GeneratorFunction / AsyncFunction / AsyncGeneratorFunction), the iterator-helper prototypes (Iterator/AsyncIterator helper, WrapForValidIterator), and the Intl DisplayNames/DurationFormat/ListFormat/PluralRules/ RelativeTimeFormat/Segmenter prototypes. Each opts in with [JsObject(UseShape = true)]; all have a clean CreateProperties_Generated-only Initialize, so shaping is mechanical. DatePrototype is deliberately left on the dictionary path (it adds a toGMTString string alias in Initialize, which the fixed shape layout can't express). Generator fix: a shaped host with no [JsFunction]s (only instance/constant properties + symbols, e.g. GeneratorFunctionPrototype) has no dispatcher and no function slots, so its IBuiltinShaped.MakeBuiltinFunction now emits a throwing body instead of referencing a dispatcher type that isn't generated. Benchmarks (BuiltinShapeBenchmark, default job, vs prior commit; EngineOnly control byte-identical at 13.69 KB): EngineInitPrototypes (extended to touch these hosts) 36.78 -> 34.84 KB (-1.94 KB; storage over EngineOnly -8.4%). No hot-path code changed. Conformance: full Test262 99260/0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3
Teach the built-in shape path to represent string [JsAccessor]s, then shape the accessor-bearing Prototype-derived hosts whose Initialize is generated-only: Symbol, Map, ArrayBuffer, SharedArrayBuffer, DataView, Iterator prototypes. - BuiltinShape gains an explicit BuiltinSlotKind per slot (Constant / Instance / Function / Accessor) and a SetterSlots array. Builder.Accessor(name, getterSlot, setterSlot, flags) reserves an accessor slot; MaterializeBuiltinSlot creates a GetSetPropertyDescriptor on first access (leaner than the dictionary path, which allocates a LazyGetSetPropertyDescriptor per accessor at Initialize even if unread). - Generator: BuildBuiltinShape_Generated emits builder.Accessor(...) for each accessor pair, after the functions, sorted by JsName to match the dictionary path's key order. JINT022 no longer rejects accessors or symbol accessors (symbol accessors register in the symbol dictionary, orthogonal to the string shape) — only intrinsic references and thrower accessors remain unsupported. - SetPrototype is deliberately NOT shaped: it aliases the string property `keys` to the `values` function via SetProperty in Initialize (spec requires keys === values), which the fixed shape layout can't express (a raw SetProperty on a shaped host writes to _properties, which the shape lookup ignores). Same class of case as Date/RegExp/String; a generator alias feature is a later step. Benchmarks (BuiltinShapeBenchmark, default job, vs prior commit; EngineOnly control byte-identical at 13.69 KB): EngineInitPrototypes (extended to touch the accessor hosts) 47.37 -> 41.63 KB (-5.74 KB; storage over EngineOnly -17.0%). Conformance: full Test262 0 new failures (the 4 annexB RegExp-*-escape-BMP timeouts are pre-existing concurrent-load flakes — RegExp is not shaped, and the same binary passed 99260/0 earlier); Set/Map/Symbol/ArrayBuffer/DataView/Iterator subset 6494/0; Jint.Tests.SourceGenerators 30/0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3
With accessor support in place, shape the remaining accessor-bearing Prototype-derived hosts whose Initialize is generated-only: Object.prototype (the root — __proto__ get/set accessor), all 8 Temporal prototypes (Duration, Instant, PlainDate, PlainDateTime, PlainMonthDay, PlainTime, PlainYearMonth, ZonedDateTime), the Intl Collator/DateTimeFormat/ NumberFormat/Locale prototypes, and the (Async)DisposableStack and AsyncIterator prototypes. The Temporal prototypes are accessor-dense (ZonedDateTime 30, PlainDateTime 22, PlainDate 16, Duration 12), so the dictionary path allocated a large per-realm property dictionary of eager LazyGetSetPropertyDescriptors even when the object was never touched beyond one property; the shape path installs a shared layout and materializes each descriptor lazily on first read. Shaping the root Object.prototype (in every ordinary object's prototype chain) with no conformance change validates the member-read fast-path integration end to end. Benchmarks (BuiltinShapeBenchmark, default job, vs prior commit; EngineOnly control byte-identical at 13.69 KB): EngineInitPrototypes (extended to touch these hosts) 87.36 -> 62.67 KB (-24.69 KB; storage over EngineOnly -33.5%). Conformance: full Test262 0 new failures (the annexB RegExp-*-escape-BMP timeouts are the pre-existing concurrent-load flakes; RegExp is not shaped). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3
…l, Promise, ArrayBuffer Extend built-in shape storage to Constructor-derived hosts — the last major base class. Constructors derive from Constructor : Function : ObjectInstance and are not PlainObject, but the composable IBuiltinShaped storage (emitted onto the host by the generator) plus the P2 fast-path work already handle them: - The JintMemberExpression receiver gate was broadened to PlainObject | BuiltinShapeMode in P2, so a shaped constructor (not PlainObject) still gets the version-gated inline cache. - Function keeps serving length/name/prototype from its own fields and chains base.GetOwnProperty into ObjectInstance, which dispatches to the shape store. GetBuiltinShapeOwnPropertyKeys prepends GetInitialOwnStringPropertyKeys() so getOwnPropertyNames yields length,name,prototype ahead of the shaped statics, matching the dictionary path. - @@species getters (symbol accessors) and well-known symbol constants (SymbolConstructor) work via the accessor + symbol machinery. This batch: Object, Array, ArrayBuffer, Map, Set, Symbol, Promise constructors. Benchmarks (BuiltinShapeBenchmark, default job, vs prior commit; EngineOnly control byte-identical at 13.70 KB): EngineInitConstructors 26.30 -> 21.35 KB (-4.95 KB; storage over EngineOnly -39.3%; time -10.7%) — the per-realm constructor dictionary (ObjectConstructor 23 statics, SymbolConstructor 17) is pure overhead the shape removes. Conformance: full Test262 0 new failures (the 4 annexB RegExp-*-escape-BMP timeouts are pre-existing concurrent-load flakes; RegExp is not shaped); constructor smoke covers length/name/prototype coexistence, static methods, @@species, construction, and deopt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3
…tor, Intl, Temporal) With the Function-derived constructor path proven, shape the remaining clean constructors whose Initialize is generated-only: Date, Error, BigInt, String, Proxy, SharedArrayBuffer, Iterator/AsyncIterator, all 8 Temporal constructors, and all 9 Intl constructors. Left on the dictionary path (hand-written string aliases / intrinsic refs, not shape- expressible): NumberConstructor (Number.parseInt === parseInt), RegExpConstructor (legacy statics), and the TypedArray constructor family (handled separately). Also fixes a pre-existing IDE0055 formatting issue in CollatorConstructor (comments between `=>` and the value in a switch expression) that surfaced once the file was re-analyzed. Benchmarks (BuiltinShapeBenchmark, default job, vs prior commit; EngineOnly control byte-identical at 13.70 KB): EngineInitConstructors (extended to touch these constructors) 51.23 -> 46.51 KB (-4.72 KB; storage over EngineOnly -12.6%). Conformance: full Test262 0 new failures (the 4 annexB RegExp-*-escape-BMP timeouts are the pre-existing concurrent-load flakes; RegExp is not shaped). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3
… Error) Two more prototype families join the shape path: - Iterator prototypes (Array/Map/Set/String/RegExpString iterator prototypes), which derive from the already-shaped IteratorPrototype. A derived host re-implements IBuiltinShaped (interface re-implementation), so each carries its own shape — verified by the iterator suite passing unchanged. - Instance-typed prototypes: ArrayPrototype (: ArrayInstance), NumberPrototype (: NumberInstance), BooleanPrototype (: BooleanInstance), ErrorPrototype (: ErrorInstance). These bases override GetOwnProperty for integer indices / length and chain base.GetOwnProperty into ObjectInstance, so string method names resolve through the shape store while length/index behavior is unchanged. Array.prototype's hand-written @@iterator===values identity and @@unscopables (symbols, orthogonal to the string shape) are preserved. This confirms shape storage composes across every built-in base class, including the ones with their own [[GetOwnProperty]] overrides. Benchmarks (BuiltinShapeBenchmark, default job, vs prior commit; EngineOnly control byte- identical at 13.70 KB): EngineInitPrototypes (extended to touch these hosts) 86.26 -> 80.55 KB (-5.71 KB). Conformance: full Test262 0 new failures across two runs (iterators, then instance-typed); only the pre-existing annexB RegExp-*-escape-BMP and Atomics.waitAsync concurrent-load flakes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3
…types
Add a [JsAlias("name", "target")] class-level attribute for spec function-identity aliases —
a string own property that shares another generated member's descriptor so the two names
resolve to the very same function object. This removes the final hand-written string-property
tails that blocked shaping (raw SetProperty/AddDangerous lands in _properties, which the shape
lookup ignores).
- BuiltinShape gains a BuiltinSlotKind.Alias whose FunctionSlots holds the target slot index;
MaterializeBuiltinSlot(alias) materializes the target and shares its descriptor. Builder.Alias
resolves the target by name. The generator emits builder.Alias last (own-key order) in the
shape path and, in the dictionary path, AddDangerous with the target's captured descriptor.
- Shape SetPrototype (keys === values), StringPrototype (trimLeft/trimRight === trimStart/trimEnd)
and DatePrototype (toGMTString === toUTCString) via [JsAlias]; their ExtraCapacity + AddDangerous
tails are gone. Symbol aliases (Set/String @@iterator, Date @@toPrimitive) stay hand-written —
symbols are orthogonal to the string shape.
String (49 members) and Date (48) are the largest prototypes and always used, so their per-realm
dictionaries were the biggest single init allocations.
Benchmarks (BuiltinShapeBenchmark, default job, vs prior commit; EngineOnly control byte-identical
at 13.70 KB): EngineInitPrototypes (extended to touch String/Date/Set) 87.54 -> 76.92 KB
(-10.62 KB; storage over EngineOnly -14.4%).
Conformance: full Test262 0 new failures (only the pre-existing annexB RegExp-*-escape-BMP and
Atomics.waitAsync concurrent-load flakes); Jint.Tests.SourceGenerators 30/30 (JintAttributes
snapshot updated for [JsAlias]); the Set combination methods that a naive shaping broke earlier
now pass. Alias smoke: keys===values, trimLeft===trimStart, toGMTString===toUTCString.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3
RegExpPrototype was blocked only by its hand-registered `exec`: HasDefaultExec detects
user replacement by comparing the current exec value's underlying delegate against
_defaultExec, so exec must be a ClrFunction wrapping _defaultExec (a generated [JsFunction]
dispatcher is a different Function subtype and would break the check). Because the check is
on the delegate, not on instance identity, exec fits the existing per-realm instance-slot
mechanism: declare it as a [JsProperty] ClrFunction created in the constructor, filled via
SetBuiltinInstanceDescriptor. No new generator feature needed.
RegExpPrototype (10 accessors + ~15 methods + exec) now shapes; its ExtraCapacity + the raw
_properties.AddDangerous("exec", ...) tail are gone. HasDefaultExec (and the replace/split/
match fast paths that depend on it) is unchanged and verified: replacing RegExp.prototype.exec
is still observed.
Benchmarks (BuiltinShapeBenchmark, default job, vs prior commit; EngineOnly control byte-
identical at 13.70 KB): EngineInitPrototypes (extended to touch RegExp.prototype) 80.44 ->
79.09 KB (-1.35 KB).
Conformance: full Test262 0 new failures (the 4 annexB RegExp-*-escape-BMP timeouts are the
pre-existing concurrent-load flakes — pattern-parsing tests, unrelated to property storage).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3
This was referenced Jul 5, 2026
Merged
lahma
added a commit
that referenced
this pull request
Jul 8, 2026
Re-run after the builtin-shapes rollout and the 2026-07 performance campaign (#2580-#2597). Highlights vs the 4.11.0 refresh: minimal script -47% time / -45% allocation (prepared execution now under a microsecond), evaluation -33% allocation, stopwatch-modern -22% (ahead of NiL.JS, 1.13x behind Jurassic, from 1.44x), object-string -14%, string-base64 -12% (taking the lead from NiL.JS), object-array -11%. Competitor versions unchanged; their rows served as thermal canaries. Claude-Session: https://claude.ai/code/session_01S2U2y9voMQV9rvCkYeQbka Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends the built-in hidden-class shape storage (a process-shared
BuiltinShapelayout + a per-realm lazily-filled descriptor array, from the last release) from the 7BuiltinShapeObjectnamespaces to ~96 built-in hosts across every base class — allPrototype-derived hosts (function-only, accessor-bearing, instance-typed, iterators, and the rootObject.prototype) andFunction-derived constructors. Each shaped host stops allocating a per-realmPropertyDictionaryof lazy descriptors inInitialize.The single blocker was C# single inheritance: prototypes derive from
Prototype/instance types, constructors fromConstructor : Function, so none could also derive fromBuiltinShapeObject. This PR makes the shape storage composable so any[JsObject]host opts in with a one-liner, and it removes the hand-written registration tails (Intl/Temporal intrinsic refs,keys/trimLeft/toGMTString/execaliases) — the "coherent, full-blown generator usage" goal.How it works
InternalTypes.BuiltinShapeModeflag + anIBuiltinShapedstorage interface + logic onObjectInstance(dispatched from the property virtuals viaUnsafe.As<IBuiltinShaped>, mirroring howShapeModeis already handled). The per-realm descriptor field is generator-emitted onto each host, so the million-population bases (ObjectInstance,Function,ArrayInstance, …) pay nothing.BuiltinShapeObjectopts in with[JsObject(UseShape = true)]; the generator emits the field +IBuiltinShapedglue onto it.Constant/Instance/Function/Accessor(GetSetPropertyDescriptor, materialized lazily — leaner than the dictionary path's eagerLazyGetSetPropertyDescriptor) /Alias(new[JsAlias("name","target")]for spec function-identity aliases likeSet.prototype.keys === values).ObjectInstance_propertiesfast paths are gated(_type & (PlainObject | BuiltinShapeMode)) == PlainObject, and theJintMemberExpressionreceiver inline-cache gate broadened toPlainObject | BuiltinShapeMode, so shaped prototypes/constructors keep the version-gated descriptor cache. Redefine mutates the slot in place; add/delete deopts to a dictionary — byte-for-byte the pre-shape representation.Two bugs the verification caught and fixed: a lazy-init fast-path bug (
typeof WeakMap.prototype.get→undefinedon first read, fixed with an_initializedgate) and the string-alias hazard (a naive shaping ofSetPrototypedroppedkeysand broke 74 tests — the reason for[JsAlias]).Benchmarks
Jint.Benchmark/BuiltinShapeBenchmark.cs, default job. Every commit was A/B'd against anEngineOnlycontrol that stayed byte-identical at 13.70 KB (no regression to bare-engine construction, and ordinary-object get/set/create allocation is byte-identical throughout). Per-realmInitializeallocation removed, per commit:[JsIntrinsicReference]Object.prototype, 8× Temporal, Intl[JsAlias]→ Set, String, Dateexec→ instance slot)Summing the batches, the shaped surface eliminates ~61 KB of per-realm property-dictionary allocation (~51 KB prototypes + ~10 KB constructors) when the full built-in surface is exercised, plus the Intl/Temporal cold-start improvements. Final absolute figures (all-shaped):
EngineInitPrototypes79.09 KB andEngineInitConstructors46.54 KB vs the 13.70 KB control.Conformance
annexB RegExp-*-escape-BMPandAtomics.waitAsyncconcurrent-load timeout flakes, which flake identically onmainand pass in isolation).Notes / left on the dictionary path (intentional)
Cross-object aliases (
%TypedArray%.prototype.toString===Array.prototype.toString;Number.parseInt=== globalparseInt), the TypedArray constructor hierarchy, and the intrinsic-reference / thrower-accessor hosts (GlobalObject, Intl/Temporal instances,FunctionPrototype). Extending[JsAlias]to cross-host would unblock the two alias cases; a natural follow-up.🤖 Generated with Claude Code
https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3