mirror of
https://github.com/ARMSX2/ARMSX3.git
synced 2026-08-24 16:58:52 -07:00
While chasing an unrelated SPURS hang I noticed the JIT publishes freshly written code on ARM64 with no instruction-cache maintenance at all. A grep for clear_cache or flushInstructionCache over the JIT layer comes back empty. The branch-rewrite sites only issue ISB; DSB ISH, which performs no D-cache clean or I-cache invalidation and is ordered backwards for self-modifying code besides. On ARMv8 a correct publication needs the DC CVAU / IC IVAU broadcast sequence; x86 has a coherent instruction cache, so none of this was ever visible there. All sites use the bundled asmjit::VirtMem::flushInstructionCache(), which emits that sequence portably across toolchains. This covers every publication path I could find: - MemoryManager1::finalizeMemory() and MemoryManager2::finalizeMemory() were both no-ops. RuntimeDyld calls finalizeMemory() after writing code and relies on it for cache maintenance, so LLVM emitted PPU and SPU code was never flushed. MemoryManager1 serves the primary PPU JIT, MemoryManager2 the SPU JIT and auxiliary engines. Both managers now record code section allocations and flush them on finalize. I confirmed at runtime that the MemoryManager2 path executes (about 12800 calls per cold boot). - jit_runtime_base::_add() copies asmjit output into executable memory with no flush. - jit_runtime::finalize() restores an executable code snapshot in place during emulator restart with only the ISB/DSB pair. - spu_runtime::rebuild_ubertrampoline() publishes a hand-written trampoline via CAS with no flush; the flush now happens before the publication. - spu_runtime::make_branch_patchpoint() writes a patchpoint byte by byte and returns it with only the ISB/DSB pair. - Both 16-byte branch-site rewrites (dispatch and branch) atomically overwrite live code and only issued the ISB/DSB pair. The ISB/DSB pairs adjacent to the new flushes are removed along with their misleading "flush all cache lines" comments: the flush helper already issues the trailing barriers, and the pairs never performed any cache maintenance in the first place. I want to be upfront that this was not the cause of the hang I was debugging (a same-item compilation race, fixed separately), and I have not observed a failure that this change alone fixes. It is a latent correctness issue on any ARM64 host: nothing prevents another core from fetching stale instruction bytes for freshly published code.