Skip to content

Built-in shapes: support per-realm instance properties; shape the Generator prototypes#2557

Merged
lahma merged 1 commit into
sebastienros:mainfrom
lahma:builtin-shapes-instance-props
Jun 29, 2026
Merged

Built-in shapes: support per-realm instance properties; shape the Generator prototypes#2557
lahma merged 1 commit into
sebastienros:mainfrom
lahma:builtin-shapes-instance-props

Conversation

@lahma

@lahma lahma commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Extend the built-in shape path to represent per-realm instance properties — a data property whose value varies per realm, e.g. a prototype's constructor reference — in addition to functions, static-immutable constants, and symbols. This is the most common single member kind that previously blocked shaping a built-in, and it's the foundation for shaping the larger prototype set.

What changed

  • BuiltinShape.Builder.Instance reserves a slot for a per-realm instance property; BuiltinShapeObject.SetBuiltinInstanceDescriptor fills it at initialization (never lazily materialized as a function).
  • The generator emits an instance slot per non-static-immutable [JsProperty] plus a SetBuiltinInstanceDescriptor call in CreateProperties_Generated (slot index = the property's position in the layout). The JINT022 diagnostic no longer rejects instance properties — only accessors / intrinsic references / throwers remain unsupported.
  • Generator.prototype and AsyncGenerator.prototype (3 functions + a constructor instance property each) adopt shapes by simply deriving from BuiltinShapeObject.

Scope notes (documented on BuiltinShapeObject)

  • A shaped built-in's own string properties are exactly those in its shape, so it must declare them all through the generator surface and must not add properties via the raw SetProperty primitive in Initialize. Intl (which registers constructor references from the realm intrinsics that way) stays on the dictionary path.
  • Prototypes that are InternalTypes.PlainObject (most — they derive from the Prototype base) still need member-read fast-path integration before they can be shaped. That's the next, separate change, which would unlock the big ones (Date.prototype = 46 functions, etc.).

Benchmarks (BuiltinShapeBenchmark, default job, vs main)

EngineOnly control identical (13.69 KB).

Benchmark Allocation
EngineInitMath / EngineInitTemporalNow unchanged (15.51 / 19.45 KB)
EngineInitGenerators 20.06 → 19.44 KB (−3.1%)

Conformance & tests

  • Intl 6586/6586 (no regression — Intl deliberately stays dictionary-backed), Math 662, Generators 510.
  • Full Test262: 0 new failures (the annexB/RegExp-*-escape-BMP timeout tests are pre-existing slow-eval flakes under concurrent load).
  • Jint.Tests 3138/3076; Jint.Tests.PublicInterface 79/79; Jint.Tests.SourceGenerators 30/30.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RDS23QeSSNRkaUB2KL74U9

…erator prototypes

Extend the built-in shape path to represent per-realm instance properties (a data
property whose value varies per realm, e.g. a prototype's constructor reference) in
addition to functions, static-immutable constants and symbols. This unlocks shaping
built-ins that were previously blocked only by such a property.

- BuiltinShape.Builder.Instance reserves a slot for a per-realm instance property;
  BuiltinShapeObject.SetBuiltinInstanceDescriptor fills it at initialization. The slot
  is never lazily materialized as a function.
- The generator emits an instance slot per non-static-immutable [JsProperty] and a
  SetBuiltinInstanceDescriptor call in CreateProperties_Generated (slot index = the
  property's position in the layout). The JINT022 diagnostic no longer rejects instance
  properties (only accessors / intrinsic references / throwers remain unsupported).
- Generator.prototype and AsyncGenerator.prototype (3 functions + a constructor instance
  property each) adopt shapes by deriving from BuiltinShapeObject.

A shaped built-in's own string properties are exactly those in its shape, so it must
declare them all through the generator surface and must not add properties via the raw
SetProperty primitive in Initialize (documented on BuiltinShapeObject). Intl, which
registers constructor references from the realm intrinsics that way, stays on the
dictionary path. Prototypes that are InternalTypes.PlainObject (most, deriving from the
Prototype base) still need member-read fast-path integration before they can be shaped —
a separate change.

Benchmarks (BuiltinShapeBenchmark, default job, vs main; EngineOnly control identical at
13.69 KB):

  EngineInitMath / EngineInitTemporalNow   unchanged (15.51 / 19.45 KB)
  EngineInitGenerators                     20.06 → 19.44 KB  (−3.1%)

Conformance: Intl 6586/6586 (no regression), Math 662, Generators 510; full Test262 0 new
failures (the annexB RegExp-*-escape-BMP timeout tests are pre-existing flakes under
concurrent load). Jint.Tests 3138/3076; Jint.Tests.PublicInterface 79/79;
Jint.Tests.SourceGenerators 30/30.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS23QeSSNRkaUB2KL74U9
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