From 31c4db0d3886dbc51cc6cbc1a4a5432d678ab113 Mon Sep 17 00:00:00 2001 From: MarcelMediaDev Date: Thu, 23 Jul 2026 20:55:11 +0100 Subject: [PATCH] fix(cpu): prefer native workers for all guest entry stubs Route thread entry, continuation, and main entry through RunGuestEntryStub so guest stubs are not invoked above CLR-managed frames (UnmanagedCallersOnly FailFast). Keep requireNativeWorker for tbb_thead; other paths prefer workers with calli fallback. Co-authored-by: Cursor --- .../Cpu/Native/DirectExecutionBackend.cs | 47 ++++++------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.cs b/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.cs index 4fb10e6f..297bddcf 100644 --- a/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.cs +++ b/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.cs @@ -5735,23 +5735,13 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I ActiveGuestThreadYieldReason = null; try { - // TBB execute-AV recover needs native-worker TLS (eligible/done). - // Other guests stay on CallNativeEntry — full native-worker migration - // increased splash hangs / UnmanagedCallersOnly (tLTN/tLTO). - int nativeReturn; - if (name == "tbb_thead") - { - nativeReturn = RunGuestEntryStub(ptr, hostRspSlot, requireNativeWorker: true); - } - else - { - if (!TlsSetValue(_hostRspSlotTlsIndex, (nint)hostRspSlot)) - { - reason = "failed to bind host-RSP storage for guest thread stub"; - return GuestNativeCallExitReason.Exception; - } - nativeReturn = CallNativeEntry(ptr); - } + // Prefer pooled native OS workers so guest stubs do not sit above + // CLR-managed frames (UnmanagedCallersOnly FailFast on GTA and + // similar titles). tbb_thead still requires a worker — never fall + // back to managed inline during the Astro spawn storm. + var nativeReturn = name == "tbb_thead" + ? RunGuestEntryStub(ptr, hostRspSlot, requireNativeWorker: true) + : RunGuestEntryStub(ptr, hostRspSlot); if (ActiveGuestThreadYieldRequested) { reason = ActiveGuestThreadYieldReason ?? "guest thread blocked"; @@ -5901,20 +5891,11 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I ActiveGuestThreadYieldReason = null; try { - int nativeReturn; - if (name == "tbb_thead") - { - nativeReturn = RunGuestEntryStub(ptr, hostRspSlot, requireNativeWorker: true); - } - else - { - if (!TlsSetValue(_hostRspSlotTlsIndex, (nint)hostRspSlot)) - { - reason = "failed to bind host-RSP storage for guest continuation stub"; - return GuestNativeCallExitReason.Exception; - } - nativeReturn = CallNativeEntry(ptr); - } + // Same routing as thread entry: prefer native workers for all + // continuations; require them for tbb_thead. + var nativeReturn = name == "tbb_thead" + ? RunGuestEntryStub(ptr, hostRspSlot, requireNativeWorker: true) + : RunGuestEntryStub(ptr, hostRspSlot); if (ActiveGuestThreadYieldRequested) { reason = ActiveGuestThreadYieldReason ?? "guest thread blocked"; @@ -6244,7 +6225,9 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I int num6 = -1; try { - num6 = CallNativeEntry(ptr); + // Main entry also prefers a native worker so the guest process + // does not begin above CLR-managed frames on this thread. + num6 = RunGuestEntryStub(ptr, num2); Console.Error.WriteLine($"[LOADER][INFO] Guest returned: {num6}"); // A host stop has already invalidated the session. Draining guest // continuations here can re-enter a blocked HLE call after its owner