Merge pull request #9237 from hrydgard/memory-cleanups

Memory cleanups
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2017-01-26 10:35:41 +01:00
commit c9a2f87edc
20 files changed
+30 -75

No files matched your search

+5 -7
View File
@@ -51,12 +51,9 @@ public:
// Call this before you generate any code.
void AllocCodeSpace(int size) {
region_size = size;
// The protection will be set to RW if PlatformIsWXExclusive.
region = (u8*)AllocateExecutableMemory(region_size);
T::SetCodePointer(region);
// On W^X platforms, we start with writable but not executable pages.
if (PlatformIsWXExclusive()) {
ProtectMemoryPages(region, region_size, MEM_PROT_READ | MEM_PROT_WRITE);
}
}
// Always clear code space with breakpoints, so that if someone accidentally executes
@@ -71,7 +68,8 @@ public:
ResetCodePtr();
}
// BeginWrite/EndWrite assume that we keep appending. If you don't specify a size and we encounter later executable block, we're screwed.
// BeginWrite/EndWrite assume that we keep appending.
// If you don't specify a size and we later encounter an executable non-writable block, we're screwed.
// These CANNOT be nested. We rely on the memory protection starting at READ|WRITE after start and reset.
void BeginWrite(size_t sizeEstimate = 1) {
#ifdef _DEBUG
@@ -88,9 +86,9 @@ public:
void EndWrite() {
// OK, we're done. Re-protect the memory we touched.
if (PlatformIsWXExclusive()) {
if (PlatformIsWXExclusive() && writeStart_ != nullptr) {
const uint8_t *end = GetCodePtr();
ProtectMemoryPages(writeStart_, end, MEM_PROT_READ | MEM_PROT_EXEC);
ProtectMemoryPages(writeStart_, end - writeStart_, MEM_PROT_READ | MEM_PROT_EXEC);
writeStart_ = nullptr;
}
}
-15
View File
@@ -67,21 +67,6 @@ error:
return ret;
}
static int ashmem_set_prot_region(int fd, int prot) {
return ioctl(fd, ASHMEM_SET_PROT_MASK, prot);
}
static int ashmem_pin_region(int fd, size_t offset, size_t len) {
// Even on 64-bit, it seems these arguments are 32-bit and thus need a cast to avoid warnings.
struct ashmem_pin pin = { (uint32_t)offset, (uint32_t)len };
return ioctl(fd, ASHMEM_PIN, &pin);
}
static int ashmem_unpin_region(int fd, size_t offset, size_t len) {
struct ashmem_pin pin = { (uint32_t)offset, (uint32_t)len };
return ioctl(fd, ASHMEM_UNPIN, &pin);
}
// Windows mappings need to be on 64K boundaries, due to Alpha legacy.
size_t MemArena::roundup(size_t x) {
return x;
+15 -8
View File
@@ -50,7 +50,7 @@ static SYSTEM_INFO sys_info;
#ifdef _WIN32
// Win32 flags are odd...
uint32_t ConvertProtFlagsWin32(uint32_t flags) {
static uint32_t ConvertProtFlagsWin32(uint32_t flags) {
uint32_t protect = 0;
switch (flags) {
case 0: protect = PAGE_NOACCESS; break;
@@ -67,7 +67,7 @@ uint32_t ConvertProtFlagsWin32(uint32_t flags) {
#else
uint32_t ConvertProtFlagsUnix(uint32_t flags) {
static uint32_t ConvertProtFlagsUnix(uint32_t flags) {
uint32_t protect = 0;
if (flags & MEM_PROT_READ)
protect |= PROT_READ;
@@ -117,6 +117,9 @@ static void *SearchForFreeMem(size_t size) {
void *AllocateExecutableMemory(size_t size) {
#if defined(_WIN32)
void *ptr;
DWORD prot = PAGE_EXECUTE_READWRITE;
if (PlatformIsWXExclusive())
prot = PAGE_READWRITE;
#if defined(_M_X64)
if ((uintptr_t)&hint_location > 0xFFFFFFFFULL) {
if (sys_info.dwPageSize == 0)
@@ -131,14 +134,16 @@ void *AllocateExecutableMemory(size_t size) {
ptr = SearchForFreeMem(aligned_size);
}
if (ptr) {
ptr = VirtualAlloc(ptr, aligned_size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
ptr = VirtualAlloc(ptr, aligned_size, MEM_RESERVE | MEM_COMMIT, prot);
} else {
ERROR_LOG(COMMON, "Unable to find nearby executable memory for jit");
}
}
else
#endif
ptr = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
{
ptr = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, prot);
}
#else
static char *map_hint = 0;
#if defined(_M_X64)
@@ -192,7 +197,6 @@ void *AllocateExecutableMemory(size_t size) {
}
}
#endif
return ptr;
}
@@ -205,7 +209,7 @@ void *AllocateMemoryPages(size_t size, uint32_t memProtFlags) {
PanicAlert("Failed to allocate raw memory");
#else
uint32_t protect = ConvertProtFlagsUnix(memProtFlags);
void* ptr = mmap(0, size, protect, MAP_ANON | MAP_PRIVATE, -1, 0);
void *ptr = mmap(0, size, protect, MAP_ANON | MAP_PRIVATE, -1, 0);
if (ptr == MAP_FAILED) {
ERROR_LOG(MEMMAP, "Failed to allocate memory pages: errno=%d", errno);
return nullptr;
@@ -274,11 +278,14 @@ bool PlatformIsWXExclusive() {
}
bool ProtectMemoryPages(const void* ptr, size_t size, uint32_t memProtFlags) {
VERBOSE_LOG(JIT, "ProtectMemoryPages: %p (%d) : r%d w%d x%d", ptr, (int)size, (memProtFlags & MEM_PROT_READ) != 0, (memProtFlags & MEM_PROT_WRITE) != 0, (memProtFlags & MEM_PROT_EXEC) != 0);
VERBOSE_LOG(JIT, "ProtectMemoryPages: %p (%d) : r%d w%d x%d", ptr, (int)size,
(memProtFlags & MEM_PROT_READ) != 0, (memProtFlags & MEM_PROT_WRITE) != 0, (memProtFlags & MEM_PROT_EXEC) != 0);
if (PlatformIsWXExclusive()) {
if ((memProtFlags & (MEM_PROT_WRITE | MEM_PROT_EXEC)) == (MEM_PROT_WRITE | MEM_PROT_EXEC))
if ((memProtFlags & (MEM_PROT_WRITE | MEM_PROT_EXEC)) == (MEM_PROT_WRITE | MEM_PROT_EXEC)) {
ERROR_LOG(MEMMAP, "Bad memory protection %d!", memProtFlags);
PanicAlert("Bad memory protect : W^X is in effect, can't both write and exec");
}
}
// Note - VirtualProtect will affect the full pages containing the requested range.
// mprotect does not seem to, at least not on Android unless I made a mistake somewhere, so we manually round.
-3
View File
@@ -37,9 +37,6 @@ void* AllocateExecutableMemory(size_t size);
void* AllocateMemoryPages(size_t size, uint32_t memProtFlags);
// Note that on platforms returning PlatformIsWXExclusive, you cannot set a page to be both readable and writable at the same time.
bool ProtectMemoryPages(const void* ptr, size_t size, uint32_t memProtFlags);
inline void ProtectMemoryPages(const void *start, const void *end, uint32_t memProtFlags) {
ProtectMemoryPages((void *)start, (const uint8_t *)end - (const uint8_t *)start, memProtFlags);
}
void FreeMemoryPages(void* ptr, size_t size);
// Regular aligned memory. Don't try to apply memory protection willy-nilly to memory allocated this way as in-page alignment is unknown (though could be checked).
+1 -1
View File
@@ -540,7 +540,7 @@ void CBreakPoints::Update(u32 addr)
if (addr != 0)
MIPSComp::jit->InvalidateCacheAt(addr - 4, 8);
else
MIPSComp::jit->InvalidateCache();
MIPSComp::jit->ClearCache();
if (resume)
Core_EnableStepping(false);
-5
View File
@@ -154,11 +154,6 @@ void ArmJit::ClearCache()
GenerateFixedCode();
}
void ArmJit::InvalidateCache()
{
blocks.Clear();
}
void ArmJit::InvalidateCacheAt(u32 em_address, int length)
{
blocks.InvalidateICache(em_address, length);
-1
View File
@@ -174,7 +174,6 @@ public:
void RestoreSavedEmuHackOps(std::vector<u32> saved) override { blocks.RestoreSavedEmuHackOps(saved); }
void ClearCache() override;
void InvalidateCache() override;
void InvalidateCacheAt(u32 em_address, int length = 4) override;
void EatPrefix() override { js.EatPrefix(); }
+5 -9
View File
@@ -146,10 +146,6 @@ void Arm64Jit::ClearCache() {
GenerateFixedCode(jo);
}
void Arm64Jit::InvalidateCache() {
blocks.Clear();
}
void Arm64Jit::InvalidateCacheAt(u32 em_address, int length) {
blocks.InvalidateICache(em_address, length);
}
@@ -194,7 +190,7 @@ void Arm64Jit::Compile(u32 em_address) {
ClearCache();
}
BeginWrite();
BeginWrite(4);
int block_num = blocks.AllocateBlock(em_address);
JitBlock *b = blocks.GetBlock(block_num);
@@ -203,6 +199,9 @@ void Arm64Jit::Compile(u32 em_address) {
EndWrite();
// Don't forget to zap the newly written instructions in the instruction cache!
FlushIcache();
bool cleanSlate = false;
if (js.hasSetRounding && !js.lastSetRounding) {
@@ -336,9 +335,6 @@ const u8 *Arm64Jit::DoJit(u32 em_address, JitBlock *b) {
if (dontLogBlocks > 0)
dontLogBlocks--;
// Don't forget to zap the newly written instructions in the instruction cache!
FlushIcache();
if (js.lastContinuedPC == 0) {
b->originalSize = js.numInstructions;
} else {
@@ -406,7 +402,7 @@ void Arm64Jit::LinkBlock(u8 *exitPoint, const u8 *checkedEntry) {
}
ARM64XEmitter emit(exitPoint);
emit.B(checkedEntry);
// TODO: Write stuff after.
// TODO: Write stuff after, convering up the now-unused instructions.
emit.FlushIcache();
if (PlatformIsWXExclusive()) {
ProtectMemoryPages(exitPoint, 32, MEM_PROT_READ | MEM_PROT_EXEC);
-1
View File
@@ -175,7 +175,6 @@ public:
void RestoreSavedEmuHackOps(std::vector<u32> saved) override { blocks.RestoreSavedEmuHackOps(saved); }
void ClearCache() override;
void InvalidateCache() override;
void InvalidateCacheAt(u32 em_address, int length = 4) override;
void EatPrefix() override { js.EatPrefix(); }
-4
View File
@@ -69,10 +69,6 @@ void IRJit::ClearCache() {
blocks_.Clear();
}
void IRJit::InvalidateCache() {
blocks_.Clear();
}
void IRJit::InvalidateCacheAt(u32 em_address, int length) {
blocks_.InvalidateICache(em_address, length);
}
-1
View File
@@ -144,7 +144,6 @@ public:
void RestoreSavedEmuHackOps(std::vector<u32> saved) override { blocks_.RestoreSavedEmuHackOps(saved); }
void ClearCache() override;
void InvalidateCache() override;
void InvalidateCacheAt(u32 em_address, int length = 4) override;
const u8 *GetDispatcher() const override { return nullptr; }
+1 -1
View File
@@ -60,7 +60,7 @@ op_agent_t agent;
const u32 INVALID_EXIT = 0xFFFFFFFF;
JitBlockCache::JitBlockCache(MIPSState *mips, CodeBlockCommon *codeBlock) :
codeBlock_(codeBlock), blocks_(0), num_blocks_(0) {
codeBlock_(codeBlock), blocks_(nullptr), num_blocks_(0) {
}
JitBlockCache::~JitBlockCache() {
-1
View File
@@ -123,7 +123,6 @@ namespace MIPSComp {
virtual bool DescribeCodePtr(const u8 *ptr, std::string &name) = 0;
virtual const u8 *GetDispatcher() const = 0;
virtual JitBlockCache *GetBlockCache() = 0;
virtual void InvalidateCache() = 0;
virtual void InvalidateCacheAt(u32 em_address, int length = 4) = 0;
virtual void DoState(PointerWrap &p) = 0;
virtual void DoDummyState(PointerWrap &p) = 0;
-5
View File
@@ -99,11 +99,6 @@ void MipsJit::ClearCache()
//GenerateFixedCode();
}
void MipsJit::InvalidateCache()
{
blocks.Clear();
}
void MipsJit::InvalidateCacheAt(u32 em_address, int length)
{
blocks.InvalidateICache(em_address, length);
-1
View File
@@ -135,7 +135,6 @@ public:
void RestoreSavedEmuHackOps(std::vector<u32> saved) override { blocks.RestoreSavedEmuHackOps(saved); }
void ClearCache() override;
void InvalidateCache() override;
void InvalidateCacheAt(u32 em_address, int length = 4) override;
void EatPrefix() override { js.EatPrefix(); }
-5
View File
@@ -94,11 +94,6 @@ void FakeJit::ClearCache()
//GenerateFixedCode();
}
void FakeJit::InvalidateCache()
{
blocks.Clear();
}
void FakeJit::InvalidateCacheAt(u32 em_address, int length)
{
blocks.InvalidateICache(em_address, length);
-1
View File
@@ -128,7 +128,6 @@ public:
JitBlockCache *GetBlockCache() { return &blocks; }
void ClearCache();
void InvalidateCache();
void InvalidateCacheAt(u32 em_address, int length = 4);
void EatPrefix() { js.EatPrefix(); }
-5
View File
@@ -245,11 +245,6 @@ void Jit::ClearCache()
GenerateFixedCode(jo);
}
void Jit::InvalidateCache()
{
blocks.Clear();
}
void Jit::CompileDelaySlot(int flags, RegCacheState *state)
{
// Need to offset the downcount which was already incremented for the branch + delay slot.
-1
View File
@@ -163,7 +163,6 @@ public:
void RestoreSavedEmuHackOps(std::vector<u32> saved) override { blocks.RestoreSavedEmuHackOps(saved); }
void ClearCache() override;
void InvalidateCache() override;
void InvalidateCacheAt(u32 em_address, int length = 4) override {
if (blocks.RangeMayHaveEmuHacks(em_address, em_address + length)) {
blocks.InvalidateICache(em_address, length);
+3
View File
@@ -363,6 +363,9 @@ void SystemInfoScreen::CreateViews() {
deviceSpecs->Add(new InfoItem("D3DX Version", StringFromFormat("%d", GetD3DXVersion())));
}
#endif
deviceSpecs->Add(new ItemHeader("OS Information"));
deviceSpecs->Add(new InfoItem("Memory Page Size", StringFromFormat("%d bytes", GetMemoryProtectPageSize())));
deviceSpecs->Add(new InfoItem("RW/RX exclusive: ", PlatformIsWXExclusive() ? "Yes" : "No"));
#ifdef __ANDROID__
deviceSpecs->Add(new ItemHeader("Audio Information"));