-
Notifications
You must be signed in to change notification settings - Fork 19
jit: journal the portal coordinate and snapshot the locals the f_locals fold writes #1434
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| bridges_compiled=0 | ||
| descr_set_absent=0 | ||
| descr_set_ambiguous=0 | ||
| descr_set_stale_absent=0 | ||
| fbw_blackhole_adopted_multi_frame=0 | ||
| fbw_blackhole_adopted_single_frame=0 | ||
| fbw_rolled_back_with_effects=0 | ||
| fbw_store_journal_rollback_failed=0 | ||
| field_pos_attached_misplaced=0 | ||
| field_pos_spec_misplaced=0 | ||
| guard_failures=1 | ||
| internal_compile_panics=0 | ||
| loops_aborted=0 | ||
| loops_compiled=1 | ||
| retraces_compiled=0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| bridges_compiled=0 | ||
| descr_set_absent=0 | ||
| descr_set_ambiguous=0 | ||
| descr_set_stale_absent=0 | ||
| fbw_blackhole_adopted_multi_frame=0 | ||
| fbw_blackhole_adopted_single_frame=0 | ||
| fbw_rolled_back_with_effects=0 | ||
| fbw_store_journal_rollback_failed=0 | ||
| field_pos_attached_misplaced=0 | ||
| field_pos_spec_misplaced=0 | ||
| guard_failures=1 | ||
| internal_compile_panics=0 | ||
| loops_aborted=0 | ||
| loops_compiled=1 | ||
| retraces_compiled=0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # pyre-check: max-pypy-ratio=12 | ||
| # pypy's exec time here sits at the startup-subtraction floor, so the printed | ||
| # ratio is not a measurement; the ceiling is fitted to the slowest of nine | ||
| # local readings across the three backends plus headroom. | ||
| # | ||
| # Folding `frame.f_locals` mirrors the virtualizable shadow into the live | ||
| # `locals_cells_stack_w` array, because pyre answers the attribute with a 3.14 | ||
| # `FrameLocalsProxy` that reads that array lazily rather than copying out of it | ||
| # at the call. The mirror is an eager walk-time write, so it needs an undo for | ||
| # the walk that does not commit — and the undo it is recorded in decides how | ||
| # long it survives. | ||
| # | ||
| # Recording it in the residual force's escape-flush capture is wrong: the tail | ||
| # of `try_execute_residual_call_via_executor` restores that capture after EVERY | ||
| # non-forcing residual call, so the next call in the same walk reverts the | ||
| # mirror and the proxy answers from before the fold. That is what this fixture | ||
| # reads — `str(i)` between the fold and the subscript — and the failure is one | ||
| # wrong answer on the trace-recording iteration alone, not every iteration, so | ||
| # a short loop passes either way. | ||
| import sys | ||
|
|
||
|
|
||
| def f(n): | ||
| bad = 0 | ||
| for i in range(n): | ||
| x = i * 2 | ||
| loc = sys._getframe(0).f_locals | ||
| s = str(i) # a residual call between fold and read | ||
| if loc['x'] != x: # must be this iteration's value | ||
| bad += 1 | ||
| return bad | ||
|
|
||
|
|
||
| print("mismatches:", f(3000)) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| bridges_compiled=0 | ||
| descr_set_absent=0 | ||
| descr_set_ambiguous=0 | ||
| descr_set_stale_absent=0 | ||
| fbw_blackhole_adopted_multi_frame=0 | ||
| fbw_blackhole_adopted_single_frame=0 | ||
| fbw_rolled_back_with_effects=0 | ||
| fbw_store_journal_rollback_failed=0 | ||
| field_pos_attached_misplaced=0 | ||
| field_pos_spec_misplaced=0 | ||
| guard_failures=1 | ||
| internal_compile_panics=0 | ||
| loops_aborted=0 | ||
| loops_compiled=1 | ||
| retraces_compiled=0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2595,7 +2595,18 @@ fn walker_write_back_standard_frame_locals<Sym: WalkSym>( | |
| Some((value, _)) => slots.push((slot as i64, value)), | ||
| } | ||
| } | ||
| // The mirror below writes the live frame's locals array, and a walk that | ||
| // does not commit replays from its pre-walk instruction — so the pre-walk | ||
| // values have to be recoverable. Journal them against the walk's own | ||
| // non-commit epilogue rather than the escape-flush capture: that capture is | ||
| // consumed by every non-forcing residual (`try_execute_residual_call_via_ | ||
| // executor`'s tail restore), which would revert this mirror mid-walk and | ||
| // leave a live `FrameLocalsProxy` reading pre-fold values. | ||
| crate::jitcode_dispatch::fbw_note_locals_mirror_undo(concrete_frame, nlocals); | ||
| if !crate::state::flush_locals_region_to_frame(ctx.trace_ctx, concrete_frame) { | ||
| // All-or-nothing decline: nothing was written. The journal entry is | ||
| // harmless — restoring the values still in place is a no-op — and the | ||
| // first-per-frame rule means dropping it could discard a real one. | ||
| return false; | ||
| } | ||
| ctx.trace_ctx | ||
|
|
@@ -9602,6 +9613,10 @@ pub(crate) fn try_walker_specialize_sys_getframe<Sym: WalkSym>( | |
| .trace_ctx | ||
| .virtualizable_entry_at(crate::virtualizable_spec::LAST_INSTR_VABLE_FIELD_INDEX) | ||
| { | ||
| // Journaled like the per-opcode publication: this store lands whether | ||
| // or not the walk commits, and a walk that does not commit replays the | ||
| // frame from its pre-walk coordinate. | ||
| crate::jitcode_dispatch::fbw_note_last_instr_undo(cur_ptr as usize); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When this positive-depth AGENTS.md reference: AGENTS.md:L26-L33 Useful? React with 👍 / 👎. |
||
| unsafe { (*cur_ptr).last_instr = last_instr as isize }; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
f_localsis folded for a nursery-allocated standard virtualizable, such as a bridge or recursive JIT frame, a subsequent proxy or residual allocation can relocate that frame before the non-commit epilogue. The extra-root walker forwardsentry.slotsbut never this rawusize, sofbw_locals_mirror_rollbacklater dereferences the abandoned nursery address instead of the live red frame, failing to restore its locals and potentially corrupting reused nursery memory. Store and visit this frame identity as a forwardable GC root rather than a raw address.AGENTS.md reference: AGENTS.md:L26-L33
Useful? React with 👍 / 👎.