Merge train: #9566 #9567 #9568 - #9572
Merged
Merged
Conversation
`const Mixed2 = mixin(Mixed)` — a mixin applied to a previous mixin's
RESULT — SIGSEGVed as soon as anything derived from it was constructed.
Node prints `4` for the issue's reproducer; Perry exited 139 after
unbounded recursion.
The HIR mixin fast path in `lower/stmt.rs` synthesizes a real class for
`const M = mixinFn(Base)`. At the second level the base is `Mixed`, a
lexical VALUE binding, so `lower_class_from_ast` takes its
locally-shadowed arm and captures the parent as `extends_expr` — a
dynamic parent — rather than a static class link. That is correct. What
was missing is the other half: unlike the sibling `const X = class {…}`
path immediately above it, this arm bound the synthesized class without
emitting the declaration-time `RegisterClassParentDynamic`. The
generated `Mixed2_constructor` therefore called
`js_get_dynamic_parent_value` for its class id with no registration to
answer it; with an undefined parent `js_fetch_or_value_super` fell back
to the most-derived receiver, re-selected `Mixed2`, and recursed until
the stack overflowed.
Emit the registration here too, in source order after the parent's own
value binding and before this class's — exactly where the sibling path
puts it. A single-level `mixin(Root)` extends a real class, keeps
`extends_expr` at `None`, and is unchanged: that is why one level
already worked (#9073) and two did not.
Verified on Linux (perrymaster) with a fresh
`PERRY_NO_AUTO_OPTIMIZE=1 cargo build --profile perry-dev -p perry
-p perry-runtime-static -p perry-stdlib-static`:
- Baseline binary built from this tree before the patch: exit 139.
- After: the gap fixture is byte-identical to the pinned Node 26.5.1
oracle under both `PERRY_NO_AUTO_OPTIMIZE=1` and the default
auto-optimize pipeline.
- LLVM for the fixture: every `js_get_dynamic_parent_value(i32 N)` in
the module now has a matching `js_register_class_parent_dynamic(i32
N, …)` — zero orphans; `Mixed2_constructor`'s id is among them.
- `cargo test -p perry-hir`: all green. The new lowering unit test was
confirmed to FAIL against the unpatched lowering.
The gap fixture keeps the issue's reproducer verbatim and adds the
assertions it left open: inherited `Root` state and the mixin method
through both synthesized levels, `instanceof` across the whole chain, a
leaf with no own constructor, the still-working one-level case, and a
three-level chain built from three distinct mixins so a dropped level
shows up as a missing method rather than being masked by identical
bodies.
Closes #9079
Claude-Session: https://claude.ai/code/session_01SNcEDcviLvFMta5oL7Zxig
This was referenced Sep 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lands the validated train: #9566 (Linux callback-deopt GC coverage restored — the fixture now builds a release panic=abort runtime per the #8479 exception-transport contract, replacing the Linux ignore from #9488), #9567 (dynamic parent of a mixin-of-a-mixin registered, #9079), #9568 (child-process null-byte validation, #9537).
Validation: release build green; RUST_TEST_THREADS=1 perry-runtime green; perry-hir green; the restored deopt test passes (both evacuation arms, 175s); both gap fixtures byte-identical to node; lint gates green.
Rebase-merge preserving authorship.