Skip to content

codegen: perry_method_<Class>__<name> emission order is HashMap-nondeterministic when a method name is shared across classes (#7038/#7039 family) #7172

Description

@proggeramlug

Found during PR #7171's IR-neutrality verification (macOS arm64, same-compiler control runs): emitted LLVM IR is nondeterministic when a method name is shared across classes — perry_method_<Class>__<name> symbols are emitted in HashMap iteration order, so two runs of the same compiler on the same source produce differently-ordered IR.

Observed on real dependency files: vite's module-runner.js and rollup's shared/index.js (the two corpus files excluded as control-failed in #7171's 47/0/2 IR comparison — reported honestly as control failures, not counted as passing).

Class

Same family as #7038/#7039 (closure-source HashMap iteration made @.str.N numbering a per-process permutation on macOS — fixed by sorting) and #7131 (Linux temp names — fixed). This is the method-emission sibling: cross-class shared method names iterate an unordered map.

Why it matters

Repro

Compile vite/dist/node/module-runner.js (or rollup shared/index.js) twice with the same compiler, --trace llvm or --no-link, diff the IR: method-symbol ordering differs run-to-run.

Activity

  1. proggeramlug commented on Aug 9, 2026

    @proggeramlug
    ContributorAuthor

    Closing — fixed by c413af072 (PR #7625, "make emitted IR run-to-run deterministic").

    It sorts the ctx.class_ids iteration in lower_call/property_get/dynamic_dispatch.rs (dispatch_roots.sort_unstable_by(|a,b| a.1.cmp(&b.1).then_with(|| a.0.cmp(&b.0)))) and sorts method_registry.rs's class_table walk that builds the (class, method) → perry_method_* symbol map — the exact map this issue names.

    The commit reproduces this issue's symptom verbatim: "the same source compiled twice by the same binary emitted the same arms naming DIFFERENT perry_method_* callees per position."

    Backed by sabotage-tested coverage in codegen/emission_order_tests.rs and a 126-program zero-diff A/B in changelog.d/7625-codegen-determinism.md — which matters here more than usual, since nondeterminism is precisely the class of bug that a single passing run cannot rule out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions