mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Opens up for having multiple JIT implementations available at runtime, which could be use for experimenting with new JIT compiler types or for unit testing one JIT on another architecture. Very few of the newly virtual calls are on any sort of critical path so hopefully there will not be a performance loss.
88 lines
2.1 KiB
C++
88 lines
2.1 KiB
C++
// Copyright 2013 Dolphin Emulator Project
|
|
// Licensed under GPLv2
|
|
// Refer to the license.txt file included.
|
|
|
|
#pragma once
|
|
|
|
#include "Common.h"
|
|
#include "MemoryUtil.h"
|
|
|
|
// Everything that needs to generate code should inherit from this.
|
|
// You get memory management for free, plus, you can use all emitter functions without
|
|
// having to prefix them with gen-> or something similar.
|
|
// Example implementation:
|
|
// class JIT : public CodeBlock<ARMXEmitter>, public JitInterface {}
|
|
template<class T> class CodeBlock : public T, NonCopyable
|
|
{
|
|
private:
|
|
// A privately used function to set the executable RAM space to something invalid.
|
|
// For debugging usefulness it should be used to set the RAM to a host specific breakpoint instruction
|
|
virtual void PoisonMemory() = 0;
|
|
|
|
protected:
|
|
u8 *region;
|
|
size_t region_size;
|
|
|
|
public:
|
|
CodeBlock() : region(nullptr), region_size(0) {}
|
|
virtual ~CodeBlock() { if (region) FreeCodeSpace(); }
|
|
|
|
// Call this before you generate any code.
|
|
void AllocCodeSpace(int size)
|
|
{
|
|
region_size = size;
|
|
region = (u8*)AllocateExecutableMemory(region_size);
|
|
T::SetCodePtr(region);
|
|
}
|
|
|
|
// Always clear code space with breakpoints, so that if someone accidentally executes
|
|
// uninitialized, it just breaks into the debugger.
|
|
void ClearCodeSpace()
|
|
{
|
|
PoisonMemory();
|
|
ResetCodePtr();
|
|
}
|
|
|
|
// Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
|
|
void FreeCodeSpace()
|
|
{
|
|
#ifdef __SYMBIAN32__
|
|
ResetExecutableMemory(region);
|
|
#else
|
|
FreeMemoryPages(region, region_size);
|
|
#endif
|
|
region = nullptr;
|
|
region_size = 0;
|
|
}
|
|
|
|
bool IsInSpace(const u8 *ptr)
|
|
{
|
|
return (ptr >= region) && (ptr < (region + region_size));
|
|
}
|
|
|
|
// Cannot currently be undone. Will write protect the entire code region.
|
|
// Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
|
|
void WriteProtect()
|
|
{
|
|
WriteProtectMemory(region, region_size, true);
|
|
}
|
|
|
|
void ResetCodePtr()
|
|
{
|
|
T::SetCodePtr(region);
|
|
}
|
|
|
|
size_t GetSpaceLeft() const
|
|
{
|
|
return region_size - (T::GetCodePtr() - region);
|
|
}
|
|
|
|
u8 *GetBasePtr() {
|
|
return region;
|
|
}
|
|
|
|
size_t GetOffset(const u8 *ptr) const {
|
|
return ptr - region;
|
|
}
|
|
};
|
|
|