diff --git a/src/dynarmic/backend/arm64/address_space.cpp b/src/dynarmic/backend/arm64/address_space.cpp index 00f2fcd3..ce6729bb 100644 --- a/src/dynarmic/backend/arm64/address_space.cpp +++ b/src/dynarmic/backend/arm64/address_space.cpp @@ -46,13 +46,32 @@ CodePtr AddressSpace::GetOrEmit(IR::LocationDescriptor descriptor) { 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); - reverse_block_entries.insert_or_assign(block_info.entry_point, descriptor.Value()); return block_info.entry_point; } +void AddressSpace::InvalidateBasicBlocks(const tsl::robin_set& descriptors) { + mem.unprotect(); + + for (const auto& descriptor : descriptors) { + const auto iter = block_infos.find(descriptor.Value()); + if (iter == block_infos.end()) { + continue; + } + + // Unlink before removal because InvalidateBasicBlocks can be called within a fastmem callback, + // and the currently executing block may have references to itself which need to be unlinked. + RelinkForDescriptor(descriptor, nullptr); + + const auto entry_point = iter->second.entry_point; + + block_infos.erase(iter); + block_entries.erase(descriptor.Value()); + reverse_block_entries.erase(entry_point); + } + + mem.protect(); +} + void AddressSpace::ClearCache() { block_entries.clear(); reverse_block_entries.clear(); @@ -74,12 +93,14 @@ EmittedBlockInfo AddressSpace::Emit(IR::Block block) { EmittedBlockInfo block_info = EmitArm64(code, std::move(block), GetEmitConfig()); + block_infos.insert_or_assign(block.Location().Value(), block_info); + block_entries.insert_or_assign(block.Location().Value(), block_info.entry_point); + reverse_block_entries.insert_or_assign(block_info.entry_point, block.Location().Value()); + Link(block.Location(), block_info); + RelinkForDescriptor(block.Location(), block_info.entry_point); mem.invalidate(reinterpret_cast(block_info.entry_point), block_info.size); - - RelinkForDescriptor(block.Location()); - mem.protect(); return block_info; @@ -239,12 +260,14 @@ void AddressSpace::Link(IR::LocationDescriptor block_descriptor, EmittedBlockInf } } -void AddressSpace::RelinkForDescriptor(IR::LocationDescriptor target_descriptor) { +void AddressSpace::RelinkForDescriptor(IR::LocationDescriptor target_descriptor, CodePtr target_ptr) { 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; + if (auto block_iter = block_infos.find(block_descriptor); block_iter != block_infos.end()) { + const EmittedBlockInfo& block_info = block_iter->second; - LinkBlockLinks(block_info.entry_point, Get(target_descriptor), block_infos[block_descriptor].block_relocations[target_descriptor]); + if (auto relocation_iter = block_info.block_relocations.find(target_descriptor); relocation_iter != block_info.block_relocations.end()) { + LinkBlockLinks(block_info.entry_point, target_ptr, relocation_iter->second); + } mem.invalidate(reinterpret_cast(block_info.entry_point), block_info.size); } diff --git a/src/dynarmic/backend/arm64/address_space.h b/src/dynarmic/backend/arm64/address_space.h index 65e7ec98..49b43889 100644 --- a/src/dynarmic/backend/arm64/address_space.h +++ b/src/dynarmic/backend/arm64/address_space.h @@ -35,6 +35,8 @@ public: CodePtr GetOrEmit(IR::LocationDescriptor descriptor); + void InvalidateBasicBlocks(const tsl::robin_set& descriptors); + void ClearCache(); protected: @@ -43,7 +45,7 @@ protected: size_t GetRemainingSize(); EmittedBlockInfo Emit(IR::Block ir_block); void Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block); - void RelinkForDescriptor(IR::LocationDescriptor target_descriptor); + void RelinkForDescriptor(IR::LocationDescriptor target_descriptor, CodePtr target_ptr); const size_t code_cache_size; oaknut::CodeBlock mem;