Skip to content

runtime: migrate array-like lengths to Int64#461

Merged
dowdiness merged 4 commits into
mainfrom
arch/int64-index-migration
Jun 25, 2026
Merged

runtime: migrate array-like lengths to Int64#461
dowdiness merged 4 commits into
mainfrom
arch/int64-index-migration

Conversation

@dowdiness

Copy link
Copy Markdown
Owner

Summary

  • migrate runtime ToLength/ToIndex and array-like element helpers from MoonBit Int to Int64
  • preserve sparse/high array index semantics for array methods, DefineOwnProperty, own-key ordering, and species creation
  • keep ArrayBuffer/DataView/TypedArray allocation/indexing bounded when converting back to MoonBit Int
  • remove the int64-array-index (#307) Test262 skip entries now covered by the migration

Refs #392, #307.

Testing

Known baseline issue

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@dowdiness, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 8 minutes and 52 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 24f58ddf-337c-417d-90fb-485ac320d577

📥 Commits

Reviewing files that changed from the base of the PR and between a4d48b8 and 4a5d2d2.

📒 Files selected for processing (22)
  • interpreter/interpreter_test.mbt
  • interpreter/runtime/array_like.mbt
  • interpreter/runtime/array_like_wbtest.mbt
  • interpreter/runtime/call.mbt
  • interpreter/runtime/conversions.mbt
  • interpreter/runtime/conversions_wbtest.mbt
  • interpreter/runtime/iterators.mbt
  • interpreter/runtime/own_property_keys.mbt
  • interpreter/runtime/pkg.generated.mbti
  • interpreter/runtime/property_own.mbt
  • interpreter/runtime/property_set.mbt
  • interpreter/stdlib/array_indexed_mutators.mbt
  • interpreter/stdlib/array_sort.mbt
  • interpreter/stdlib/builtins_array_init.mbt
  • interpreter/stdlib/builtins_arraybuffer.mbt
  • interpreter/stdlib/builtins_dataview.mbt
  • interpreter/stdlib/builtins_json.mbt
  • interpreter/stdlib/builtins_object_integrity.mbt
  • interpreter/stdlib/builtins_reflect.mbt
  • interpreter/stdlib/builtins_typedarray.mbt
  • scripts/test262_skip_metadata.json
  • tooling/test262_metadata/metadata_wbtest.mbt
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch arch/int64-index-migration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 628e621550

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread interpreter/runtime/array_like.mbt Outdated
Comment on lines 615 to 620
let _ = interp.define_own_property(
target,
index.to_string(),
value,
String_(index.to_string()),
PartialDescriptor::data_default(value),
@token.Loc::default(),
strict=true,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Throw when CreateDataPropertyOrThrow is rejected

For custom species methods such as an Array subclass whose Symbol.species constructor returns Object.preventExtensions({}), CreateDataPropertyOrThrow must throw if defining the result index returns false. This branch now ignores the Boolean from define_own_property, so map/slice/concat can silently return a non-extensible result without the copied element (and then set length), whereas the old strict set_property path raised.

Useful? React with 👍 / 👎.

Comment on lines +871 to +872
if new_len > ARRAY_MAX_SAFE_LENGTH_I64 {
raise @errors.TypeError(message="Invalid array length")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Check splice length overflow before species creation

When len + insertCount - actualDeleteCount exceeds the max safe integer, the spec requires the TypeError before ArraySpeciesCreate, but this new check runs only after creating and populating the deleted array. With a custom constructor[Symbol.species], splice will call user code and may copy deleted values before throwing, so overflow cases have observable side effects that should not occur.

Useful? React with 👍 / 👎.

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

Run: https://github.com/dowdiness/js_engine/actions/runs/28181056771

startup/tiny_program is the PR #153 / issue #141 guardrail for built-in realm-stamping startup cost.

Stage summary

stage benchmarks total mean slowest benchmark slowest mean noisy rows
startup 3 2.317 ms startup/tiny_program 1.177 ms 0
frontend 7 0.987 ms pipeline/parse_heavy 0.568 ms 2
execution 26 15184.089 ms exec/fibonacci_30 13652.451 ms 2

Focused bytecode base-vs-head comparison

Base-vs-head deltas are reporting-only. Negative delta and PR/base < 1.00x mean the PR is faster; interpret high-CV or noisy rows cautiously.

benchmark stage base mean PR mean delta PR/base base CV PR CV noisy
baseline/bytecode/closure_factory execution 14.476 ms 14.102 ms -2.6% 0.97x 6.0% 9.8% no
pipeline/bytecode/evaluate execution 9.169 ms 9.875 ms +7.7% 1.08x 3.5% 14.4% no
isolate/bytecode/call_frame execution 7.876 ms 7.505 ms -4.7% 0.95x 5.2% 0.9% no
isolate/bytecode/runtime_helpers execution 11.150 ms 11.248 ms +0.9% 1.01x 0.6% 3.9% no
isolate/bytecode/local_access execution 39.728 ms 38.793 ms -2.4% 0.98x 3.9% 1.9% no
isolate/bytecode/env_access execution 39.619 ms 37.714 ms -4.8% 0.95x 3.3% 3.5% no
isolate/bytecode/captured_access execution 38.381 ms 37.457 ms -2.4% 0.98x 4.8% 2.4% no
isolate/bytecode/dispatch_stack execution 23.710 ms 24.091 ms +1.6% 1.02x 1.7% 2.2% no

Base-vs-head comparison

benchmark stage base mean PR mean delta PR/base base CV PR CV noisy
startup/tiny_program startup 1.352 ms 1.177 ms -12.9% 0.87x 11.4% 8.0% no
lexer/small frontend 0.036 ms 0.035 ms -1.6% 0.98x 50.6% 29.3% base, PR
lexer/large frontend 0.310 ms 0.300 ms -3.3% 0.97x 1.0% 0.6% no
exec/fibonacci_30 execution 14026.637 ms 13652.451 ms -2.7% 0.97x 1.3% 0.9% no
exec/property_chain execution 15.023 ms 15.142 ms +0.8% 1.01x 10.5% 7.1% no
startup/phase/parse_tiny frontend 0.002 ms 0.002 ms -0.6% 0.99x 0.6% 1.3% no
startup/phase/new_interpreter startup 1.267 ms 1.140 ms -10.0% 0.90x 12.5% 12.2% no
startup/phase/execute_preparsed_tiny execution 0.000 ms 0.000 ms -4.8% 0.95x 1.2% 0.9% no
startup/phase/event_loop_drain_empty startup 0.000 ms 0.000 ms -3.2% 0.97x 1.0% 2.7% no
startup/phase/result_stringify_output execution 0.000 ms 0.000 ms +0.9% 1.01x 0.5% 3.9% no
exec/array_map_filter execution 21.411 ms 20.723 ms -3.2% 0.97x 21.1% 18.8% base, PR
exec/closure_factory execution 30.387 ms 29.382 ms -3.3% 0.97x 6.4% 5.8% no
baseline/closure_legacy/closure_factory execution 28.227 ms 27.429 ms -2.8% 0.97x 9.2% 9.3% no
baseline/bytecode/closure_factory execution 14.476 ms 14.102 ms -2.6% 0.97x 6.0% 9.8% no
isolate/bytecode/dispatch_stack execution 23.710 ms 24.091 ms +1.6% 1.02x 1.7% 2.2% no
isolate/bytecode/local_access execution 39.728 ms 38.793 ms -2.4% 0.98x 3.9% 1.9% no
isolate/bytecode/env_access execution 39.619 ms 37.714 ms -4.8% 0.95x 3.3% 3.5% no
isolate/bytecode/captured_access execution 38.381 ms 37.457 ms -2.4% 0.98x 4.8% 2.4% no
isolate/bytecode/call_frame execution 7.876 ms 7.505 ms -4.7% 0.95x 5.2% 0.9% no
isolate/bytecode/runtime_helpers execution 11.150 ms 11.248 ms +0.9% 1.01x 0.6% 3.9% no
isolate/bytecode/property_get execution 43.592 ms 44.698 ms +2.5% 1.03x 2.0% 1.9% no
isolate/bytecode/property_set execution 40.561 ms 40.302 ms -0.6% 0.99x 1.4% 1.7% no
isolate/bytecode/method_call execution 8.861 ms 8.306 ms -6.3% 0.94x 1.5% 0.5% no
isolate/bytecode/object_literal execution 13.555 ms 13.195 ms -2.7% 0.97x 0.6% 3.0% no
isolate/bytecode/array_literal execution 14.626 ms 15.453 ms +5.7% 1.06x 1.4% 1.4% no
exec/for_of execution 6.109 ms 6.805 ms +11.4% 1.11x 10.2% 6.8% no
exec/arithmetic_loop execution 977.314 ms 1065.039 ms +9.0% 1.09x 1.3% 0.5% no
exec/object_construction execution 7.856 ms 7.740 ms -1.5% 0.99x 7.6% 9.0% no
exec/string_ops execution 2.061 ms 1.935 ms -6.1% 0.94x 24.7% 23.8% base, PR
pipeline/exec/lex frontend 0.031 ms 0.031 ms +1.2% 1.01x 0.4% 0.6% no
pipeline/exec/parse frontend 0.027 ms 0.027 ms +0.2% 1.00x 3.2% 3.4% no
pipeline/exec/evaluate execution 28.228 ms 28.240 ms +0.0% 1.00x 6.8% 12.6% no
pipeline/closure_legacy/evaluate execution 26.361 ms 26.463 ms +0.4% 1.00x 4.9% 10.6% no
pipeline/bytecode/compile frontend 0.022 ms 0.024 ms +13.3% 1.13x 26.9% 19.4% base, PR
pipeline/bytecode/evaluate execution 9.169 ms 9.875 ms +7.7% 1.08x 3.5% 14.4% no
pipeline/parse_heavy frontend 0.525 ms 0.568 ms +8.1% 1.08x 7.2% 13.3% no

Mean-time chart (log scale)

benchmark stage mean chart
startup/tiny_program startup 1.177 ms ##
lexer/small frontend 0.035 ms ⚠ #
lexer/large frontend 0.300 ms #
exec/fibonacci_30 execution 13652.451 ms ##############################
exec/property_chain execution 15.142 ms ########
startup/phase/parse_tiny frontend 0.002 ms #
startup/phase/new_interpreter startup 1.140 ms ##
startup/phase/execute_preparsed_tiny execution 0.000 ms #
startup/phase/event_loop_drain_empty startup 0.000 ms #
startup/phase/result_stringify_output execution 0.000 ms #
exec/array_map_filter execution 20.723 ms ⚠ #########
exec/closure_factory execution 29.382 ms ##########
baseline/closure_legacy/closure_factory execution 27.429 ms ##########
baseline/bytecode/closure_factory execution 14.102 ms ########
isolate/bytecode/dispatch_stack execution 24.091 ms ##########
isolate/bytecode/local_access execution 38.793 ms ###########
isolate/bytecode/env_access execution 37.714 ms ###########
isolate/bytecode/captured_access execution 37.457 ms ###########
isolate/bytecode/call_frame execution 7.505 ms ######
isolate/bytecode/runtime_helpers execution 11.248 ms #######
isolate/bytecode/property_get execution 44.698 ms ############
isolate/bytecode/property_set execution 40.302 ms ###########
isolate/bytecode/method_call execution 8.306 ms #######
isolate/bytecode/object_literal execution 13.195 ms ########
isolate/bytecode/array_literal execution 15.453 ms ########
exec/for_of execution 6.805 ms ######
exec/arithmetic_loop execution 1065.039 ms #####################
exec/object_construction execution 7.740 ms ######
exec/string_ops execution 1.935 ms ⚠ ###
pipeline/exec/lex frontend 0.031 ms #
pipeline/exec/parse frontend 0.027 ms #
pipeline/exec/evaluate execution 28.240 ms ##########
pipeline/closure_legacy/evaluate execution 26.463 ms ##########
pipeline/bytecode/compile frontend 0.024 ms ⚠ #
pipeline/bytecode/evaluate execution 9.875 ms #######
pipeline/parse_heavy frontend 0.568 ms #

Closure-conversion comparison

  • unavailable

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a243dc57cd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +54 to +56
} else if n.is_inf() {
if n < 0.0 {
-ARRAY_MAX_SAFE_LENGTH_I64

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve -Infinity for relative indices

When n is -Infinity, saturating it to -ARRAY_MAX_SAFE_LENGTH_I64 makes callers that add the index to a max-safe length treat it as index 0. For example, Array.prototype.at.call({0: 'x', length: 9007199254740991}, -Infinity) would return 'x', and lastIndexOf(..., -Infinity) can search index 0, but ToIntegerOrInfinity should keep this out of range. Preserve an infinity sentinel or special-case these relative-index callers instead of clamping negative infinity.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7c6106304f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

let o = to_object(source, interp)
let len = @runtime.to_array_like_length_interp(o, interp)
for i = 0; i < len; i = i + 1 {
for i = 0L; i < len; i = i + 1L {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Check Array.from length before the element loop

When Array.from is used on a non-iterable array-like whose length is now representable as an Int64 but is too large for an Array result, this loop reads index properties before the result constructor can reject the length. For example, Array.from({ length: 2 ** 32, get 0() { throw err; } }) should throw the Array constructor's RangeError before accessing 0, but this path invokes the getter first (or loops billions of times if there is no early throw). Add the ArrayCreate/constructor length check before entering the array-like element loop.

Useful? React with 👍 / 👎.

let array_like = to_object(source, interp)
let len = @runtime.to_array_like_length_interp(array_like, interp)
for i = 0; i < len; i = i + 1 {
for i = 0L; i < len; i = i + 1L {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Check TypedArray.from length before collecting elements

The array-like branch of TypedArray.from now accepts an Int64 length but still collects every source element before constructing the typed-array result. For sources with a length the constructor would reject in this runtime, such as Int8Array.from({ length: 2147483648, get 0() { throw err; } }), the getter runs or the loop hangs instead of throwing the constructor/allocation RangeError before element access. Validate/construct from len before this collection loop.

Useful? React with 👍 / 👎.

@dowdiness dowdiness merged commit 9b89b6c into main Jun 25, 2026
15 checks passed
@dowdiness dowdiness deleted the arch/int64-index-migration branch June 25, 2026 16:00
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