Skip to content

Array index width: migrate ToLength/ToIndex from Int to Int64 for spec conformance #307

Description

@dowdiness

Problem

MoonBit's Int is 32-bit (max ≈ 2³¹−1 ≈ 2.1 billion). JavaScript's ToLength caps at 2⁵³−1 ≈ 9 quadrillion. When test262 exercises array-like objects with .length = 2**53 - 1 or iterates at indices near 2⁵³, our engine overflows to a large negative number.

Example failure (Array.prototype.splice/length-near-integer-limit-grow-array.js):

Expected SameValue(«-2147483648», «9007199254740991»)

-2147483648 is Int.min_value — a classic 32-bit overflow.

Affected test262 tests (ES2016 strict, 11 total)

Failures (7):

  • built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-proxy.js
  • built-ins/Array/prototype/slice/length-exceeding-integer-limit-proxied-array.js
  • built-ins/Array/prototype/slice/length-exceeding-integer-limit.js
  • built-ins/Array/prototype/splice/length-and-deleteCount-exceeding-integer-limit.js
  • built-ins/Array/prototype/splice/length-exceeding-integer-limit-shrink-array.js
  • built-ins/Array/prototype/splice/length-near-integer-limit-grow-array.js
  • built-ins/Array/prototype/toSorted/length-exceeding-array-length-limit.js
  • built-ins/Array/prototype/toSpliced/length-clamped-to-2pow53minus1.js
  • built-ins/Array/prototype/toSpliced/length-exceeding-array-length-limit.js
  • built-ins/Array/prototype/includes/length-boundaries.js

Timeouts (6):

  • built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-object.js
  • built-ins/Array/prototype/splice/clamps-length-to-integer-limit.js
  • built-ins/Array/prototype/splice/create-species-length-exceeding-integer-limit.js
  • built-ins/Array/prototype/splice/throws-if-integer-limit-exceeded.js
  • built-ins/Array/prototype/toReversed/length-exceeding-array-length-limit.js
  • built-ins/Array/prototype/with/length-exceeding-array-length-limit.js

All classified as ES2016 because the tests use 2**53 literal syntax (the exponentiation feature flag), not because they test the ** operator itself.

Root cause

to_array_like_length_interp returns Int. Every array built-in loop counter is Int. When a Double like 9007199254740990.0 is converted via .to_int(), it overflows to a large negative number. The subsequent for i = start; i < len loop either never runs, runs forever (timeout), or produces wrong indices.

Fix

  1. Change to_array_like_length_interp to return Int64.
  2. Update every array built-in that loops over an array-like object to use Int64 counters (MoonBit for loop variables are Int, so these become while loops with Int64).
  3. Update fromIndex, start, end, k local variables in: includes, indexOf, lastIndexOf, slice, splice, reverse, sort, copyWithin, fill, find, findIndex, findLast, findLastIndex, every, some, forEach, map, filter, reduce, reduceRight, flat, flatMap, toSorted, toSpliced, toReversed, with, at.
  4. Update TypedArray variants similarly.

This is a pervasive but mechanical change — roughly 20+ files in interpreter/stdlib/.

Real-world impact

None in practice. No real JavaScript array holds more than ~2³¹ elements (that would require ≥ 16 GB of memory for a dense array of 64-bit values). These are spec-compliance edge cases only.

Interim mitigation

These 16 tests are currently tracked as unresolved ES2016 failures. Adding them to the skip list with a reason: int64-array-index-unsupported tag is an option while this issue is open.

Metadata

Metadata

Assignees

No one assigned

    Labels

    architectureInternal architecture / unification / cross-cutting refactor

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions