From 8f9d1dbf4ee8c2beca046db92bf6111a9e1638d3 Mon Sep 17 00:00:00 2001 From: Merry Date: Tue, 29 Nov 2022 12:22:45 +0000 Subject: [PATCH] address_space: Deduplicate {A32,A64}AddressSpace --- src/dynarmic/CMakeLists.txt | 2 + .../backend/arm64/a32_address_space.cpp | 173 +------------- .../backend/arm64/a32_address_space.h | 70 +----- .../backend/arm64/a64_address_space.cpp | 196 +--------------- .../backend/arm64/a64_address_space.h | 77 +------ src/dynarmic/backend/arm64/address_space.cpp | 213 ++++++++++++++++++ src/dynarmic/backend/arm64/address_space.h | 92 ++++++++ 7 files changed, 327 insertions(+), 496 deletions(-) create mode 100644 src/dynarmic/backend/arm64/address_space.cpp create mode 100644 src/dynarmic/backend/arm64/address_space.h diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt index 35335d70..992f3c4f 100644 --- a/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/CMakeLists.txt @@ -373,6 +373,8 @@ elseif(ARCHITECTURE STREQUAL "arm64") backend/arm64/a32_jitstate.h backend/arm64/abi.cpp backend/arm64/abi.h + backend/arm64/address_space.cpp + backend/arm64/address_space.h backend/arm64/devirtualize.h backend/arm64/emit_arm64.cpp backend/arm64/emit_arm64.h diff --git a/src/dynarmic/backend/arm64/a32_address_space.cpp b/src/dynarmic/backend/arm64/a32_address_space.cpp index a7a8a7a8..333d21fa 100644 --- a/src/dynarmic/backend/arm64/a32_address_space.cpp +++ b/src/dynarmic/backend/arm64/a32_address_space.cpp @@ -14,6 +14,7 @@ #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h" #include "dynarmic/frontend/A32/translate/a32_translate.h" +#include "dynarmic/interface/A32/config.h" #include "dynarmic/interface/exclusive_monitor.h" #include "dynarmic/ir/opt/passes.h" @@ -97,9 +98,8 @@ static void* EmitExclusiveWriteCallTrampoline(oaknut::CodeGenerator& code, const } A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf) - : conf(conf) - , mem(conf.code_cache_size) - , code(mem.ptr()) { + : AddressSpace(conf.code_cache_size) + , conf(conf) { EmitPrelude(); } @@ -121,33 +121,6 @@ IR::Block A32AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const { return ir_block; } -CodePtr A32AddressSpace::Get(IR::LocationDescriptor descriptor) { - if (const auto iter = block_entries.find(descriptor.Value()); iter != block_entries.end()) { - return iter->second; - } - return nullptr; -} - -CodePtr A32AddressSpace::GetOrEmit(IR::LocationDescriptor descriptor) { - if (CodePtr block_entry = Get(descriptor)) { - return block_entry; - } - - IR::Block ir_block = GenerateIR(descriptor); - const EmittedBlockInfo block_info = Emit(std::move(ir_block)); - - block_infos.insert_or_assign(descriptor.Value(), block_info); - block_entries.insert_or_assign(descriptor.Value(), block_info.entry_point); - return block_info.entry_point; -} - -void A32AddressSpace::ClearCache() { - block_entries.clear(); - block_infos.clear(); - block_references.clear(); - code.set_ptr(prelude_info.end_of_prelude); -} - void A32AddressSpace::EmitPrelude() { using namespace oaknut::util; @@ -291,18 +264,8 @@ void A32AddressSpace::EmitPrelude() { mem.protect(); } -size_t A32AddressSpace::GetRemainingSize() { - return conf.code_cache_size - (code.ptr() - reinterpret_cast(mem.ptr())); -} - -EmittedBlockInfo A32AddressSpace::Emit(IR::Block block) { - if (GetRemainingSize() < 1024 * 1024) { - ClearCache(); - } - - mem.unprotect(); - - const EmitConfig emit_conf{ +EmitConfig A32AddressSpace::GetEmitConfig() { + return EmitConfig{ .optimizations = conf.unsafe_optimizations ? conf.optimizations : conf.optimizations & all_safe_optimizations, .hook_isb = conf.hook_isb, @@ -328,132 +291,6 @@ EmittedBlockInfo A32AddressSpace::Emit(IR::Block block) { .coprocessors = conf.coprocessors, }; - EmittedBlockInfo block_info = EmitArm64(code, std::move(block), emit_conf); - - Link(block.Location(), block_info); - - mem.invalidate(reinterpret_cast(block_info.entry_point), block_info.size); - - RelinkForDescriptor(block.Location()); - - mem.protect(); - - return block_info; -} - -static void LinkBlockLinks(const CodePtr entry_point, const CodePtr target_ptr, const std::vector& block_relocations_list) { - using namespace oaknut; - using namespace oaknut::util; - - for (auto [ptr_offset] : block_relocations_list) { - CodeGenerator c{reinterpret_cast(entry_point + ptr_offset)}; - - if (target_ptr) { - c.B((void*)target_ptr); - } else { - c.NOP(); - } - } -} - -void A32AddressSpace::Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block_info) { - using namespace oaknut; - using namespace oaknut::util; - - for (auto [ptr_offset, target] : block_info.relocations) { - CodeGenerator c{reinterpret_cast(block_info.entry_point + ptr_offset)}; - - switch (target) { - case LinkTarget::ReturnToDispatcher: - c.B(prelude_info.return_to_dispatcher); - break; - case LinkTarget::ReturnFromRunCode: - c.B(prelude_info.return_from_run_code); - break; - case LinkTarget::ReadMemory8: - c.BL(prelude_info.read_memory_8); - break; - case LinkTarget::ReadMemory16: - c.BL(prelude_info.read_memory_16); - break; - case LinkTarget::ReadMemory32: - c.BL(prelude_info.read_memory_32); - break; - case LinkTarget::ReadMemory64: - c.BL(prelude_info.read_memory_64); - break; - case LinkTarget::ExclusiveReadMemory8: - c.BL(prelude_info.exclusive_read_memory_8); - break; - case LinkTarget::ExclusiveReadMemory16: - c.BL(prelude_info.exclusive_read_memory_16); - break; - case LinkTarget::ExclusiveReadMemory32: - c.BL(prelude_info.exclusive_read_memory_32); - break; - case LinkTarget::ExclusiveReadMemory64: - c.BL(prelude_info.exclusive_read_memory_64); - break; - case LinkTarget::WriteMemory8: - c.BL(prelude_info.write_memory_8); - break; - case LinkTarget::WriteMemory16: - c.BL(prelude_info.write_memory_16); - break; - case LinkTarget::WriteMemory32: - c.BL(prelude_info.write_memory_32); - break; - case LinkTarget::WriteMemory64: - c.BL(prelude_info.write_memory_64); - break; - case LinkTarget::ExclusiveWriteMemory8: - c.BL(prelude_info.exclusive_write_memory_8); - break; - case LinkTarget::ExclusiveWriteMemory16: - c.BL(prelude_info.exclusive_write_memory_16); - break; - case LinkTarget::ExclusiveWriteMemory32: - c.BL(prelude_info.exclusive_write_memory_32); - break; - case LinkTarget::ExclusiveWriteMemory64: - c.BL(prelude_info.exclusive_write_memory_64); - break; - case LinkTarget::CallSVC: - c.BL(prelude_info.call_svc); - break; - case LinkTarget::ExceptionRaised: - c.BL(prelude_info.exception_raised); - break; - case LinkTarget::InstructionSynchronizationBarrierRaised: - c.BL(prelude_info.isb_raised); - break; - case LinkTarget::AddTicks: - c.BL(prelude_info.add_ticks); - break; - case LinkTarget::GetTicksRemaining: - c.BL(prelude_info.get_ticks_remaining); - break; - default: - ASSERT_FALSE("Invalid relocation target"); - } - } - - for (auto [target_descriptor, list] : block_info.block_relocations) { - block_references[target_descriptor.Value()].emplace(block_descriptor.Value()); - LinkBlockLinks(block_info.entry_point, Get(target_descriptor), list); - } -} - -void A32AddressSpace::RelinkForDescriptor(IR::LocationDescriptor target_descriptor) { - for (auto block_descriptor : block_references[target_descriptor.Value()]) { - if (auto iter = block_infos.find(block_descriptor); iter != block_infos.end()) { - const EmittedBlockInfo& block_info = iter->second; - - LinkBlockLinks(block_info.entry_point, Get(target_descriptor), block_infos[block_descriptor].block_relocations[target_descriptor]); - - mem.invalidate(reinterpret_cast(block_info.entry_point), block_info.size); - } - } } } // namespace Dynarmic::Backend::Arm64 diff --git a/src/dynarmic/backend/arm64/a32_address_space.h b/src/dynarmic/backend/arm64/a32_address_space.h index 18ed118d..e33be9b0 100644 --- a/src/dynarmic/backend/arm64/a32_address_space.h +++ b/src/dynarmic/backend/arm64/a32_address_space.h @@ -5,84 +5,24 @@ #pragma once -#include -#include -#include -#include -#include - -#include "dynarmic/backend/arm64/emit_arm64.h" +#include "dynarmic/backend/arm64/address_space.h" #include "dynarmic/interface/A32/config.h" -#include "dynarmic/interface/halt_reason.h" -#include "dynarmic/ir/basic_block.h" -#include "dynarmic/ir/location_descriptor.h" namespace Dynarmic::Backend::Arm64 { -struct A32JitState; - -class A32AddressSpace final { +class A32AddressSpace final : public AddressSpace { public: explicit A32AddressSpace(const A32::UserConfig& conf); - IR::Block GenerateIR(IR::LocationDescriptor) const; + IR::Block GenerateIR(IR::LocationDescriptor) const override; - CodePtr Get(IR::LocationDescriptor descriptor); - - CodePtr GetOrEmit(IR::LocationDescriptor descriptor); - - void ClearCache(); - -private: +protected: friend class A32Core; void EmitPrelude(); - - size_t GetRemainingSize(); - EmittedBlockInfo Emit(IR::Block ir_block); - void Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block); - void RelinkForDescriptor(IR::LocationDescriptor target_descriptor); + EmitConfig GetEmitConfig() override; const A32::UserConfig conf; - - oaknut::CodeBlock mem; - oaknut::CodeGenerator code; - - tsl::robin_map block_entries; - tsl::robin_map block_infos; - tsl::robin_map> block_references; - - struct PreludeInfo { - u32* end_of_prelude; - - using RunCodeFuncType = HaltReason (*)(CodePtr entry_point, A32JitState* context, volatile u32* halt_reason); - RunCodeFuncType run_code; - RunCodeFuncType step_code; - void* return_to_dispatcher; - void* return_from_run_code; - - void* read_memory_8; - void* read_memory_16; - void* read_memory_32; - void* read_memory_64; - void* exclusive_read_memory_8; - void* exclusive_read_memory_16; - void* exclusive_read_memory_32; - void* exclusive_read_memory_64; - void* write_memory_8; - void* write_memory_16; - void* write_memory_32; - void* write_memory_64; - void* exclusive_write_memory_8; - void* exclusive_write_memory_16; - void* exclusive_write_memory_32; - void* exclusive_write_memory_64; - void* call_svc; - void* exception_raised; - void* isb_raised; - void* add_ticks; - void* get_ticks_remaining; - } prelude_info; }; } // namespace Dynarmic::Backend::Arm64 diff --git a/src/dynarmic/backend/arm64/a64_address_space.cpp b/src/dynarmic/backend/arm64/a64_address_space.cpp index 3bb2b7cf..529ac245 100644 --- a/src/dynarmic/backend/arm64/a64_address_space.cpp +++ b/src/dynarmic/backend/arm64/a64_address_space.cpp @@ -14,6 +14,7 @@ #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/frontend/A64/a64_location_descriptor.h" #include "dynarmic/frontend/A64/translate/a64_translate.h" +#include "dynarmic/interface/A64/config.h" #include "dynarmic/interface/exclusive_monitor.h" #include "dynarmic/ir/opt/passes.h" @@ -96,8 +97,6 @@ static void* EmitExclusiveWriteCallTrampoline(oaknut::CodeGenerator& code, const return target; } -/* =========================== 128-bit versions =========================== */ - static void* EmitRead128CallTrampoline(oaknut::CodeGenerator& code, A64::UserCallbacks* this_) { using namespace oaknut::util; @@ -214,9 +213,8 @@ static void* EmitExclusiveWrite128CallTrampoline(oaknut::CodeGenerator& code, co } A64AddressSpace::A64AddressSpace(const A64::UserConfig& conf) - : conf(conf) - , mem(conf.code_cache_size) - , code(mem.ptr()) { + : AddressSpace(conf.code_cache_size) + , conf(conf) { EmitPrelude(); } @@ -242,33 +240,6 @@ IR::Block A64AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const { return ir_block; } -CodePtr A64AddressSpace::Get(IR::LocationDescriptor descriptor) { - if (const auto iter = block_entries.find(descriptor.Value()); iter != block_entries.end()) { - return iter->second; - } - return nullptr; -} - -CodePtr A64AddressSpace::GetOrEmit(IR::LocationDescriptor descriptor) { - if (CodePtr block_entry = Get(descriptor)) { - return block_entry; - } - - IR::Block ir_block = GenerateIR(descriptor); - const EmittedBlockInfo block_info = Emit(std::move(ir_block)); - - block_infos.insert_or_assign(descriptor.Value(), block_info); - block_entries.insert_or_assign(descriptor.Value(), block_info.entry_point); - return block_info.entry_point; -} - -void A64AddressSpace::ClearCache() { - block_entries.clear(); - block_infos.clear(); - block_references.clear(); - code.set_ptr(prelude_info.end_of_prelude); -} - void A64AddressSpace::EmitPrelude() { using namespace oaknut::util; @@ -421,18 +392,8 @@ void A64AddressSpace::EmitPrelude() { mem.protect(); } -size_t A64AddressSpace::GetRemainingSize() { - return conf.code_cache_size - (code.ptr() - reinterpret_cast(mem.ptr())); -} - -EmittedBlockInfo A64AddressSpace::Emit(IR::Block block) { - if (GetRemainingSize() < 1024 * 1024) { - ClearCache(); - } - - mem.unprotect(); - - const EmitConfig emit_conf{ +EmitConfig A64AddressSpace::GetEmitConfig() { + return EmitConfig{ .optimizations = conf.unsafe_optimizations ? conf.optimizations : conf.optimizations & all_safe_optimizations, .hook_isb = conf.hook_isb, @@ -458,153 +419,6 @@ EmittedBlockInfo A64AddressSpace::Emit(IR::Block block) { .coprocessors{}, }; - EmittedBlockInfo block_info = EmitArm64(code, std::move(block), emit_conf); - - Link(block.Location(), block_info); - - mem.invalidate(reinterpret_cast(block_info.entry_point), block_info.size); - - RelinkForDescriptor(block.Location()); - - mem.protect(); - - return block_info; -} - -static void LinkBlockLinks(const CodePtr entry_point, const CodePtr target_ptr, const std::vector& block_relocations_list) { - using namespace oaknut; - using namespace oaknut::util; - - for (auto [ptr_offset] : block_relocations_list) { - CodeGenerator c{reinterpret_cast(entry_point + ptr_offset)}; - - if (target_ptr) { - c.B((void*)target_ptr); - } else { - c.NOP(); - } - } -} - -void A64AddressSpace::Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block_info) { - using namespace oaknut; - using namespace oaknut::util; - - for (auto [ptr_offset, target] : block_info.relocations) { - CodeGenerator c{reinterpret_cast(block_info.entry_point + ptr_offset)}; - - switch (target) { - case LinkTarget::ReturnToDispatcher: - c.B(prelude_info.return_to_dispatcher); - break; - case LinkTarget::ReturnFromRunCode: - c.B(prelude_info.return_from_run_code); - break; - case LinkTarget::ReadMemory8: - c.BL(prelude_info.read_memory_8); - break; - case LinkTarget::ReadMemory16: - c.BL(prelude_info.read_memory_16); - break; - case LinkTarget::ReadMemory32: - c.BL(prelude_info.read_memory_32); - break; - case LinkTarget::ReadMemory64: - c.BL(prelude_info.read_memory_64); - break; - case LinkTarget::ReadMemory128: - c.BL(prelude_info.read_memory_128); - break; - case LinkTarget::ExclusiveReadMemory8: - c.BL(prelude_info.exclusive_read_memory_8); - break; - case LinkTarget::ExclusiveReadMemory16: - c.BL(prelude_info.exclusive_read_memory_16); - break; - case LinkTarget::ExclusiveReadMemory32: - c.BL(prelude_info.exclusive_read_memory_32); - break; - case LinkTarget::ExclusiveReadMemory64: - c.BL(prelude_info.exclusive_read_memory_64); - break; - case LinkTarget::ExclusiveReadMemory128: - c.BL(prelude_info.exclusive_read_memory_128); - break; - case LinkTarget::WriteMemory8: - c.BL(prelude_info.write_memory_8); - break; - case LinkTarget::WriteMemory16: - c.BL(prelude_info.write_memory_16); - break; - case LinkTarget::WriteMemory32: - c.BL(prelude_info.write_memory_32); - break; - case LinkTarget::WriteMemory64: - c.BL(prelude_info.write_memory_64); - break; - case LinkTarget::WriteMemory128: - c.BL(prelude_info.write_memory_128); - break; - case LinkTarget::ExclusiveWriteMemory8: - c.BL(prelude_info.exclusive_write_memory_8); - break; - case LinkTarget::ExclusiveWriteMemory16: - c.BL(prelude_info.exclusive_write_memory_16); - break; - case LinkTarget::ExclusiveWriteMemory32: - c.BL(prelude_info.exclusive_write_memory_32); - break; - case LinkTarget::ExclusiveWriteMemory64: - c.BL(prelude_info.exclusive_write_memory_64); - break; - case LinkTarget::ExclusiveWriteMemory128: - c.BL(prelude_info.exclusive_write_memory_128); - break; - case LinkTarget::CallSVC: - c.BL(prelude_info.call_svc); - break; - case LinkTarget::ExceptionRaised: - c.BL(prelude_info.exception_raised); - break; - case LinkTarget::InstructionSynchronizationBarrierRaised: - c.BL(prelude_info.isb_raised); - break; - case LinkTarget::InstructionCacheOperationRaised: - c.BL(prelude_info.ic_raised); - break; - case LinkTarget::DataCacheOperationRaised: - c.BL(prelude_info.dc_raised); - break; - case LinkTarget::GetCNTPCT: - c.BL(prelude_info.get_cntpct); - break; - case LinkTarget::AddTicks: - c.BL(prelude_info.add_ticks); - break; - case LinkTarget::GetTicksRemaining: - c.BL(prelude_info.get_ticks_remaining); - break; - default: - ASSERT_FALSE("Invalid relocation target"); - } - } - - for (auto [target_descriptor, list] : block_info.block_relocations) { - block_references[target_descriptor.Value()].emplace(block_descriptor.Value()); - LinkBlockLinks(block_info.entry_point, Get(target_descriptor), list); - } -} - -void A64AddressSpace::RelinkForDescriptor(IR::LocationDescriptor target_descriptor) { - for (auto block_descriptor : block_references[target_descriptor.Value()]) { - if (auto iter = block_infos.find(block_descriptor); iter != block_infos.end()) { - const EmittedBlockInfo& block_info = iter->second; - - LinkBlockLinks(block_info.entry_point, Get(target_descriptor), block_infos[block_descriptor].block_relocations[target_descriptor]); - - mem.invalidate(reinterpret_cast(block_info.entry_point), block_info.size); - } - } } } // namespace Dynarmic::Backend::Arm64 diff --git a/src/dynarmic/backend/arm64/a64_address_space.h b/src/dynarmic/backend/arm64/a64_address_space.h index 9ae78ad8..2eadf953 100644 --- a/src/dynarmic/backend/arm64/a64_address_space.h +++ b/src/dynarmic/backend/arm64/a64_address_space.h @@ -5,91 +5,24 @@ #pragma once -#include -#include -#include -#include -#include - -#include "dynarmic/backend/arm64/emit_arm64.h" +#include "dynarmic/backend/arm64/address_space.h" #include "dynarmic/interface/A64/config.h" -#include "dynarmic/interface/halt_reason.h" -#include "dynarmic/ir/basic_block.h" -#include "dynarmic/ir/location_descriptor.h" namespace Dynarmic::Backend::Arm64 { -struct A64JitState; - -class A64AddressSpace final { +class A64AddressSpace final : public AddressSpace { public: explicit A64AddressSpace(const A64::UserConfig& conf); - IR::Block GenerateIR(IR::LocationDescriptor) const; + IR::Block GenerateIR(IR::LocationDescriptor) const override; - CodePtr Get(IR::LocationDescriptor descriptor); - - CodePtr GetOrEmit(IR::LocationDescriptor descriptor); - - void ClearCache(); - -private: +protected: friend class A64Core; void EmitPrelude(); - - size_t GetRemainingSize(); - EmittedBlockInfo Emit(IR::Block ir_block); - void Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block); - void RelinkForDescriptor(IR::LocationDescriptor target_descriptor); + EmitConfig GetEmitConfig() override; const A64::UserConfig conf; - - oaknut::CodeBlock mem; - oaknut::CodeGenerator code; - - tsl::robin_map block_entries; - tsl::robin_map block_infos; - tsl::robin_map> block_references; - - struct PreludeInfo { - u32* end_of_prelude; - - using RunCodeFuncType = HaltReason (*)(CodePtr entry_point, A64JitState* context, volatile u32* halt_reason); - RunCodeFuncType run_code; - RunCodeFuncType step_code; - void* return_to_dispatcher; - void* return_from_run_code; - - void* read_memory_8; - void* read_memory_16; - void* read_memory_32; - void* read_memory_64; - void* read_memory_128; - void* exclusive_read_memory_8; - void* exclusive_read_memory_16; - void* exclusive_read_memory_32; - void* exclusive_read_memory_64; - void* exclusive_read_memory_128; - void* write_memory_8; - void* write_memory_16; - void* write_memory_32; - void* write_memory_64; - void* write_memory_128; - void* exclusive_write_memory_8; - void* exclusive_write_memory_16; - void* exclusive_write_memory_32; - void* exclusive_write_memory_64; - void* exclusive_write_memory_128; - void* call_svc; - void* exception_raised; - void* dc_raised; - void* ic_raised; - void* isb_raised; - void* get_cntpct; - void* add_ticks; - void* get_ticks_remaining; - } prelude_info; }; } // namespace Dynarmic::Backend::Arm64 diff --git a/src/dynarmic/backend/arm64/address_space.cpp b/src/dynarmic/backend/arm64/address_space.cpp new file mode 100644 index 00000000..3aeaa453 --- /dev/null +++ b/src/dynarmic/backend/arm64/address_space.cpp @@ -0,0 +1,213 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2022 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#include "dynarmic/backend/arm64/a64_address_space.h" +#include "dynarmic/backend/arm64/a64_jitstate.h" +#include "dynarmic/backend/arm64/abi.h" +#include "dynarmic/backend/arm64/devirtualize.h" +#include "dynarmic/backend/arm64/emit_arm64.h" +#include "dynarmic/backend/arm64/stack_layout.h" +#include "dynarmic/common/cast_util.h" +#include "dynarmic/common/fp/fpcr.h" +#include "dynarmic/interface/exclusive_monitor.h" +#include "dynarmic/ir/opt/passes.h" + +namespace Dynarmic::Backend::Arm64 { + +AddressSpace::AddressSpace(size_t code_cache_size) + : code_cache_size(code_cache_size) + , mem(code_cache_size) + , code(mem.ptr()) {} + +AddressSpace::~AddressSpace() = default; + +CodePtr AddressSpace::Get(IR::LocationDescriptor descriptor) { + if (const auto iter = block_entries.find(descriptor.Value()); iter != block_entries.end()) { + return iter->second; + } + return nullptr; +} + +CodePtr AddressSpace::GetOrEmit(IR::LocationDescriptor descriptor) { + if (CodePtr block_entry = Get(descriptor)) { + return block_entry; + } + + IR::Block ir_block = GenerateIR(descriptor); + const EmittedBlockInfo block_info = Emit(std::move(ir_block)); + + block_infos.insert_or_assign(descriptor.Value(), block_info); + block_entries.insert_or_assign(descriptor.Value(), block_info.entry_point); + return block_info.entry_point; +} + +void AddressSpace::ClearCache() { + block_entries.clear(); + block_infos.clear(); + block_references.clear(); + code.set_ptr(prelude_info.end_of_prelude); +} + +size_t AddressSpace::GetRemainingSize() { + return code_cache_size - (code.ptr() - reinterpret_cast(mem.ptr())); +} + +EmittedBlockInfo AddressSpace::Emit(IR::Block block) { + if (GetRemainingSize() < 1024 * 1024) { + ClearCache(); + } + + mem.unprotect(); + + EmittedBlockInfo block_info = EmitArm64(code, std::move(block), GetEmitConfig()); + + Link(block.Location(), block_info); + + mem.invalidate(reinterpret_cast(block_info.entry_point), block_info.size); + + RelinkForDescriptor(block.Location()); + + mem.protect(); + + return block_info; +} + +static void LinkBlockLinks(const CodePtr entry_point, const CodePtr target_ptr, const std::vector& block_relocations_list) { + using namespace oaknut; + using namespace oaknut::util; + + for (auto [ptr_offset] : block_relocations_list) { + CodeGenerator c{reinterpret_cast(entry_point + ptr_offset)}; + + if (target_ptr) { + c.B((void*)target_ptr); + } else { + c.NOP(); + } + } +} + +void AddressSpace::Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block_info) { + using namespace oaknut; + using namespace oaknut::util; + + for (auto [ptr_offset, target] : block_info.relocations) { + CodeGenerator c{reinterpret_cast(block_info.entry_point + ptr_offset)}; + + switch (target) { + case LinkTarget::ReturnToDispatcher: + c.B(prelude_info.return_to_dispatcher); + break; + case LinkTarget::ReturnFromRunCode: + c.B(prelude_info.return_from_run_code); + break; + case LinkTarget::ReadMemory8: + c.BL(prelude_info.read_memory_8); + break; + case LinkTarget::ReadMemory16: + c.BL(prelude_info.read_memory_16); + break; + case LinkTarget::ReadMemory32: + c.BL(prelude_info.read_memory_32); + break; + case LinkTarget::ReadMemory64: + c.BL(prelude_info.read_memory_64); + break; + case LinkTarget::ReadMemory128: + c.BL(prelude_info.read_memory_128); + break; + case LinkTarget::ExclusiveReadMemory8: + c.BL(prelude_info.exclusive_read_memory_8); + break; + case LinkTarget::ExclusiveReadMemory16: + c.BL(prelude_info.exclusive_read_memory_16); + break; + case LinkTarget::ExclusiveReadMemory32: + c.BL(prelude_info.exclusive_read_memory_32); + break; + case LinkTarget::ExclusiveReadMemory64: + c.BL(prelude_info.exclusive_read_memory_64); + break; + case LinkTarget::ExclusiveReadMemory128: + c.BL(prelude_info.exclusive_read_memory_128); + break; + case LinkTarget::WriteMemory8: + c.BL(prelude_info.write_memory_8); + break; + case LinkTarget::WriteMemory16: + c.BL(prelude_info.write_memory_16); + break; + case LinkTarget::WriteMemory32: + c.BL(prelude_info.write_memory_32); + break; + case LinkTarget::WriteMemory64: + c.BL(prelude_info.write_memory_64); + break; + case LinkTarget::WriteMemory128: + c.BL(prelude_info.write_memory_128); + break; + case LinkTarget::ExclusiveWriteMemory8: + c.BL(prelude_info.exclusive_write_memory_8); + break; + case LinkTarget::ExclusiveWriteMemory16: + c.BL(prelude_info.exclusive_write_memory_16); + break; + case LinkTarget::ExclusiveWriteMemory32: + c.BL(prelude_info.exclusive_write_memory_32); + break; + case LinkTarget::ExclusiveWriteMemory64: + c.BL(prelude_info.exclusive_write_memory_64); + break; + case LinkTarget::ExclusiveWriteMemory128: + c.BL(prelude_info.exclusive_write_memory_128); + break; + case LinkTarget::CallSVC: + c.BL(prelude_info.call_svc); + break; + case LinkTarget::ExceptionRaised: + c.BL(prelude_info.exception_raised); + break; + case LinkTarget::InstructionSynchronizationBarrierRaised: + c.BL(prelude_info.isb_raised); + break; + case LinkTarget::InstructionCacheOperationRaised: + c.BL(prelude_info.ic_raised); + break; + case LinkTarget::DataCacheOperationRaised: + c.BL(prelude_info.dc_raised); + break; + case LinkTarget::GetCNTPCT: + c.BL(prelude_info.get_cntpct); + break; + case LinkTarget::AddTicks: + c.BL(prelude_info.add_ticks); + break; + case LinkTarget::GetTicksRemaining: + c.BL(prelude_info.get_ticks_remaining); + break; + default: + ASSERT_FALSE("Invalid relocation target"); + } + } + + for (auto [target_descriptor, list] : block_info.block_relocations) { + block_references[target_descriptor.Value()].emplace(block_descriptor.Value()); + LinkBlockLinks(block_info.entry_point, Get(target_descriptor), list); + } +} + +void AddressSpace::RelinkForDescriptor(IR::LocationDescriptor target_descriptor) { + for (auto block_descriptor : block_references[target_descriptor.Value()]) { + if (auto iter = block_infos.find(block_descriptor); iter != block_infos.end()) { + const EmittedBlockInfo& block_info = iter->second; + + LinkBlockLinks(block_info.entry_point, Get(target_descriptor), block_infos[block_descriptor].block_relocations[target_descriptor]); + + mem.invalidate(reinterpret_cast(block_info.entry_point), block_info.size); + } + } +} + +} // namespace Dynarmic::Backend::Arm64 diff --git a/src/dynarmic/backend/arm64/address_space.h b/src/dynarmic/backend/arm64/address_space.h new file mode 100644 index 00000000..3544174c --- /dev/null +++ b/src/dynarmic/backend/arm64/address_space.h @@ -0,0 +1,92 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2022 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "dynarmic/backend/arm64/emit_arm64.h" +#include "dynarmic/interface/halt_reason.h" +#include "dynarmic/ir/basic_block.h" +#include "dynarmic/ir/location_descriptor.h" + +namespace Dynarmic::Backend::Arm64 { + +class AddressSpace { +public: + explicit AddressSpace(size_t code_cache_size); + virtual ~AddressSpace(); + + virtual IR::Block GenerateIR(IR::LocationDescriptor) const = 0; + + CodePtr Get(IR::LocationDescriptor descriptor); + + CodePtr GetOrEmit(IR::LocationDescriptor descriptor); + + void ClearCache(); + +protected: + virtual EmitConfig GetEmitConfig() = 0; + + size_t GetRemainingSize(); + EmittedBlockInfo Emit(IR::Block ir_block); + void Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block); + void RelinkForDescriptor(IR::LocationDescriptor target_descriptor); + + const size_t code_cache_size; + oaknut::CodeBlock mem; + oaknut::CodeGenerator code; + + tsl::robin_map block_entries; + tsl::robin_map block_infos; + tsl::robin_map> block_references; + + struct PreludeInfo { + u32* end_of_prelude; + + using RunCodeFuncType = HaltReason (*)(CodePtr entry_point, void* jit_state, volatile u32* halt_reason); + RunCodeFuncType run_code; + RunCodeFuncType step_code; + void* return_to_dispatcher; + void* return_from_run_code; + + void* read_memory_8; + void* read_memory_16; + void* read_memory_32; + void* read_memory_64; + void* read_memory_128; + void* exclusive_read_memory_8; + void* exclusive_read_memory_16; + void* exclusive_read_memory_32; + void* exclusive_read_memory_64; + void* exclusive_read_memory_128; + void* write_memory_8; + void* write_memory_16; + void* write_memory_32; + void* write_memory_64; + void* write_memory_128; + void* exclusive_write_memory_8; + void* exclusive_write_memory_16; + void* exclusive_write_memory_32; + void* exclusive_write_memory_64; + void* exclusive_write_memory_128; + + void* call_svc; + void* exception_raised; + void* dc_raised; + void* ic_raised; + void* isb_raised; + + void* get_cntpct; + void* add_ticks; + void* get_ticks_remaining; + } prelude_info; +}; + +} // namespace Dynarmic::Backend::Arm64