Skip to content

Answer inherited Object.prototype members for computed-key dynamic reads - #2057

Draft
cramforce wants to merge 6 commits into
mainfrom
fix/inherited-computed
Draft

cramforce wants to merge 6 commits into
mainfrom
fix/inherited-computed

Conversation

@cramforce

@cramforce cramforce commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Natively, o[k] with k naming constructor, toString, valueOf, hasOwnProperty or propertyIsEnumerable read undefined on a plain object, while the constant-key read o.toString answered the inherited member. Computed string keys and dyn keys now fall back through scr_dyn_inherited_read the same way.

Computed keys are built at run time, so every program with a computed dynamic read must link the fallback. To keep that cheap, the fallback moves out of scr_dyn_invoke.c (which also pulled in scr_async_dyn.c) into two small units that reference only the base units:

  • scr_dyn_inherited.c: the five-member fallback, Object.prototype's methods as values and the interned builtin constructors. The new dynInherited feature links it for computed-key reads and for constant keys naming one of the five members. The dyn-invoke unit links it too.
  • scr_dyn_global_construct.c: new through those constructors, which builds dates and collections. The dyn-invoke unit links it, and so do programs that construct dynamic values and also read inherited members; those programs install it at start through dyn.globalConstructInstall.

Evidence: corpus 8113-computed-inherited-member-reads.js, 8114-computed-inherited-member-unknown.ts and 8116-computed-inherited-construct.js, with order baselines and CI costs recorded. All three fail on main and match Node in the plain and sanitized lanes. The 525 corpus programs whose executables change also pass the plain differential.

Zero-cost gate against main, full sets (bench, self and the TypeScript corpus):

  • Typed benchmarks are identical. The seven dynamic workloads grow by +96 B each.
  • 143 corpus programs with computed dynamic reads grow by 5.5–31.6 KB (median +10 KB).
  • 6 programs that also construct dynamic values grow by about 110 KB.
  • 18 programs whose constant-key inherited reads used to link the dyn-invoke unit shrink by up to 206 KB.
  • The rest are relinks of +96 B.

The full list is in the verification comment.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
scriptc Ready Ready Preview, v0 Oct 24, 2026 2:46am UTC

cramforce and others added 4 commits October 23, 2026 17:49
o[k] with k naming constructor, toString, valueOf, hasOwnProperty or
propertyIsEnumerable read undefined on a plain object, while o.toString
answered the member. Computed string and dyn keys now fall back through
scr_dyn_inherited_read like constant keys, and link scr_dyn_invoke.c.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ime unit

Computed-key dynamic reads may name an inherited member at run time, so
every such program needs the fallback. It lived in scr_dyn_invoke.c, which
also pulled scr_async_dyn.c into those programs. scr_dyn_inherited.c now
holds the fallback, Object.prototype's methods as values and the interned
builtin constructors, over the base units only; the dynInherited feature
links it for computed keys and constant keys naming one of the five
members, and the dyn-invoke unit links it too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The interned constructors' `new` support builds dates and collections and
pulled the date, time-zone and collection code into every program with a
computed dynamic read. It moves to scr_dyn_global_construct.c, which the
dyn-invoke unit links and which programs that also construct dynamic
values install at start (dyn.globalConstructInstall). Corpus 8116 pins
construction through computed and constant constructor reads in a program
without method dispatch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cramforce

Copy link
Copy Markdown
Contributor Author

Verification for 8cb80e6, rebased onto origin/main 4206155. The later head adds only the corpus cost files.

Runtime unit split. Computed keys are built at run time, so every program with a computed dynamic read needs the inherited-member fallback, and restricting the link would be unsound. Before this change, the fallback pulled scr_dyn_invoke.c and scr_async_dyn.c into all of those programs. It now lives in two small units that reference only the base units:

  • scr_dyn_inherited.c holds the five-member fallback, Object.prototype's methods as values and the interned builtin constructors. The new dynInherited feature links it for computed-key reads and for constant keys naming one of the five members. The dyn-invoke unit links it too.
  • scr_dyn_global_construct.c holds new through those constructors, which builds dates and collections and so brings in the date, time-zone and collection code (~90 KB). Only programs that can use it link it: the dyn-invoke unit, and programs that construct dynamic values and also read inherited members. Those programs install it at start through dyn.globalConstructInstall.

Differential. Corpus 8113, 8114 and the new 8116 (construction through computed and constant constructor reads in a program without method dispatch) fail on main and match Node in both lanes, through differential.test.ts and llvm-differential.test.ts, plain and sanitized. Every one of the 525 corpus programs whose executable changed also passes the plain differential.

Zero-cost gate against main 4206155, full sets: bench, self and the TypeScript corpus. Run without --allow, so the verdict is FAIL and the differences are listed below.

  • Typed benchmarks: all identical. The 7 differing benchmarks are all in DYNAMIC_WORKLOADS (atomics-contended, channel-messages, dynamic-methods, intern-table, thread-slots, typed-array-scan-workers, worker-messages). Each grows +96 B, a relink of programs that link the dyn-invoke unit. Bench geomean -0.39% [95% CI -0.85%, -0.08%].
  • self/cli: its LLVM differs because its computed dynamic reads now call the fallback. Compile time -0.87%, within tolerance.
  • TypeScript corpus, 2958 programs: 2433 identical, 525 differing.
    • 143 grow by 5.5–31.6 KB (median +10.4 KB, 0.3–7.3%). These are programs with computed dynamic reads, which now link scr_dyn_inherited.c (~14 KB of code). The gate also reports that they gain dynamic-tier symbols (scr_dyn_key_probe_computed, scr_dyn_property_*), all in programs that already use dynamic values.
    • 6 grow by 103–113 KB: 5820-node-stream-dyn-constructor-overrides, 6406-npm-instance-receiver, 6480-node-stream-dyn-readable, 6482-node-stream-dyn-helpers, 6494-events-once-dyn-stream-slot, 7037-js-var-open-writes. They construct dynamic values and read inherited members, so they link the constructor unit.
    • 18 shrink by up to 206 KB. Their constant-key inherited reads no longer link the dyn-invoke and dyn-async units. Examples: 4795-published-untyped-member-reads -206 KB, 5911-dyn-class-to-primitive -193 KB, 4455-live-view-reads-without-stores -193 KB.
    • 358 change by +88 B to +5 KB (almost all +96 B). These programs already linked the dyn-invoke unit and are relinked now that the moved code sits in its own units.
Programs that grow by more than 5 KB (program, baseline bytes, growth)
6406-npm-instance-receiver/main.ts	568048	+112952
7037-js-var-open-writes/main.ts	775488	+112096
6480-node-stream-dyn-readable/main.ts	2105760	+111672
6494-events-once-dyn-stream-slot/main.ts	1964440	+107560
5820-node-stream-dyn-constructor-overrides/main.ts	799072	+103744
6482-node-stream-dyn-helpers/main.ts	979336	+103560
3126-js-number-radix/main.ts	431864	+31560
1558-any-joins-and-dyn-validation.ts	528360	+31560
2584-union-dyn-collapse.ts	487032	+31528
762-any-boundary.ts	457032	+27520
2365-dyn-into-island.ts	452944	+27512
5197-object-entries-dynamic-objects.ts	523496	+27496
declared-index-spread.ts	473184	+27480
reflect-typed-record-keys.ts	419744	+27472
7000-umd-package-entry/main.ts	438232	+27472
5323-dyn-numeric-index-reads.ts	466256	+27464
1574-dyn-optional-method-number-keys.ts	529712	+27464
5972-net-set-encoding-listeners.ts	658608	+27432
3102-json-unknown-fields.ts	453008	+27400
5081-boolean-array-dynamic-views.ts	512168	+27368
6346-inspect-dyn-dataview.ts	444576	+26128
6480-boolean-callbacks.ts	436064	+23504
6043-string-index-narrowed-union.ts	369568	+23504
5792-json-parse-repeated-layouts.ts	510304	+23472
2043-any-dom-values.ts	431400	+23464
5341-compound-any-operand.ts	508784	+23456
6248-tagged-template-any-rest.ts	384664	+23432
checked-array-assignment.ts	420424	+23424
6182-interface-overload-types.ts	506408	+23424
5521-dyn-property-read-keys.ts	445608	+23424
2692-inline-record-assert-index.ts	414840	+23424
5262-record-unknown-many.ts	402824	+23416
2557-width-field-lifts.ts	397168	+23416
7446-crypto-rsa-key-pair-errors.ts	1083688	+23384
6249-tagged-template-missing-substitutions.ts	375328	+23376
arguments-reexport/main.ts	404904	+23368
1551-dyn-receiver-methods.ts	622736	+23368
native-class-array-boundaries.ts	404072	+23344
checked-proxy-callback/main.ts	418288	+23344
7749-text-codec-unknown-roundtrip.ts	634336	+23336
7404-frozen-records.ts	479608	+23336
7262-fresh-literal-untyped-param/main.ts	485392	+23336
7007-filter-written-type-predicates.ts	484384	+23336
6252-fetch-input-url-unions.ts	1790744	+23336
6147-jsval-any-operators.ts	496800	+23336
2678-util-parseargs.ts	649392	+23336
1746-stream-for-await.ts	580256	+23336
6156-cjs-function-members-from-ts/main.ts	441624	+23328
5466-dyn-index-read-special.ts	457584	+23304
5791-dyn-constant-key-read-sites.ts	531152	+23296
5465-dyn-index-read-arrays.ts	447216	+23296
5141-os-constants.ts	518368	+23176
6913-builtin-constructor-shorthand.ts	477792	+22824
765-any-optional-chain.ts	503224	+18600
7006-evolving-array-aliases.ts	602888	+18592
6560-npm-js-capability-probes/main.ts	654672	+18544
4593-weak-keys-empty-objects.ts	536392	+14536
unknown-object-enumeration.ts	655168	+14504
record-unknown-values.ts	659904	+14504
6452-promisify-untyped-functions.ts	605232	+14504
5430-dyn-number-string-boxes.ts	586544	+14504
5196-object-values-typed-as-unknown.ts	575128	+14504
2170-island-array-exits.ts	632768	+14504
7001-package-declared-types/main.ts	510976	+14496
generator-checked-protocol.ts	564024	+14448
5322-json-stringify-parsed-trees.ts	605776	+14448
5175-forin-typed-as-unknown.ts	431928	+14448
7731-npm-any-string-index/main.ts	609040	+14400
4610-array-ext-dyn-refresh.ts	702024	+14400
4083-dynamic-import-failure/main.ts	558032	+14352
5933-class-fields-unknown-object.ts	651088	+14344
5715-json-parse-fitted-tables.ts	653448	+14304
worker-class-instance-clone.ts	789800	+14232
4930-typed-record-reflection.ts	603376	+14192
collection-ingestion.ts	606680	+10488
collection-storage-copies.ts	606080	+10480
6583-emitter-untyped-surface.ts	611968	+10448
5324-structured-clone-documents.ts	557832	+10448
checked-collection-symbol-methods.ts	568944	+10440
6245-rest-unknown-handlers.ts	663968	+10440
1544-dyn-json-reads.ts	411664	+10432
class-fetch-handle-fields.ts	1780936	+10408
checked-array-flat/main.ts	550256	+10408
761-any-objects.ts	597272	+10408
7451-crypto-diffie-hellman.ts	1386656	+10408
5837-util-format-json-circular.ts	565792	+10408
5349-object-entries-values-optional.ts	552928	+10408
5321-json-parse-cycles.ts	622928	+10408
6909-empty-object-type-values.ts	582192	+10400
5250-cipher-aes-gcm.ts	947936	+10400
5086-promise-any-turns.ts	656400	+10400
4636-contract-program-lifetime-references.ts	700736	+10400
class-checked-composites.ts	545496	+10368
5520-dyn-property-read-receivers.ts	605088	+10368
7748-npm-any-bytes-receiver/main.ts	1933760	+10360
7014-js-never-array-literal-fields/main.ts	593384	+10360
6471-any-method-chains.ts	690808	+10360
6410-json-mixed-scalar-tables/main.ts	721016	+10352
4091-class-evaluation-deferred.ts	556096	+10352
6414-catch-values-roundtrip.ts	594168	+10256
native-worker-publish-classes.ts	918224	+10248
5051-typed-record-prototypes.ts	501360	+10248
native-worker-class-fields.ts	656448	+10200
native-worker-message-graphs.ts	719240	+10160
4931-typed-data-generic-walks.ts	661824	+10144
4598-live-array-ref-element-access.ts	647896	+10144
5930-method-census-asserted-number-keys.ts	463336	+10136
6470-any-destructuring.ts	690312	+10104
6419-untyped-async-package/main.ts	813192	+10104
6350-globalthis-assertion-state.ts	605872	+10104
5245-event-target-subclass-signals.ts	1776736	+10104
typed-prototype-methods.ts	485560	+10096
5819-node-stream-dyn-direct-pipe/main.ts	1970200	+10056
cjs-class-hierarchy-npm/main.ts	845248	+10048
7362-globalthis-intersection-singleton.ts	495896	+10048
6402-override-js-base/main.ts	527624	+10040
caught-class-identity.ts	448304	+9976
5681-array-pop-and-length.ts	524256	+9976
6925-instanceof-dynamic-constructors.ts	843272	+9624
5858-disposable-stack.ts	621032	+8744
2585-unknown-array.ts	565952	+6312
6412-any-valued-dictionaries.ts	669872	+6272
checked-byte-storage/main.ts	563408	+6256
6580-npm-dyn-for-await/main.ts	721112	+6256
6352-globalthis-state-modules/main.ts	604888	+6256
5133-abort-signal-event-target.ts	1820856	+6256
native-worker-published-graphs.ts	736304	+6152
5870-worker-thread-names.ts	762528	+6152
5916-dyn-error-stack-property.ts	640744	+6144
5808-worker-unhandled-rejections.ts	741064	+6104
2973-http-static-agent.ts	786760	+6056
5150-small-array-inline-slots.ts	693424	+6048
6824-jsx-automatic-runtime/main.ts	633208	+6008
generator-custom-delegation/main.ts	618600	+6000
5956-erased-generic-members.ts	742896	+6000
5765-class-structural-view-identity.ts	630376	+6000
5240-event-target-subclass.ts	714776	+6000
class-symbol-accessors.ts	434264	+5992
array-element-compound-updates.ts	525928	+5992
5243-event-target-subclass-dynamic.ts	686944	+5960
class-computed-presence.ts	440224	+5952
5849-class-view-observations.ts	482824	+5952
5764-class-structural-view-writes.ts	485056	+5952
5246-event-target-subclass-listener-throw.ts	468792	+5944
6481-node-stream-dyn-writable/main.ts	746920	+5912
7365-class-methods-untyped-computed-writes/main.ts	684920	+5896
6592-promise-armed-method-values/main.ts	1104304	+5896
5680-array-growth-after-copy.ts	499736	+5888
6914-dynamic-builtin-construct.ts	713104	+5504

…ition

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — 148e0d85 Deployed Oct 24, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant