Skip to content

[regression] codegen: numeric array-index fast path lost when the array comes from a call — 6.8x slower (v0.5.1255 → main) #6299

Description

@proggeramlug

Summary

Between v0.5.1255 and current main (0960415ad), codegen stopped emitting the guarded numeric fast path for array element access when the array arrives as the return value of a function call. The access falls back to the fully generic js_array_get_index_or_string / js_typed_feedback_array_set_index_or_string path, costing ~6.8x.

This is a codegen-only regression: the lowered HIR is byte-identical between the good and bad compilers.

Repro

function build(): number[] { const arr: number[] = []; for (let i = 0; i < 250000; i++) arr.push(i); return arr; }
function run(): number {
  const arr = build();                 // <-- array arrives from a CALL
  let checksum = 0;
  for (let iter = 0; iter < 25; iter++) {
    for (let i = 0; i < arr.length; i++) { arr[i] = arr[i] + 1; }
    checksum = checksum + arr[0] + arr[arr.length - 1];
  }
  return checksum + arr.length;
}
const t0 = Date.now();
const r = run();
console.log("result", r, "ms", Date.now() - t0);

Measurement

Both binaries linked against the identical v0.5.1255 release runtime archive, so only codegen differs:

codegen time
v0.5.1255 190 ms
main @ 0960415 1300 ms
node 26 19 ms

Evidence

Lowered HIR for run() is identical between the two compilers (--trace hir --focus run), so this is not a lowering/type-inference change. The emitted LLVM differs:

helper (in run) v0.5.1255 main
js_typed_feedback_numeric_array_index_get_guard 3 2
js_typed_feedback_numeric_array_index_set_guard 2 1
js_array_get_index_or_string 2 3
js_typed_feedback_array_set_index_or_string 1 2

The trigger is narrow: the array must arrive as a call's return value, even with an explicit : number[] annotation on both the local and the callee's return type. An array built inline in the same function, or passed in as a number[] parameter, still gets the fast path.

Decision site: crates/perry-codegen/src/expr/index_get.rsexpr_has_numeric_pointer_free_array_layout (guarded path, :1541) vs the generic fallback (:1483).

Window

11 commits touch perry-codegen/perry-hir in 83f4fcba5..0960415ad. HIR being identical rules out the HIR-only commits (#6270, #6245). The only commit in the window that touches the pointer-locals analysis feeding the predicate is ac5263d (#6253), a +155-line change to crates/perry-codegen/src/collectors/pointer_locals.rs which added MAX_FIXPOINT_ITERS/MAX_FIXPOINT_LOCALS curtailment and broadened the statement walk. That is the prime suspect but has not been confirmed by bisect.

This currently contaminates every array-heavy benchmark, including the ones tracked under #5094.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions