dynarmic/src/backend_x64/block_of_code.h

152 lines
4.7 KiB
C
Raw Normal View History

2016-07-01 14:01:06 +01:00
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* This software may be used and distributed according to the terms of the GNU
* General Public License version 2 or any later version.
*/
#pragma once
#include <array>
#include <memory>
#include <type_traits>
2016-08-24 20:07:08 +01:00
#include <xbyak.h>
#include <xbyak_util.h>
2018-01-06 21:15:25 +00:00
#include "backend_x64/callback.h"
#include "backend_x64/constant_pool.h"
2018-01-04 21:12:02 +00:00
#include "backend_x64/jitstate_info.h"
2016-07-01 14:01:06 +01:00
#include "common/common_types.h"
namespace Dynarmic::BackendX64 {
2016-07-01 14:01:06 +01:00
2018-01-04 21:12:02 +00:00
using CodePtr = const void*;
struct RunCodeCallbacks {
2018-01-06 21:15:25 +00:00
std::unique_ptr<Callback> LookupBlock;
std::unique_ptr<Callback> AddTicks;
std::unique_ptr<Callback> GetTicksRemaining;
2018-01-04 21:12:02 +00:00
};
2017-04-07 10:52:44 +01:00
2016-08-24 20:07:08 +01:00
class BlockOfCode final : public Xbyak::CodeGenerator {
2016-07-01 14:01:06 +01:00
public:
2018-01-04 21:12:02 +00:00
BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi);
/// Call when external emitters have finished emitting their preludes.
void PreludeComplete();
2016-08-12 18:17:31 +01:00
/// 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.
size_t SpaceRemaining() const;
2016-07-01 14:01:06 +01:00
2018-01-04 21:12:02 +00:00
/// Runs emulated code.
void RunCode(void* jit_state) const;
/// Runs emulated code from code_ptr.
void RunCodeFrom(void* jit_state, CodePtr code_ptr) const;
2017-04-07 10:52:44 +01:00
/// Code emitter: Returns to dispatcher
void ReturnFromRunCode(bool mxcsr_already_exited = false);
2017-04-07 10:52:44 +01:00
/// Code emitter: Returns to dispatcher, forces return to host
void ForceReturnFromRunCode(bool mxcsr_already_exited = false);
2016-08-12 18:17:31 +01:00
/// Code emitter: Makes guest MXCSR the current MXCSR
void SwitchMxcsrOnEntry();
2016-08-12 18:17:31 +01:00
/// Code emitter: Makes saved host MXCSR the current MXCSR
void SwitchMxcsrOnExit();
2016-08-24 20:07:08 +01:00
/// Code emitter: Calls the function
template <typename FunctionPointer>
void CallFunction(FunctionPointer fn) {
static_assert(std::is_pointer<FunctionPointer>() && std::is_function<std::remove_pointer_t<FunctionPointer>>(),
"Supplied type must be a pointer to a function");
const u64 address = reinterpret_cast<u64>(fn);
const u64 distance = address - (getCurr<u64>() + 5);
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
// Far call
mov(rax, address);
call(rax);
} else {
call(fn);
}
}
Xbyak::Address MConst(u64 constant);
2016-07-01 14:01:06 +01:00
2017-04-19 18:58:36 +01:00
/// Far code sits far away from the near code. Execution remains primarily in near code.
/// "Cold" / Rarely executed instructions sit in far code, so the CPU doesn't fetch them unless necessary.
void SwitchToFarCode();
void SwitchToNearCode();
2018-01-28 17:56:26 +00:00
CodePtr GetCodeBegin() const;
2016-08-24 20:07:08 +01:00
const void* GetReturnFromRunCodeAddress() const {
2017-04-07 10:52:44 +01:00
return return_from_run_code[0];
}
const void* GetForceReturnFromRunCodeAddress() const {
return return_from_run_code[FORCE_RETURN];
}
2016-08-24 20:07:08 +01:00
void int3() { db(0xCC); }
/// Allocate memory of `size` bytes from the same block of memory the code is in.
/// This is useful for objects that need to be placed close to or within code.
/// The lifetime of this memory is the same as the code around it.
void* AllocateFromCodeSpace(size_t size);
void SetCodePtr(CodePtr code_ptr);
2016-08-24 20:07:08 +01:00
void EnsurePatchLocationSize(CodePtr begin, size_t size);
static const Xbyak::Reg64 ABI_RETURN;
2018-01-24 15:53:12 +00:00
#ifndef _WIN32
static const Xbyak::Reg64 ABI_RETURN2;
#endif
static const Xbyak::Reg64 ABI_PARAM1;
static const Xbyak::Reg64 ABI_PARAM2;
static const Xbyak::Reg64 ABI_PARAM3;
static const Xbyak::Reg64 ABI_PARAM4;
2016-08-24 20:07:08 +01:00
bool DoesCpuSupport(Xbyak::util::Cpu::Type type) const;
2018-01-23 18:47:10 +00:00
JitStateInfo GetJitStateInfo() const { return jsi; }
2016-07-01 14:01:06 +01:00
private:
2018-01-04 21:12:02 +00:00
RunCodeCallbacks cb;
JitStateInfo jsi;
2017-04-07 10:52:44 +01:00
2018-01-04 21:12:02 +00:00
bool prelude_complete = false;
2017-04-19 18:58:36 +01:00
CodePtr near_code_begin;
CodePtr far_code_begin;
ConstantPool constant_pool;
2017-04-19 18:58:36 +01:00
bool in_far_code = false;
CodePtr near_code_ptr;
CodePtr far_code_ptr;
2018-01-04 21:12:02 +00:00
using RunCodeFuncType = void(*)(void*);
using RunCodeFromFuncType = void(*)(void*, CodePtr);
RunCodeFuncType run_code = nullptr;
RunCodeFromFuncType run_code_from = nullptr;
static constexpr size_t MXCSR_ALREADY_EXITED = 1 << 0;
2017-04-07 10:52:44 +01:00
static constexpr size_t FORCE_RETURN = 1 << 1;
std::array<const void*, 4> return_from_run_code;
2016-07-01 14:01:06 +01:00
void GenRunCode();
class ExceptionHandler final {
public:
ExceptionHandler();
~ExceptionHandler();
void Register(BlockOfCode* code);
private:
struct Impl;
std::unique_ptr<Impl> impl;
};
ExceptionHandler exception_handler;
Xbyak::util::Cpu cpu_info;
2016-07-01 14:01:06 +01:00
};
} // namespace Dynarmic::BackendX64