diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 99b4f029a8..f77048c734 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -1058,6 +1058,9 @@ namespace vm } } + // Mapped regions: addr -> shm handle + constexpr auto block_map = &auto_typemap::get>>>; + bool block_t::try_alloc(u32 addr, u8 flags, u32 size, std::shared_ptr&& shm) { // Check if memory area is already mapped @@ -1082,7 +1085,9 @@ namespace vm // Map "real" memory pages; provide a function to search for mirrors with private member access _page_map(page_addr, flags, page_size, shm.get(), [](vm::block_t* _this, utils::shm* shm) { - decltype(m_map)::value_type* result = nullptr; + auto& map = (_this->m.*block_map)(); + + std::remove_reference_t::value_type* result = nullptr; // Check eligibility if (!_this || !(SYS_MEMORY_PAGE_SIZE_MASK & _this->flags) || _this->addr < 0x20000000 || _this->addr >= 0xC0000000) @@ -1090,7 +1095,7 @@ namespace vm return result; } - for (auto& pp : _this->m_map) + for (auto& pp : map) { if (pp.second.second.get() == shm) { @@ -1125,7 +1130,7 @@ namespace vm } // Add entry - m_map[addr] = std::make_pair(size, std::move(shm)); + (m.*block_map)()[addr] = std::make_pair(size, std::move(shm)); return true; } @@ -1147,6 +1152,7 @@ namespace vm block_t::~block_t() { + auto& m_map = (m.*block_map)(); { vm::writer_lock lock(0); @@ -1285,6 +1291,7 @@ namespace vm u32 block_t::dealloc(u32 addr, const std::shared_ptr* src) { + auto& m_map = (m.*block_map)(); { vm::writer_lock lock(0); @@ -1334,6 +1341,8 @@ namespace vm return {addr, nullptr}; } + auto& m_map = (m.*block_map)(); + vm::reader_lock lock; const auto upper = m_map.upper_bound(addr); @@ -1370,7 +1379,7 @@ namespace vm { u32 result = 0; - for (auto& entry : m_map) + for (auto& entry : (m.*block_map)()) { result += entry.second.first - (flags & 0x10 ? 0x2000 : 0); } diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 1ce075ac83..b8b91a7e2e 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -1,9 +1,9 @@ #pragma once -#include #include #include "util/types.hpp" #include "util/atomic.hpp" +#include "util/auto_typemap.hpp" #include "Utilities/StrFmt.h" #include "util/to_endian.hpp" @@ -95,8 +95,7 @@ namespace vm // Object that handles memory allocations inside specific constant bounds ("location") class block_t final { - // Mapped regions: addr -> shm handle - std::map>> m_map; + auto_typemap m; // Common mapped region for special cases std::shared_ptr m_common; diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 14251f20a7..64b3a803f1 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -495,6 +495,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index ebb8cdbae6..5f768d7cd3 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1822,6 +1822,9 @@ Utilities + + Utilities + Utilities diff --git a/rpcs3/stdafx.h b/rpcs3/stdafx.h index d3894ba8f7..f0e4165581 100644 --- a/rpcs3/stdafx.h +++ b/rpcs3/stdafx.h @@ -7,6 +7,9 @@ #include "Utilities/File.h" #include "util/logs.hpp" #include "util/shared_ptr.hpp" +#include "util/typeindices.hpp" +#include "util/fixed_typemap.hpp" +#include "util/auto_typemap.hpp" #include #include diff --git a/rpcs3/util/auto_typemap.hpp b/rpcs3/util/auto_typemap.hpp new file mode 100644 index 0000000000..08a9783b3e --- /dev/null +++ b/rpcs3/util/auto_typemap.hpp @@ -0,0 +1,175 @@ +#pragma once + +#include "util/typeindices.hpp" + +#include +#include + +namespace stx +{ + // Simplified typemap with exactly one object of each used type, non-moveable. + template + class auto_typemap + { + // Save default constructor and destructor + struct typeinfo + { + void(*create)(void*& ptr, auto_typemap&) noexcept; + void(*destroy)(void* ptr) noexcept; + + template + static void call_ctor(void*& ptr, auto_typemap& _this) noexcept + { + // Don't overwrite if already exists + if (!ptr) + { + // Allow passing reference to "this" + if constexpr (std::is_constructible_v) + { + ptr = new T(_this); + return; + } + + // Call default constructor only if available + if constexpr (std::is_default_constructible_v) + { + ptr = new T(); + return; + } + } + } + + template + static void call_dtor(void* ptr) noexcept + { + delete static_cast(ptr); + } + + template + static typeinfo make_typeinfo() + { + typeinfo r; + r.create = &call_ctor; + r.destroy = &call_dtor; + return r; + } + }; + + // Raw pointers to existing objects (may be nullptr) + void** m_list; + + // Creation order for each object (used to reverse destruction order) + void** m_order; + + // Helper for destroying in reverse order + const typeinfo** m_info; + + public: + auto_typemap() noexcept + : m_list(new void*[stx::typelist().count()]{}) + , m_order(new void*[stx::typelist().count()]) + , m_info(new const typeinfo*[stx::typelist().count()]) + { + for (const auto& type : stx::typelist()) + { + const unsigned id = type.index(); + + type.create(m_list[id], *this); + + // Allocate initialization order id + if (m_list[id]) + { + *m_order++ = m_list[id]; + *m_info++ = &type; + } + } + } + + auto_typemap(const auto_typemap&) = delete; + + auto_typemap& operator=(const auto_typemap&) = delete; + + ~auto_typemap() + { + // Get actual number of created objects + unsigned _max = 0; + + for (const auto& type : stx::typelist()) + { + if (m_list[type.index()]) + { + // Skip object if not created + _max++; + } + } + + // Destroy objects in reverse order + for (; _max; _max--) + { + (*--m_info)->destroy(*--m_order); + } + + // Pointers should be restored to their positions + delete[] m_info; + delete[] m_order; + delete[] m_list; + } + + // Check if object is not initialized but shall be initialized first (to use in initializing other objects) + template + void need() noexcept + { + if (!m_list[stx::typeindex>()]) + { + if constexpr (std::is_constructible_v) + { + init(*this); + return; + } + + if constexpr (std::is_default_constructible_v) + { + init(); + return; + } + } + } + + // Explicitly initialize object of type T possibly with dynamic type As and arguments + template + As* init(Args&&... args) noexcept + { + auto& ptr = m_list[stx::typeindex>()]; + + if (ptr) + { + // Already exists, recreation is not supported (may be added later) + return nullptr; + } + + As* obj = new std::decay_t(std::forward(args)...); + *m_order++ = obj; + *m_info++ = &stx::typedata>(); + ptr = static_cast(obj); + return obj; + } + + // CTAD adaptor for init (see init description), accepts template not type + template