fix(codegen): root comparison operands across calls - #8011
Conversation
📝 WalkthroughWalkthroughComparison lowering now roots GC-capable operands across allocating evaluations and dispatch. It adds type-specific equality and relational paths, preserves numeric fast paths, and adds IR and moving-GC regression coverage. ChangesComparison operand rooting
Estimated code review effort: 4 (Complex) | ~45 minutes Mergeability Score: ⚪ Minimal · up to The PR keeps pointer-capable comparison operands valid across allocating calls and adds regression and corpus coverage. The remaining concerns are limited to trivial cleanup, so no actionable merge-blocking risk remains. Sequence Diagram(s)sequenceDiagram
participant ComparisonLowering
participant with_operands_rooted
participant GarbageCollector
participant ComparisonRuntime
ComparisonLowering->>with_operands_rooted: lower left and right operands
with_operands_rooted->>GarbageCollector: root GC-capable values
GarbageCollector-->>with_operands_rooted: re-read moved operands
with_operands_rooted->>ComparisonRuntime: dispatch non-fast-path comparison
ComparisonRuntime-->>ComparisonLowering: return comparison result
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
crates/perry-codegen/src/expr/compare.rs (1)
817-832: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRename or remove
either_non_numeric.The binding name states "either", but the expression tests that neither operand is numeric. The condition at line 832 also makes the term redundant:
unknown_l && unknown_ralready implies!is_numeric_expr(left) && !is_numeric_expr(right), becauseunknown_landunknown_reach include a!is_numeric_exprconjunct.Behavior is correct today. The risk is a future edit that weakens
unknown_l/unknown_rand then trusts the misleading name to still exclude numeric operands. Remove the redundant term, or rename it toneither_numeric.♻️ Proposed simplification
- let either_non_numeric = - !is_numeric_expr(ctx, left) && !is_numeric_expr(ctx, right); let only_eq = matches!( op, CompareOp::Eq | CompareOp::LooseEq | CompareOp::Ne | CompareOp::LooseNe ); @@ let unknown_r = !is_numeric_expr(ctx, right) && !is_string_expr(ctx, right) && !is_bool_expr(ctx, right); - if either_non_numeric && only_eq && unknown_l && unknown_r { + if only_eq && unknown_l && unknown_r {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/perry-codegen/src/expr/compare.rs` around lines 817 - 832, In the comparison fallback condition, remove the redundant either_non_numeric binding and its condition because unknown_l && unknown_r already excludes numeric operands; preserve the existing Eq/Ne and unknown operand checks.crates/perry-codegen/src/expr/compare_tests.rs (1)
26-26: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueExtract the generic IR helpers into a shared test module.
call_operand_ofandproducer_lineare used bycompare_tests,issue7628_rooting_tests, andslice8_rooting_tests. Both helpers fail on missing matches, so the assertions are not vacuous.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/perry-codegen/src/expr/compare_tests.rs` at line 26, Extract call_operand_of and producer_line from slice8_rooting_tests into a shared test helper module, then update compare_tests, issue7628_rooting_tests, and slice8_rooting_tests to import them from that module. Preserve their existing behavior, including failing when no matching IR instruction is found.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@crates/perry-codegen/src/expr/compare_tests.rs`:
- Line 26: Extract call_operand_of and producer_line from slice8_rooting_tests
into a shared test helper module, then update compare_tests,
issue7628_rooting_tests, and slice8_rooting_tests to import them from that
module. Preserve their existing behavior, including failing when no matching IR
instruction is found.
In `@crates/perry-codegen/src/expr/compare.rs`:
- Around line 817-832: In the comparison fallback condition, remove the
redundant either_non_numeric binding and its condition because unknown_l &&
unknown_r already excludes numeric operands; preserve the existing Eq/Ne and
unknown operand checks.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: f9267e7e-58d8-4eec-9203-681b1888b899
📒 Files selected for processing (5)
changelog.d/8011-root-comparison-operands.mdcrates/perry-codegen/src/expr/compare.rscrates/perry-codegen/src/expr/compare_tests.rstest-files/test_gap_gc_define_property_descriptor_rooting.tstest-parity/gc_repsel_corpus.txt
Closes #7979.
Summary
Object.definePropertymoving-GC witness to its natural inlineobserved() === expected()form and register it in the moving-collector corpusRoot cause
Comparison lowering evaluated
left, evaluatedright, and then consumed the original left SSA register. If the right operand collected, roots were rewritten but that bare register was not. A heap string returned by the left call therefore still named retired from-space whenjs_eq/js_jsvalue_equalsdereferenced it.with_operands_rootedprotects each pointer-capable operand before later operands run, re-reads it after evaluation, and owns release across every early-returning comparison arm. Its existing operand-protection analysis leaves proven primitives in their original registers.Validation
cargo test -p perry-codegen --lib: 937 passedcargo test -p perry-codegen --lib compare_tests: 10 passedcargo build --release -p perry -p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static--no-cache) runtime witness underPERRY_GC_SCHEDULE_SEED=1 PERRY_GC_SCHEDULE_RATE=1 PERRY_GC_PROTECT_FROMSPACE=1 PERRY_GC_PROTECT_FROMSPACE_DEPTH=800: exit 0, all three verdictsok, 301 copying minors, 111,145 moved objectscargo fmt --all -- --checkpython3 scripts/check_test_registration.py: all 206 candidates accounted for./scripts/check_file_size.shSummary by CodeRabbit
Bug Fixes
Tests