Skip to content

jit: virtualize empty-list first append (gh#389 (b)) - #598

Merged
youknowone merged 8 commits into
mainfrom
no-token
Jul 18, 2026
Merged

youknowone merged 8 commits into
mainfrom
no-token

Conversation

@youknowone

@youknowone youknowone commented Jul 16, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Resolves item (b) of #389 — a hot loop that grows an empty list via
per-iteration LIST_APPEND (inlined comprehension or explicit for … append)
no longer aborts the FBW walker; it now compiles.

The orthodox fix follows EmptyListStrategy.append → switch_to_correct_strategy
(listobject.py:1154): on the first append the walker promotes the Empty
receiver to the value-typed strategy (Integer/Float/Object), records that
transition as inline heap IR, then falls through to the existing spare-capacity
append fold. No list virtualization across the back-edge (PyPy doesn't do that
for a growing accumulator either — it materializes and appends for real).

Commits (5, stacked on main)

Key detail

The append body sub-walk reads list.items_block (heapcache-hits the promotion's
NewArray op) then block.capacity. That capacity read is a getfield, a
different heapcache channel from new_array's arraylen seed, so it is seeded
explicitly with the const (1) — matching how the heapcache tracks a const-length
new_array. The seeded const resolves through concrete_of_opref →
inline_const_to_value, so the GOTO_IF_NOT on 0 < capacity folds instead of
aborting GotoIfNotValueNotConcrete.

Verification

  • dynasm + cranelift check.py 194/194, gate on and off.
  • int / float / object / mixed-type / nested-comprehension repros byte-identical
    vs PYRE_NO_JIT=1 and under MAJIT_GC_STRESS=1.
  • census: empty-append moves from residual (exec_mf) to virtualized (exec_v).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Empty lists can now be promoted to an appropriate typed storage strategy on their first append.
    • List comprehensions with supported append patterns receive improved JIT handling.
  • Bug Fixes

    • Improved list comprehension execution for complex stack-ordering patterns.
    • Added rollback safeguards so speculative list promotions restore correctly when needed.
    • Increased safety checks for unsupported list-append comprehension bodies.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026 •

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The PR adds Empty-list first-append promotion with typed storage and rollback journaling, tightens FOR_ITER comprehension safety checks, rematerializes list receivers from vable state, and reconciles non-monotonic vstack lowering.

Changes

List promotion and comprehension execution

Layer / File(s) Summary
Typed Empty-list promotion
pyre/pyre-object/src/listobject.rs, pyre/pyre-jit-trace/src/helpers.rs, pyre/pyre-jit-trace/src/jitcode_dispatch.rs
Empty lists can be promoted to Integer, Float, or Object storage before the first append, with an environment-controlled eligibility path.
Promotion journal and rollback
pyre/pyre-jit-trace/src/jitcode_dispatch.rs
Promoted list references are journaled, treated as GC roots, cleared on rollback, and removed on commit or reset.
Comprehension safety and receiver rematerialization
pyre/pyre-jit/src/eval.rs, pyre/pyre-jit/src/jit/codewriter.rs
FOR_ITER bodies containing ListAppend use stricter opcode checks, tests cover accepted and rejected shapes, and list receivers are reloaded from vable stack state.
Vstack reorder reconciliation
pyre/pyre-jit-trace/src/jitcode_dispatch.rs
Non-monotonic comprehension lowering enters a tracked reorder region and reseeds reconciliation from shadow state until normal ordering resumes.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant FOR_ITER
  participant Codewriter
  participant JITTrace
  participant ListObject
  participant PromotionJournal
  FOR_ITER->>Codewriter: process comprehension append
  Codewriter->>JITTrace: reload list receiver from vable slot
  JITTrace->>ListObject: promote Empty list to typed strategy
  JITTrace->>PromotionJournal: record promoted list reference
  PromotionJournal-->>JITTrace: restore Empty strategy on rollback
Loading

Possibly related PRs

Suggested reviewers: lifthrasiir

Poem

I hop through empty lists, now typed and bright,
With integer, float, or object delight.
Journals remember each speculative leap,
While vstack shadows guard what we keep.
Comprehensions march in a safer array—
Sincerely, a rabbit reviewing today.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: virtualizing the first append on empty lists in the JIT.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch no-token

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.44.1)
pyre/pyre-jit-trace/src/jitcode_dispatch.rs

ast-grep timed out on this file


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 16, 2026 •

Copy link
Copy Markdown

🤖 Codex parity review

Static analysis of this diff vs the local RPython/PyPy sources (commit 39546b8).
Updated: 2026-07-18T09:52:53.079Z

Files in the reviewed diff
pyre/pyre-jit-trace/src/helpers.rs
pyre/pyre-jit-trace/src/jitcode_dispatch.rs
pyre/pyre-jit/src/eval.rs
pyre/pyre-jit/src/jit/codewriter.rs
pyre/pyre-object/src/listobject.rs

1. Regressions to PyPy parity introduced by this patch

None.

2. Other mismatches introduced by this patch

  • pyre/pyre-jit-trace/src/helpers.rs:1342 ↔ rpython/rtyper/rlist.py:590 — Object-strategy promotion allocates capacity 1 but does not cache ItemsBlock.capacity = 1; the subsequent _ll_resize_ge(length + 1) condition cannot fold through the same known-capacity path used by the Integer/Float arms. This makes the new Object first-append specialization decline/abort rather than reproduce the intended inline append.

  • pyre/pyre-jit-trace/src/jitcode_dispatch.rs:21884 ↔ pypy/objspace/std/listobject.py:1155 — the new Empty-list recognizer excludes fits-in-machine-word W_LongObjects, although PyPy’s is_plain_int1(w_item) selects IntegerListStrategy for them. The generic residual remains correct, but this new specialization is not equivalent in coverage.

3. Pre-existing mismatches (already present before this patch)

  • pyre/pyre-object/src/listobject.rs:431 ↔ pypy/objspace/std/listobject.py:1157 — pre-existing switch_to_correct_strategy has only Integer, Float, and Object branches; PyPy additionally selects BytesListStrategy and ASCII UnicodeListStrategy. git show upstream/main confirms the Rust lines were already present before this patch.

4. Structural adaptations

  • pyre/pyre-jit-trace/src/jitcode_dispatch.rs:21886 ↔ pypy/objspace/std/listobject.py:1170 — speculative full-body walking promotes the concrete list early and uses a TLS rollback journal; PyPy directly switches strategy and appends. This is required by pyre’s speculative trace/replay model, not a Python-visible strategy change.

  • pyre/pyre-jit/src/eval.rs:4148 ↔ pypy/interpreter/pyopcode.py:1492 — the conservative FOR_ITER admission gate declines value-producing list comprehensions. This is a pyre JIT replay-safety restriction around CPython-compatible bytecode, rather than interpreter semantics.

  • pyre/pyre-jit/src/jit/codewriter.rs:10184 ↔ rpython/flowspace/flowcontext.py:1115 — LIST_APPEND reloads its receiver from pyre’s virtualizable frame array instead of using flowspace’s symbolic peekvalue(oparg - 1). This preserves the operand-stack identity across pyre’s loop representation.

  • pyre/pyre-jit-trace/src/jitcode_dispatch.rs:10531 ↔ pypy/interpreter/pyopcode.py:378 — the reorder-ceiling mirror reseed compensates for pyre’s non-monotonic CPython 3.14 comprehension lowering; PyPy’s opcode dispatcher executes LIST_APPEND in normal bytecode order.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

https://github.com/youknowone/pyre/blob/b417c1c4014ddfc1546d05c915d089af52106686/pyre-jit-trace/src/jitcode_dispatch.rs#L20596
P1 Badge Move value guards before mutating the empty list

When a trace recorded from an Integer/Float first append later sees a value with a different class, the value GuardClass/w_class guards below can fail after this helper has already emitted SetfieldGc mutations that promote the real list away from Empty. Those guards capture op.pc, so deopt re-runs the LIST_APPEND on an already-promoted receiver instead of the original Empty-list state; for example, an int-specialized trace that gets a float resumes through Integer→Object rather than Empty→Float, leaving a different list strategy/capacity visible to later operations such as list.__sizeof__. Guard the appended value's type before emitting the promotion, or resume at a state that does not re-execute the append.


https://github.com/youknowone/pyre/blob/b417c1c4014ddfc1546d05c915d089af52106686/pyre-jit-trace/src/helpers.rs#L1236
P2 Badge Match first-append typed capacity to the interpreter

For the Integer and Float arms this hard-codes a capacity-1 block, but the concrete interpreter path this is replacing does IntArray::from_vec(Vec::new()) / FloatArray::from_vec(Vec::new()) with capacity 0 and then the first push grows to INT_ARRAY_INLINE_CAP/FLOAT_ARRAY_INLINE_CAP (8). A compiled first append therefore materializes a list with capacity 1 where the interpreter would have capacity 8; that is user-visible via list.__sizeof__ (typedef.rs uses w_list_capacity) and can also make later same-trace append decisions disagree with the concrete heap used by the walker.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 037341694a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

} else if !value.is_null() && pyre_object::is_plain_float_strict(value) {
ListStrategy::Float
} else {
ListStrategy::Object

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Guard Object promotion against typed first values

When the trace-time first append falls through to ListStrategy::Object, the code only guards that the receiver is still Empty; it never guards the negative predicates that made Object the right target (not plain int and not strict float). A trace recorded with an object/string first item can therefore be reused with an int or float first item, and the compiled path will install Object storage even though switch_to_correct_strategy would choose Integer/Float. That changes observable behavior such as list.__sizeof__() and subsequent strategy-dependent element handling, so the Object promotion needs guards excluding the typed cases or should decline this specialization.

Useful? React with 👍 / 👎.

};
use crate::state::{float_gcarray_descr, int_gcarray_descr, pyobject_gcarray_descr};

let cap_ref = ctx.const_int(1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve typed first-append capacity

For Integer/Float empty-list promotion this hard-codes the traced backing block capacity to 1, but the interpreter path is switch_to_correct_strategy followed by IntArray::push/FloatArray::push; from an empty typed array that grow path allocates INT_ARRAY_INLINE_CAP/FLOAT_ARRAY_INLINE_CAP slots (8). After compiling a one-element int/float append, code that observes list capacity via list.__sizeof__() will see the JIT-created capacity-1 list instead of the interpreter's capacity-8 list, so the typed arms need to emit the same first-append allocation size as the concrete append path.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6f48d38937

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// Emit the transition IR mutating the existing wrapper (helpers.rs).
// The emitter seeds the new block's capacity getfield cache so the
// append body sub-walk's spare-capacity `0 < capacity` check folds.
crate::helpers::emit_promote_empty_list_inline(ctx.trace_ctx, self_ref, target);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Guard value type before promoting the list

When this specialization records an Integer/Float first append, the value-class and w_class guards are emitted only after this call has already recorded the strategy/block SetfieldGc writes. If the trace is later entered with a different first value type (for example traced with an int but reached with a float), the guard failure resumes at the append site after the live list has already been switched out of Empty, so the interpreter re-executes w_list_append from the wrong starting strategy and can leave the list in Object storage instead of the Float/Integer strategy the interpreter would have chosen from Empty. Move the target value guards ahead of the promotion writes, or make the promotion happen only after all guards that can fail have passed.

Useful? React with 👍 / 👎.

Add `empty_append_virt_enabled()` reading `PYRE_EMPTY_APPEND_VIRT`
(default-off), mirroring `newlist_virt_enabled()`. The gate will admit the
empty-list first append into the orthodox `w_list_append` fold in a later
slice. No caller yet; `#[allow(dead_code)]` until wired.

Assisted-by: Claude
Add FBW_APPEND_PROMOTE_JOURNAL recording each list promoted Empty→typed
during a speculative full-body walk, wired parallel to FBW_APPEND_JOURNAL
through reset/commit/rollback and the GC root walker area. Rollback drains
it after the length-rewind and calls w_list_clear to restore the Empty
strategy + drop the typed backing block — the strategy switch + realloc the
length journal alone cannot undo.

No caller yet (fbw_append_promote_journal_push is #[allow(dead_code)] until
the recognize gate admits the empty append); strict no-op with the gate off.
Removable when single-executor tracing lands (gh#73/#34).

Assisted-by: Claude
…ated)

Admit the Empty-strategy first LIST_APPEND on the FBW walker under the
PYRE_EMPTY_APPEND_VIRT gate (default off). recognize classifies the append
by the value's type in switch_to_correct_strategy's int->float->object order;
commit installs the typed backing block on the concrete receiver, emits the
Empty->typed transition as inline heap IR mutating the existing wrapper, and
journals the rewind to Empty for a non-commit walk.

emit_promote_empty_list_inline returns the transition's NewArray block OpRef.
commit stamps it with the concrete backing-block address (new
w_list_items_block_ptr) so the append body sub-walk's
`list.items_block.capacity` getfield folds via field_sanity_load to the
concrete capacity (1); the spare-capacity `0 < capacity` branch then resolves
instead of aborting with a symbolic GOTO_IF_NOT condition.

The concrete strategy switch runs before the IR emit so the backing block
exists when the block OpRef is stamped.

Assisted-by: Claude
Flip the PYRE_EMPTY_APPEND_VIRT gate to default-on (set PYRE_EMPTY_APPEND_VIRT=0
to restore the residual abort), matching the newlist_virt_enabled default-on
convention. dynasm and cranelift both pass check.py 194/194 with the gate on.

Assisted-by: Claude
…mp path

Replace the NewArray-block concrete-address stamp with a heapcache capacity
seed. emit_promote_empty_list_inline now seeds the new block's ItemsBlock.capacity
getfield cache with the const (1) on the Integer and Float arms, so the append
body sub-walk's spare-capacity `0 < capacity` check folds to the const instead
of reading a symbolic getfield. This is the same shape the heapcache uses for a
const-length new_array; the capacity is read through a getfield (not arraylen),
so the field-index channel is seeded explicitly.

Removes the emit_promote_empty_list_inline `Option<OpRef>` return, the
commit-site reorder + set_opref_concrete stamp, and the now-unused
w_list_items_block_ptr accessor. Object storage needs no seed (its capacity
read resolves through list.items already).

A/B verified both levers independently compile the empty-append loop; the seed
is the smaller and matches the heapcache const-length model. dynasm+cranelift
194/194, list repros byte-identical under MAJIT_GC_STRESS.

Assisted-by: Claude
…IST_APPEND admit to call-free bodies

The py3.14 inlined comprehension emits a SWAP/BUILD_LIST/SWAP preamble
before its FOR_ITER, lowered non-monotonically in jitcode: the JitCode-PC
floor pivot maps a later jit_pc back to an earlier py_pc, so the walk
re-visits those preamble py_pcs out of order (a backward py transition,
then a forward re-walk). reconcile_vstack_at_boundary replayed the SWAP
effect and reused a stale vstack_last_ref across that region, dropping the
just-built list from the vstack_boxes mirror; the stack_sync overlay then
copied the corrupt mirror into the resume snapshot, so a deopt from the
comprehension body reconstructed a frame whose FOR_ITER iterator slot held
a duplicated iterator and a dropped list ("not an iterator").

Add WalkContext.vstack_reorder_ceiling: when the previous opcode is a
Swap/Copy and the py transition is backward (a codewriter layout artifact,
never a real branch), reseed the whole mirror from the virtualizable
shadow (VstackOpClass::ShadowReseed) until the walk advances past the
py_pc it backed off from.

Admit LIST_APPEND in for_iter_bodies_all_jit_safe only when its FOR_ITER
body performs no CALL. A per-element user-frame call (a class ctor / user
function) sets the FOR_ITER in-flight body-effect flag, and a mid-body
abort then routes through fbw_foriter_inflight_take, which refuses
delivery to avoid a double-apply and drops the trace-attempt iteration's
item. Call-free comprehension bodies never enter a user frame and stay
admissible; call-bearing bodies decline to interpretation.

Assisted-by: Claude
…ack slot

The codewriter lowered LIST_APPEND's list operand by cloning the peeked
FlowValue from the compile-time stack. The inlined-comprehension
accumulator lives on the operand stack, which is not loop-carried in
registers (the jit_merge_point reds are [frame, ec]), so the preamble
BUILD_LIST value is not a live register inside the resident loop. The
jit_list_append residual then read an unbound register for its receiver
and aborted ResidualCallArgUnbound, so the comprehension inner loop never
compiled and the #171 empty-append fold was never reached.

Reload the list receiver from its value-stack slot via
getarrayitem_vable_r each iteration, the same per-iteration
re-materialization the FOR_ITER iterator reload already uses. Call-free
comprehension inner loops (`[j for j in range(n)]`) now compile with the
append folded. A comprehension whose body enters a user frame (e.g.
`[C(i) for i in ...]`) still declines via for_iter_bodies_all_jit_safe's
call-free LIST_APPEND gate, since its in-flight FOR_ITER delivery is a
separate concern.

Assisted-by: Claude
A comprehension whose LIST_APPEND lands in a list Object-strategy
(str/None/tuple/list/dict/f-string element) lowers the append to a Void
setarrayitem_gc residual. The FBW body-effect gate marks that Void write
as a body effect, so fbw_foriter_inflight_take refuses delivery of the
in-flight FOR_ITER item on the trace-attempt abort and drops one
iteration (len 999 vs 1000). int/float-strategy appends fold via the pure
length-rewind journal and stay correct.

Replace the body_has_call scan with a body_has_list_append scan: when a
FOR_ITER body contains LIST_APPEND, admit only the bare-accumulator ops
(LoadFast/StoreFast family, ListAppend, stack shuffles, backward jumps,
ExtendedArg/Cache). Any value-producing op declines the body to the
interpreter. Bodies without LIST_APPEND keep the existing predicate.

Assisted-by: Claude

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@pyre/pyre-jit-trace/src/jitcode_dispatch.rs`:
- Around line 21993-22009: The empty-append strategy classification is
duplicated and can diverge between recognition, commit, and concrete promotion.
Add a shared classify_empty_append_strategy(value) -> Option<ListStrategy>
helper, use it in orthodox_list_append_recognize by mapping Some to Some(0), and
replace the local target computation in the commit path with it. Ensure
switch_to_correct_strategy uses the same classification rules, including
fits-int W_LongObject values.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 93b77009-d511-44ed-9ace-c70dfaba91da

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5c46 and 39546b8.

📒 Files selected for processing (5)
  • pyre/pyre-jit-trace/src/helpers.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch.rs
  • pyre/pyre-jit/src/eval.rs
  • pyre/pyre-jit/src/jit/codewriter.rs
  • pyre/pyre-object/src/listobject.rs

Comment on lines +21993 to +22009
use pyre_object::listobject::ListStrategy;
let promote_empty = empty_append_virt_enabled()
&& unsafe { pyre_object::w_list_uses_empty_storage(inner_self) };
if promote_empty {
let target = unsafe {
let int_ok = pyre_object::is_plain_int1(value)
&& !pyre_object::pyobject::is_long(value)
&& !(pyre_object::tagged_int::CAN_BE_TAGGED
&& pyre_object::tagged_int::is_tagged_int(value));
if int_ok {
ListStrategy::Integer
} else if !value.is_null() && pyre_object::is_plain_float_strict(value) {
ListStrategy::Float
} else {
ListStrategy::Object
}
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Centralize the Empty→typed strategy classification to remove a latent drift risk.

The int→float→object classification now lives in three places that must stay in lockstep:

  • orthodox_list_append_recognize (the int_ok/float_ok/obj_ok gate),
  • this target computation in the commit path, and
  • switch_to_correct_strategy in pyre-object/src/listobject.rs (the concrete promotion w_list_switch_to_strategy_for runs).

They only agree today because recognize declines the one value class where they diverge: a fits-int W_LongObject is is_plain_int1 == true, so switch_to_correct_strategy would install Integer, but this target computes Object (its int_ok adds !is_long). If recognize is ever relaxed to admit that class, the emitted IR strategy (Object) would disagree with the concrete strategy the wrapper installs (Integer), silently miscompiling the trace. Extracting a single classify_empty_append_strategy(value) -> Option<ListStrategy> shared by recognize (map Some → Some(0)) and this site removes one divergence axis and makes the remaining coupling with switch_to_correct_strategy explicit.

🤖 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 `@pyre/pyre-jit-trace/src/jitcode_dispatch.rs` around lines 21993 - 22009, The
empty-append strategy classification is duplicated and can diverge between
recognition, commit, and concrete promotion. Add a shared
classify_empty_append_strategy(value) -> Option<ListStrategy> helper, use it in
orthodox_list_append_recognize by mapping Some to Some(0), and replace the local
target computation in the commit path with it. Ensure switch_to_correct_strategy
uses the same classification rules, including fits-int W_LongObject values.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant