mirror of
https://github.com/ARMSX2/ARMSX3.git
synced 2026-08-24 16:58:52 -07:00
The ARM64 SPU gateway reserved a shared 8192-byte stack scratchpad. Compiled SPU functions build no frames of their own on ARM64 -- GHC_frame_preservation_pass runs with use_stack_frames = false -- so every one of them spills into that single reservation, and a function needing more simply writes past it. Borderlands 2's 2401-instruction function at LS 0x25da8 wants ~21 KB: the fault landed at sp+21760, exactly the top of the thread's stack mapping, on the PROT_NONE guard page above it. x86 reserves 0xc8 in the same place because LLVM emits ordinary per-function frames there, so this arrangement and this failure are ARM64-only. Raised to 256 KB. That is still a fixed bound rather than a scaling fix; a larger function could overflow it the same way. use_stack_frames = true would scale, at a cost the pass comments call out and which is not measured here. Android threads also ran on an eighth of the stack they get elsewhere: the pthread path passed null attributes, so bionic's 1 MB default applied where glibc gives 8 MB, measured as a 0xfc000 stack mapping. Not the cause of this bug -- the overrun is off the TOP of the stack, so size does not affect it, and 1 MB to 64 MB changed nothing -- but a real discrepancy worth closing. Both were invisible because of how the fault died. A guard page is not emulator memory, so is_emulator_fault() correctly declines it, the handler forwards to libsigchain, and ART's FaultManager reads the guest registers as an ArtMethod* and takes the process down. No tombstone is produced, the async emulator log never reaches disk, and Android records only 'SIGNALED status=11'. Verified with the function compiled and no forced interpretation: zero stalls, zero guard-page faults, 47 presented frames where the previous best was 18.