Skip to content

Shape Number/%TypedArray% constructors and %TypedArray%.prototype; add [JsInstanceSlot]#2581

Merged
lahma merged 2 commits into
sebastienros:mainfrom
lahma:shapes-typedarray-number
Jul 5, 2026
Merged

Shape Number/%TypedArray% constructors and %TypedArray%.prototype; add [JsInstanceSlot]#2581
lahma merged 2 commits into
sebastienros:mainfrom
lahma:shapes-typedarray-number

Conversation

@lahma

@lahma lahma commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Follow-up to #2580 — shapes three more built-in hosts, including the last big one, and adds a small reusable generator mechanism for host-computed properties.

  • NumberConstructorNumber.parseInt / parseFloat are the same functions as global parseInt / parseFloat (Jint's ClrFunction equality compares the underlying delegate). They wrap static delegates with no realm dependency, so — like RegExp.prototype.exec in Built-in shapes for prototypes and constructors: composable storage, accessors, aliases #2580 — they become per-realm [JsProperty] ClrFunction instance slots created in the constructor. Hand-written SetProperty tail + ExtraCapacity gone.
  • IntrinsicTypedArrayConstructor (%TypedArray%) — clean (from/of + @@species); opts in directly.
  • New [JsInstanceSlot("name")] — reserves a per-realm own-property slot (appended after all other own properties) that the host fills in Initialize via SetBuiltinSlotByName(name, descriptor), for a computed/lazy value the generator can't express (specifically a cross-object alias).
  • IntrinsicTypedArrayPrototype (%TypedArray%.prototype, 37 members: 10 accessors, ~20 methods, @@iterator === values) — its toString is the same function object as %Array.prototype.toString%, a lazy cross-object alias, now expressed via [JsInstanceSlot]. Resolution stays lazy, so touching %TypedArray%.prototype doesn't force Array init.

Benchmarks

Jint.Benchmark/BuiltinShapeBenchmark.cs, default job. Each commit A/B'd against a byte-identical EngineOnly control (13.70 KB); per-realm Initialize allocation removed:

Commit Δ
NumberConstructor + %TypedArray% constructor EngineInitConstructors 50.51 → 49.58 KB (−0.93 KB)
[JsInstanceSlot] + %TypedArray%.prototype EngineInitPrototypes 84.83 → 81.14 KB (−3.69 KB)

Conformance

  • Full Test262: 0 new failures on both commits (only the pre-existing annexB RegExp-*-escape-BMP concurrent-load timeout flakes).
  • Jint.Tests.SourceGenerators 30/30 (snapshot updated for the new attribute).

Remaining (deliberately on the dictionary path)

The TypedArray constructor hierarchy (Uint8ArrayConstructor would re-implement IBuiltinShaped with only its own members, dropping the inherited BYTES_PER_ELEMENT from the abstract base's shape — needs generator support for inherited [JsObject] members), RegExpConstructor legacy statics, and the intrinsic-reference / thrower hosts (GlobalObject, Intl/Temporal instances, FunctionPrototype).

🤖 Generated with Claude Code

https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3

lahma and others added 2 commits July 5, 2026 22:10
- NumberConstructor: Number.parseInt / parseFloat are the same functions as the global
  parseInt / parseFloat (Jint's ClrFunction equality compares the underlying delegate). They
  wrap static delegates with no realm dependency, so — like RegExp exec — they become per-realm
  [JsProperty] ClrFunction instance slots created in the constructor. The hand-written SetProperty
  tail + ExtraCapacity are gone.
- IntrinsicTypedArrayConstructor (%TypedArray%): clean (from/of + @@species symbol accessor);
  opts in directly.

Benchmarks (BuiltinShapeBenchmark, default job, vs prior commit; EngineOnly control byte-
identical at 13.70 KB): EngineInitConstructors (extended to touch Number/%TypedArray%)
50.51 -> 49.58 KB (-0.93 KB).

Conformance: full Test262 0 new failures (only the pre-existing annexB RegExp-*-escape-BMP
concurrent-load flakes).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Fq5mF1QEwh2qDMD8vVwt3
…totype

Add a [JsInstanceSlot("name")] class-level attribute that reserves a per-realm own-property
slot (appended after all other own properties, matching a hand-written SetProperty tail) which
the host fills in Initialize via SetBuiltinSlotByName(name, descriptor). This expresses a
computed/lazy value the generator can't — specifically a cross-object alias.

Use it for %TypedArray%.prototype.toString, which per spec is the SAME function object as
%Array.prototype.toString% (a different-host alias resolved lazily per realm). This unblocks the
37-member IntrinsicTypedArrayPrototype (10 accessors, ~20 methods, @@iterator === values); its
ExtraCapacity + the raw _properties.AddDangerous("toString", ...) tail are gone. Resolution stays
lazy, so touching %TypedArray%.prototype does not force Array init.

Benchmarks (BuiltinShapeBenchmark, default job, vs prior commit; EngineOnly control byte-
identical at 13.70 KB): EngineInitPrototypes (extended to touch %TypedArray%.prototype)
84.83 -> 81.14 KB (-3.69 KB).

Conformance: full Test262 0 new failures (only the pre-existing annexB RegExp-*-escape-BMP
concurrent-load flakes); Jint.Tests.SourceGenerators 30/30 (snapshot updated for the attribute).

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