Commit Graph

3 Commits

Author SHA1 Message Date
Sinan KARAKAYA becb2be5bd Let a thread resume at the instruction after a syscall
A syscall can hand control back to the scheduler before the instruction
after it runs. SetSyscall lets the guest install its own handler for a
syscall number; dispatchSyscallOverride then suspends the calling
thread and queues that handler as a GuestInvocation. When the
invocation finishes, EeScheduler resumes the parent thread at the
address the generated code stored just before calling handleSyscall --
the instruction right after the syscall.

The analyzer never marked that address as an entry point. It queues
resume entries for JAL and JALR only, so no generated function could be
re-entered there, EeScheduler's hasFunction() check failed, and the
thread was made dormant instead of resumed. The thread simply stops;
because the scheduler then drains normally and run() returns, it looks
like a clean shutdown rather than a fault, which makes it awkward to
recognise.

This is reachable during early boot on a real title. Dragon Quest VIII
hits it in crt0: the Metrowerks startup code installs a handler for
syscall 0x83 and immediately issues it, and execution ends there,
roughly ten functions into the binary.

Note the offset is +4, not the +8 used for JAL and JALR -- syscall has
no delay slot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 22:57:02 +02:00
Sinan KARAKAYA 75d5085a79 Don't promote a whole function because of an indirect call
When a computed jump cannot be resolved to a jump table, every instruction in
the function becomes an entry point, because the jump could land on any of
them. That fallback was also applied to JALR, which is not a jump but a call:
it transfers control to another function and returns to the instruction after
the delay slot. That return address is already queued as a resume target a few
lines above, so nothing else in the function needs to be reachable from
outside.

Indirect calls are ordinary code -- function pointers, virtual dispatch,
callbacks -- so the fallback fired constantly. On a 3 MB PS2 executable, 2,210
of the 2,422 unresolved sites were JALR, and 1,078 of the 1,282 affected
functions contained no unresolved jump at all.

Restrict the fallback to JR. Promoted entries drop from 189,876 to 1,688,
registered table entries from 156,783 to 75,386, the generated registration
file from 13 MB to 6 MB, and total output from 180 MB to 163 MB. Every
indirect call site in real code keeps its return-address resume entry (the
only sites that lose one are bogus functions carved out of rodata, where the
address is outside the function anyway).
2026-08-17 19:10:41 +02:00
Ranieri 5196a6672a Refactor runtime for move speed and better code style (#140)
* feat: added guestBranchKind enum to categorize branch types
feat: added missingFunctionPolicy enum to define behaviors for missing function scenarios
refactor: added handle guest branches and report missing functions
feat lookupFunction to utilize new dispatch logic and improve error handling for unregistered functions

* fix: fix test conflict

* feat: added debug sound driver logs

* feat: emmiter for return

* feat: added recompiler reporter
feat: added strict diagnostics flag for heavy debug calls

* feat: staticc table insted of hashmap for runtime

* feat: back file to ignore

* feat: explode code across helpers and classes

* feat: update codegen test
feat: better guest nop check

* feat: fix link problem on linux

* feat: fix Segmentation fault
2026-07-04 00:43:22 -03:00