parent
2a65442933
commit
3432a08e0a
5 changed files with 59 additions and 1 deletions
|
@ -22,6 +22,7 @@
|
|||
#include "common/assert.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/variant_util.h"
|
||||
#include "frontend/A32/location_descriptor.h"
|
||||
#include "frontend/A32/types.h"
|
||||
|
@ -85,6 +86,9 @@ A32EmitX64::A32EmitX64(BlockOfCode& code, A32::UserConfig config, A32::Jit* jit_
|
|||
A32EmitX64::~A32EmitX64() = default;
|
||||
|
||||
A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
|
||||
code.EnableWriting();
|
||||
SCOPE_EXIT { code.DisableWriting(); };
|
||||
|
||||
code.align();
|
||||
const u8* const entrypoint = code.getCurr();
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "common/assert.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/variant_util.h"
|
||||
#include "frontend/A64/location_descriptor.h"
|
||||
#include "frontend/A64/types.h"
|
||||
|
@ -71,6 +72,9 @@ A64EmitX64::A64EmitX64(BlockOfCode& code, A64::UserConfig conf, A64::Jit* jit_in
|
|||
A64EmitX64::~A64EmitX64() = default;
|
||||
|
||||
A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) {
|
||||
code.EnableWriting();
|
||||
SCOPE_EXIT { code.DisableWriting(); };
|
||||
|
||||
code.align();
|
||||
const u8* const entrypoint = code.getCurr();
|
||||
|
||||
|
|
|
@ -15,6 +15,12 @@
|
|||
#include "backend/x64/block_of_code.h"
|
||||
#include "common/assert.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
namespace Dynarmic::BackendX64 {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -36,16 +42,42 @@ const Xbyak::Reg64 BlockOfCode::ABI_PARAM6 = Xbyak::util::r9;
|
|||
const std::array<Xbyak::Reg64, 6> BlockOfCode::ABI_PARAMS = {BlockOfCode::ABI_PARAM1, BlockOfCode::ABI_PARAM2, BlockOfCode::ABI_PARAM3, BlockOfCode::ABI_PARAM4, BlockOfCode::ABI_PARAM5, BlockOfCode::ABI_PARAM6};
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr size_t TOTAL_CODE_SIZE = 128 * 1024 * 1024;
|
||||
constexpr size_t FAR_CODE_OFFSET = 100 * 1024 * 1024;
|
||||
constexpr size_t CONSTANT_POOL_SIZE = 2 * 1024 * 1024;
|
||||
|
||||
class CustomXbyakAllocator : public Xbyak::Allocator {
|
||||
public:
|
||||
bool useProtect() const override { return false; }
|
||||
};
|
||||
|
||||
// This is threadsafe as Xbyak::Allocator does not contain any state; it is a pure interface.
|
||||
CustomXbyakAllocator s_allocator;
|
||||
|
||||
void ProtectMemory(const void* base, size_t size, bool is_executable) {
|
||||
#ifdef _WIN32
|
||||
DWORD oldProtect = 0;
|
||||
VirtualProtect(const_cast<void*>(base), size, is_executable ? PAGE_EXECUTE_READ : PAGE_READWRITE, &oldProtect);
|
||||
#else
|
||||
static const size_t pageSize = sysconf(_SC_PAGESIZE);
|
||||
const size_t iaddr = reinterpret_cast<size_t>(base);
|
||||
const size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1));
|
||||
const int mode = is_executable ? (PROT_READ | PROT_EXEC) : (PROT_READ | PROT_WRITE);
|
||||
mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi)
|
||||
: Xbyak::CodeGenerator(TOTAL_CODE_SIZE)
|
||||
: Xbyak::CodeGenerator(TOTAL_CODE_SIZE, nullptr, &s_allocator)
|
||||
, cb(std::move(cb))
|
||||
, jsi(jsi)
|
||||
, constant_pool(*this, CONSTANT_POOL_SIZE)
|
||||
{
|
||||
EnableWriting();
|
||||
GenRunCode();
|
||||
exception_handler.Register(*this);
|
||||
}
|
||||
|
@ -55,6 +87,15 @@ void BlockOfCode::PreludeComplete() {
|
|||
near_code_begin = getCurr();
|
||||
far_code_begin = getCurr() + FAR_CODE_OFFSET;
|
||||
ClearCache();
|
||||
DisableWriting();
|
||||
}
|
||||
|
||||
void BlockOfCode::EnableWriting() {
|
||||
ProtectMemory(getCode(), maxSize_, false);
|
||||
}
|
||||
|
||||
void BlockOfCode::DisableWriting() {
|
||||
ProtectMemory(getCode(), maxSize_, true);
|
||||
}
|
||||
|
||||
void BlockOfCode::ClearCache() {
|
||||
|
|
|
@ -34,6 +34,11 @@ public:
|
|||
/// Call when external emitters have finished emitting their preludes.
|
||||
void PreludeComplete();
|
||||
|
||||
/// Change permissions to RW. This is required to support systems with W^X enforced.
|
||||
void EnableWriting();
|
||||
/// Change permissions to RX. This is required to support systems with W^X enforced.
|
||||
void DisableWriting();
|
||||
|
||||
/// Clears this block of code and resets code pointer to beginning.
|
||||
void ClearCache();
|
||||
/// Calculates how much space is remaining to use. This is the minimum of near code and far code.
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "common/assert.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/variant_util.h"
|
||||
#include "frontend/ir/basic_block.h"
|
||||
#include "frontend/ir/microinstruction.h"
|
||||
|
@ -327,6 +328,9 @@ void EmitX64::ClearCache() {
|
|||
}
|
||||
|
||||
void EmitX64::InvalidateBasicBlocks(const std::unordered_set<IR::LocationDescriptor>& locations) {
|
||||
code.EnableWriting();
|
||||
SCOPE_EXIT { code.DisableWriting(); };
|
||||
|
||||
for (const auto &descriptor : locations) {
|
||||
auto it = block_descriptors.find(descriptor);
|
||||
if (it == block_descriptors.end()) {
|
||||
|
|
Loading…
Reference in a new issue