diff --git a/crates/xenia-app/src/main.rs b/crates/xenia-app/src/main.rs index e569aaa..e0a9563 100644 --- a/crates/xenia-app/src/main.rs +++ b/crates/xenia-app/src/main.rs @@ -3159,6 +3159,20 @@ fn run_superblock( let mut pc_before = first_pc_before; let mut total_executed: u64 = 0; + // PERF: the running thread (`thread_ref`) is FIXED for the entire + // superblock chain — no thread spawn/exit/migration happens between + // iterations. `step_block` is pure guest interpretation; an import thunk + // or any sync-sensitive/MMIO op BREAKS the chain (below) before any kernel + // mutation could restructure the runqueue; `fire_block_entry_probes` is + // read-only; `block_cache.lookup_or_build` touches only `wc`. So this + // thread's `PpcContext` heap slot is stable for the whole loop and we can + // resolve it ONCE here — instead of a bounds-checked double slot lookup + // (`ctx_mut_ref` + `ctx`) on EVERY chained block (~10M/round). Same + // raw-pointer discipline as `block_ptr`; and `ctx(hw_id) == + // ctx_mut_ref(thread_ref)` throughout because `running_idx` is unchanged. + // Byte-identical. + let ctx_ptr: *mut xenia_cpu::PpcContext = kernel.scheduler.ctx_mut_ref(thread_ref); + let (result, last_block_ptr, last_pc_before) = loop { let mmio_before = mem.mmio_access_count(); let block = unsafe { &*block_ptr }; @@ -3167,7 +3181,7 @@ fn run_superblock( // `ctx_mut_ref` slot lookups — for cycle-before, the step, and // cycle-after — each a double bounds-checked index). Byte-identical. let (result, executed) = { - let ctx = kernel.scheduler.ctx_mut_ref(thread_ref); + let ctx = unsafe { &mut *ctx_ptr }; let cycle_before = ctx.cycle_count; // JIT seam (XENIA_JIT): run the JIT-compiled block if enabled, else // the interpreter. The JIT leaves ctx.cycle_count/pc and @@ -3205,8 +3219,9 @@ fn run_superblock( // Decide whether the NEXT PC is an ordinary guest block we can // chain into. Anything else (thunk / halt sentinel / unmapped) - // needs the full prologue dispatch next round. - let next_pc = kernel.scheduler.ctx(wc.hw_id).pc; + // needs the full prologue dispatch next round. `ctx_ptr` aliases the + // running thread's context (stable for the chain — see above). + let next_pc = unsafe { (*ctx_ptr).pc }; if next_pc == LR_HALT || (kernel.pc_in_thunk_band(next_pc) && thunk_map.contains_key(&next_pc)) || !mem.is_mapped(next_pc)