mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
Merge pull request #12079 from JosJuice/blr-no-fastmem
Jit: Allow BLR optimization without fastmem
This commit is contained in:
@ -160,18 +160,25 @@ void* AllocateAlignedMemory(size_t size, size_t alignment)
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeMemoryPages(void* ptr, size_t size)
|
bool FreeMemoryPages(void* ptr, size_t size)
|
||||||
{
|
{
|
||||||
if (ptr)
|
if (ptr)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (!VirtualFree(ptr, 0, MEM_RELEASE))
|
if (!VirtualFree(ptr, 0, MEM_RELEASE))
|
||||||
|
{
|
||||||
PanicAlertFmt("FreeMemoryPages failed!\nVirtualFree: {}", GetLastErrorString());
|
PanicAlertFmt("FreeMemoryPages failed!\nVirtualFree: {}", GetLastErrorString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
if (munmap(ptr, size) != 0)
|
if (munmap(ptr, size) != 0)
|
||||||
|
{
|
||||||
PanicAlertFmt("FreeMemoryPages failed!\nmunmap: {}", LastStrerrorString());
|
PanicAlertFmt("FreeMemoryPages failed!\nmunmap: {}", LastStrerrorString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeAlignedMemory(void* ptr)
|
void FreeAlignedMemory(void* ptr)
|
||||||
@ -186,39 +193,56 @@ void FreeAlignedMemory(void* ptr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadProtectMemory(void* ptr, size_t size)
|
bool ReadProtectMemory(void* ptr, size_t size)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DWORD oldValue;
|
DWORD oldValue;
|
||||||
if (!VirtualProtect(ptr, size, PAGE_NOACCESS, &oldValue))
|
if (!VirtualProtect(ptr, size, PAGE_NOACCESS, &oldValue))
|
||||||
|
{
|
||||||
PanicAlertFmt("ReadProtectMemory failed!\nVirtualProtect: {}", GetLastErrorString());
|
PanicAlertFmt("ReadProtectMemory failed!\nVirtualProtect: {}", GetLastErrorString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
if (mprotect(ptr, size, PROT_NONE) != 0)
|
if (mprotect(ptr, size, PROT_NONE) != 0)
|
||||||
|
{
|
||||||
PanicAlertFmt("ReadProtectMemory failed!\nmprotect: {}", LastStrerrorString());
|
PanicAlertFmt("ReadProtectMemory failed!\nmprotect: {}", LastStrerrorString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
bool WriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DWORD oldValue;
|
DWORD oldValue;
|
||||||
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
|
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
|
||||||
|
{
|
||||||
PanicAlertFmt("WriteProtectMemory failed!\nVirtualProtect: {}", GetLastErrorString());
|
PanicAlertFmt("WriteProtectMemory failed!\nVirtualProtect: {}", GetLastErrorString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#elif !(defined(_M_ARM_64) && defined(__APPLE__))
|
#elif !(defined(_M_ARM_64) && defined(__APPLE__))
|
||||||
// MacOS 11.2 on ARM does not allow for changing the access permissions of pages
|
// MacOS 11.2 on ARM does not allow for changing the access permissions of pages
|
||||||
// that were marked executable, instead it uses the protections offered by MAP_JIT
|
// that were marked executable, instead it uses the protections offered by MAP_JIT
|
||||||
// for write protection.
|
// for write protection.
|
||||||
if (mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ) != 0)
|
if (mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ) != 0)
|
||||||
|
{
|
||||||
PanicAlertFmt("WriteProtectMemory failed!\nmprotect: {}", LastStrerrorString());
|
PanicAlertFmt("WriteProtectMemory failed!\nmprotect: {}", LastStrerrorString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
bool UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DWORD oldValue;
|
DWORD oldValue;
|
||||||
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue))
|
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue))
|
||||||
|
{
|
||||||
PanicAlertFmt("UnWriteProtectMemory failed!\nVirtualProtect: {}", GetLastErrorString());
|
PanicAlertFmt("UnWriteProtectMemory failed!\nVirtualProtect: {}", GetLastErrorString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#elif !(defined(_M_ARM_64) && defined(__APPLE__))
|
#elif !(defined(_M_ARM_64) && defined(__APPLE__))
|
||||||
// MacOS 11.2 on ARM does not allow for changing the access permissions of pages
|
// MacOS 11.2 on ARM does not allow for changing the access permissions of pages
|
||||||
// that were marked executable, instead it uses the protections offered by MAP_JIT
|
// that were marked executable, instead it uses the protections offered by MAP_JIT
|
||||||
@ -227,8 +251,10 @@ void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
|||||||
allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ) != 0)
|
allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ) != 0)
|
||||||
{
|
{
|
||||||
PanicAlertFmt("UnWriteProtectMemory failed!\nmprotect: {}", LastStrerrorString());
|
PanicAlertFmt("UnWriteProtectMemory failed!\nmprotect: {}", LastStrerrorString());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t MemPhysical()
|
size_t MemPhysical()
|
||||||
|
@ -27,12 +27,12 @@ struct ScopedJITPageWriteAndNoExecute
|
|||||||
~ScopedJITPageWriteAndNoExecute() { JITPageWriteDisableExecuteEnable(); }
|
~ScopedJITPageWriteAndNoExecute() { JITPageWriteDisableExecuteEnable(); }
|
||||||
};
|
};
|
||||||
void* AllocateMemoryPages(size_t size);
|
void* AllocateMemoryPages(size_t size);
|
||||||
void FreeMemoryPages(void* ptr, size_t size);
|
bool FreeMemoryPages(void* ptr, size_t size);
|
||||||
void* AllocateAlignedMemory(size_t size, size_t alignment);
|
void* AllocateAlignedMemory(size_t size, size_t alignment);
|
||||||
void FreeAlignedMemory(void* ptr);
|
void FreeAlignedMemory(void* ptr);
|
||||||
void ReadProtectMemory(void* ptr, size_t size);
|
bool ReadProtectMemory(void* ptr, size_t size);
|
||||||
void WriteProtectMemory(void* ptr, size_t size, bool executable = false);
|
bool WriteProtectMemory(void* ptr, size_t size, bool executable = false);
|
||||||
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false);
|
bool UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false);
|
||||||
size_t MemPhysical();
|
size_t MemPhysical();
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
@ -391,9 +391,10 @@ static void CpuThread(const std::optional<std::string>& savestate_path, bool del
|
|||||||
static_cast<void>(IDCache::GetEnvForThread());
|
static_cast<void>(IDCache::GetEnvForThread());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const bool fastmem_enabled = Config::Get(Config::MAIN_FASTMEM);
|
// The JIT need to be able to intercept faults, both for fastmem and for the BLR optimization.
|
||||||
if (fastmem_enabled)
|
const bool exception_handler = EMM::IsExceptionHandlerSupported();
|
||||||
EMM::InstallExceptionHandler(); // Let's run under memory watch
|
if (exception_handler)
|
||||||
|
EMM::InstallExceptionHandler();
|
||||||
|
|
||||||
#ifdef USE_MEMORYWATCHER
|
#ifdef USE_MEMORYWATCHER
|
||||||
s_memory_watcher = std::make_unique<MemoryWatcher>();
|
s_memory_watcher = std::make_unique<MemoryWatcher>();
|
||||||
@ -441,7 +442,7 @@ static void CpuThread(const std::optional<std::string>& savestate_path, bool del
|
|||||||
|
|
||||||
s_is_started = false;
|
s_is_started = false;
|
||||||
|
|
||||||
if (fastmem_enabled)
|
if (exception_handler)
|
||||||
EMM::UninstallExceptionHandler();
|
EMM::UninstallExceptionHandler();
|
||||||
|
|
||||||
if (GDBStub::IsActive())
|
if (GDBStub::IsActive())
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/CoreTiming.h"
|
#include "Core/CoreTiming.h"
|
||||||
#include "Core/HW/CPU.h"
|
#include "Core/HW/CPU.h"
|
||||||
|
#include "Core/MemTools.h"
|
||||||
#include "Core/PowerPC/PPCAnalyst.h"
|
#include "Core/PowerPC/PPCAnalyst.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
@ -132,7 +133,8 @@ void JitBase::RefreshConfig()
|
|||||||
analyzer.SetDivByZeroExceptionsEnabled(m_enable_div_by_zero_exceptions);
|
analyzer.SetDivByZeroExceptionsEnabled(m_enable_div_by_zero_exceptions);
|
||||||
|
|
||||||
bool any_watchpoints = m_system.GetPowerPC().GetMemChecks().HasAny();
|
bool any_watchpoints = m_system.GetPowerPC().GetMemChecks().HasAny();
|
||||||
jo.fastmem = m_fastmem_enabled && jo.fastmem_arena && (m_ppc_state.msr.DR || !any_watchpoints);
|
jo.fastmem = m_fastmem_enabled && jo.fastmem_arena && (m_ppc_state.msr.DR || !any_watchpoints) &&
|
||||||
|
EMM::IsExceptionHandlerSupported();
|
||||||
jo.memcheck = m_system.IsMMUMode() || m_system.IsPauseOnPanicMode() || any_watchpoints;
|
jo.memcheck = m_system.IsMMUMode() || m_system.IsPauseOnPanicMode() || any_watchpoints;
|
||||||
jo.fp_exceptions = m_enable_float_exceptions;
|
jo.fp_exceptions = m_enable_float_exceptions;
|
||||||
jo.div_by_zero_exceptions = m_enable_div_by_zero_exceptions;
|
jo.div_by_zero_exceptions = m_enable_div_by_zero_exceptions;
|
||||||
@ -140,7 +142,8 @@ void JitBase::RefreshConfig()
|
|||||||
|
|
||||||
void JitBase::InitBLROptimization()
|
void JitBase::InitBLROptimization()
|
||||||
{
|
{
|
||||||
m_enable_blr_optimization = jo.enableBlocklink && m_fastmem_enabled && !m_enable_debugging;
|
m_enable_blr_optimization =
|
||||||
|
jo.enableBlocklink && !m_enable_debugging && EMM::IsExceptionHandlerSupported();
|
||||||
m_cleanup_after_stackfault = false;
|
m_cleanup_after_stackfault = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +154,12 @@ void JitBase::ProtectStack()
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ULONG reserveSize = SAFE_STACK_SIZE;
|
ULONG reserveSize = SAFE_STACK_SIZE;
|
||||||
SetThreadStackGuarantee(&reserveSize);
|
if (!SetThreadStackGuarantee(&reserveSize))
|
||||||
|
{
|
||||||
|
PanicAlertFmt("Failed to set thread stack guarantee");
|
||||||
|
m_enable_blr_optimization = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
auto [stack_addr, stack_size] = Common::GetCurrentThreadStack();
|
auto [stack_addr, stack_size] = Common::GetCurrentThreadStack();
|
||||||
|
|
||||||
@ -184,7 +192,12 @@ void JitBase::ProtectStack()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_stack_guard = reinterpret_cast<u8*>(stack_guard_addr);
|
m_stack_guard = reinterpret_cast<u8*>(stack_guard_addr);
|
||||||
Common::ReadProtectMemory(m_stack_guard, GUARD_SIZE);
|
if (!Common::ReadProtectMemory(m_stack_guard, GUARD_SIZE))
|
||||||
|
{
|
||||||
|
m_stack_guard = nullptr;
|
||||||
|
m_enable_blr_optimization = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user