perf: generalize object-write loops and stable dynamic keys#6821
perf: generalize object-write loops and stable dynamic keys#6821proggeramlug wants to merge 3 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe PR generalizes guarded numeric object-write loops from two fields to one through four fields, adds immutable string-local static-key support, strengthens runtime preflight validation, and adds regression tests plus benchmark tooling and measurements. ChangesObject-write optimization
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Compiler
participant RuntimeGuard
participant ObjectArray
participant FastLoop
Compiler->>RuntimeGuard: pass up to four property keys and receiver count
RuntimeGuard->>ObjectArray: validate shared shape, slots, and typed layout
ObjectArray-->>RuntimeGuard: return packed slot indexes
RuntimeGuard-->>Compiler: accept or reject fast path
Compiler->>FastLoop: emit numeric stores for validated fields
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 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.
Actionable comments posted: 1
🧹 Nitpick comments (1)
crates/perry-codegen/src/expr/proxy_reflect.rs (1)
442-448: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winStatic-key resolution logic duplicated three times. The same "resolve
Expr::Stringliteral or immutableExpr::LocalGetviactx.const_string_locals" rule is implemented independently in three places instead of sharing one helper; a future extension to the recognized key shapes could easily miss one or two copies and silently desync the optimization coverage between the PIC write path and the loop fast paths.
crates/perry-codegen/src/expr/proxy_reflect.rs#L442-L448: keepstatic_write_keyhere (or move to a shared module liketype_analysis) and mark itpub(crate)soloops.rscan reuse it directly.crates/perry-codegen/src/stmt/loops.rs#L2094-L2098: replace the inline match inmatch_storewith a call to the sharedstatic_write_key(ctx, key.as_ref()).crates/perry-codegen/src/stmt/loops.rs#L2564-L2568: replace the inline match inmatch_class_field_versioned_loopwith the same shared helper call.♻️ Sketch: share one helper
-fn static_write_key(ctx: &FnCtx<'_>, key: &Expr) -> Option<String> { +pub(crate) fn static_write_key(ctx: &FnCtx<'_>, key: &Expr) -> Option<String> { match key { Expr::String(property) => Some(property.clone()), Expr::LocalGet(id) => ctx.const_string_locals.get(id).cloned(), _ => None, } }- let property = match key.as_ref() { - Expr::String(property) => property.clone(), - Expr::LocalGet(id) => ctx.const_string_locals.get(id).cloned()?, - _ => return None, - }; + let property = crate::expr::proxy_reflect::static_write_key(ctx, key.as_ref())?;(same replacement at the
match_class_field_versioned_loopsite)🤖 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/proxy_reflect.rs` around lines 442 - 448, Centralize static-key resolution in crates/perry-codegen/src/expr/proxy_reflect.rs:442-448 by making static_write_key accessible as pub(crate), then reuse it from both inline-match sites in crates/perry-codegen/src/stmt/loops.rs:2094-2098 (match_store) and 2564-2568 (match_class_field_versioned_loop), passing key.as_ref() and preserving the existing String/const_string_locals behavior.
🤖 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.
Inline comments:
In `@crates/perry-codegen/src/stmt/let_stmt.rs`:
- Around line 1531-1535: Move the const_string_locals insertion logic from its
current position to the start of the let-statement handling in the relevant
function, before module-global and boxed-variable early returns. Apply it for
every non-mutable local whose initializer is a string literal, while preserving
the existing id/value insertion behavior.
---
Nitpick comments:
In `@crates/perry-codegen/src/expr/proxy_reflect.rs`:
- Around line 442-448: Centralize static-key resolution in
crates/perry-codegen/src/expr/proxy_reflect.rs:442-448 by making
static_write_key accessible as pub(crate), then reuse it from both inline-match
sites in crates/perry-codegen/src/stmt/loops.rs:2094-2098 (match_store) and
2564-2568 (match_class_field_versioned_loop), passing key.as_ref() and
preserving the existing String/const_string_locals behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 0391fd8f-cd89-42ab-adb1-746d67717cab
📒 Files selected for processing (23)
benchmarks/object-write-6812/README.mdbenchmarks/object-write-6812/baseline.mdbenchmarks/object-write-6812/canonical.tsbenchmarks/object-write-6812/followup-stable-key.mdbenchmarks/object-write-6812/matrix.tsbenchmarks/object-write-6812/results.mdbenchmarks/object-write-6812/run_matrix.pychangelog.d/6812-immutable-string-key-loop-pic.mdchangelog.d/6812-object-write-loop-generalization.mdcrates/perry-codegen/src/codegen/closure.rscrates/perry-codegen/src/codegen/entry.rscrates/perry-codegen/src/codegen/function.rscrates/perry-codegen/src/codegen/method.rscrates/perry-codegen/src/expr/mod.rscrates/perry-codegen/src/expr/proxy_reflect.rscrates/perry-codegen/src/runtime_decls/objects.rscrates/perry-codegen/src/stmt/let_stmt.rscrates/perry-codegen/src/stmt/loops.rscrates/perry-codegen/tests/native_proof_regressions.rscrates/perry-runtime/src/gc/layout.rscrates/perry-runtime/src/proxy.rscrates/perry-runtime/src/proxy/put_value.rstest-files/test_gap_6812_object_write_loop_generalization.ts
| if !mutable { | ||
| if let Some(perry_hir::Expr::String(value)) = init { | ||
| ctx.const_string_locals.insert(id, value.clone()); | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
const_string_locals never populated for module-level or boxed immutable string locals.
This insertion sits after the module-globals early return (Line 1004) and the boxed-var early returns (Lines 1061, 1108). A top-level const key = "x"; referenced inside a hot loop resolves through the module-globals branch and returns before ever reaching this block, so it's silently excluded from the new static-key fast path (fallback is still correct, just unoptimized). Move the check earlier so it runs unconditionally for every non-mutable string-literal local.
🔧 Proposed fix: hoist the check before any early return
ctx.local_id_to_name.insert(id, name.to_string());
if !mutable {
if let Some(init_expr) = init {
+ if let perry_hir::Expr::String(value) = init_expr {
+ ctx.const_string_locals.insert(id, value.clone());
+ }
if let Some(props) = crate::lower_call::extract_options_fields(ctx, init_expr) {
ctx.option_object_locals.insert(id, props);
}
@@
}
- if !mutable {
- if let Some(perry_hir::Expr::String(value)) = init {
- ctx.const_string_locals.insert(id, value.clone());
- }
- }
Ok(())
}🤖 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/stmt/let_stmt.rs` around lines 1531 - 1535, Move the
const_string_locals insertion logic from its current position to the start of
the let-statement handling in the relevant function, before module-global and
boxed-variable early returns. Apply it for every non-mutable local whose
initializer is a string literal, while preserving the existing id/value
insertion behavior.
|
Superseded by merged PR #6822, which contains these commits plus the numeric-bound follow-up. Closing this duplicate PR to avoid a redundant/conflicting merge. |
Summary
const key = "x") as static keys, so stable dynamic-key writes reuse the guarded PIC and loop fast path.Validation
cargo fmt --all -- --checkcargo test -p perry-codegen --test native_proof_regressions— 250 passedkey_stable_dynamic: Node 138 ms, Perry 124 ms in the follow-up measurement.key_alternating_dynamicremains the conservative fallback control case.Closes #6812
Summary by CodeRabbit