From b3c8997829ed986c948d195bc1e7c8f66c42755e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 17 Nov 2020 19:58:41 -0500 Subject: page_table: Allow page tables to be moved Makes page tables and virtual buffers able to be moved, but not copied, making the interface more flexible. Previously, with the destructor specified, but no move assignment or constructor specified, they wouldn't be implicitly generated. --- src/common/virtual_buffer.h | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'src/common/virtual_buffer.h') diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index 125cb42f0..363913d45 100644 --- a/src/common/virtual_buffer.h +++ b/src/common/virtual_buffer.h @@ -4,25 +4,38 @@ #pragma once -#include "common/common_funcs.h" +#include namespace Common { -void* AllocateMemoryPages(std::size_t size); -void FreeMemoryPages(void* base, std::size_t size); +void* AllocateMemoryPages(std::size_t size) noexcept; +void FreeMemoryPages(void* base, std::size_t size) noexcept; template -class VirtualBuffer final : NonCopyable { +class VirtualBuffer final { public: constexpr VirtualBuffer() = default; explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} { base_ptr = reinterpret_cast(AllocateMemoryPages(alloc_size)); } - ~VirtualBuffer() { + ~VirtualBuffer() noexcept { FreeMemoryPages(base_ptr, alloc_size); } + VirtualBuffer(const VirtualBuffer&) = delete; + VirtualBuffer& operator=(const VirtualBuffer&) = delete; + + VirtualBuffer(VirtualBuffer&& other) noexcept + : alloc_size{std::exchange(other.alloc_size, 0)}, base_ptr{std::exchange(other.base_ptr), + nullptr} {} + + VirtualBuffer& operator=(VirtualBuffer&& other) noexcept { + alloc_size = std::exchange(other.alloc_size, 0); + base_ptr = std::exchange(other.base_ptr, nullptr); + return *this; + } + void resize(std::size_t count) { FreeMemoryPages(base_ptr, alloc_size); -- cgit v1.2.3 From 0ca91ced2dab3654e78e4c465506d7baad3cbeeb Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 17 Nov 2020 20:09:55 -0500 Subject: virtual_buffer: Add compile-time type-safety guarantees with VirtualBuffer VirtualBuffer makes use of VirtualAlloc (on Windows) and mmap() (on other platforms). Neither of these ensure that non-trivial objects are properly constructed in the allocated memory. To prevent potential undefined behavior occurring due to that, we can add a static assert to loudly complain about cases where that is done. --- src/common/virtual_buffer.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/common/virtual_buffer.h') diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index 363913d45..078e61c77 100644 --- a/src/common/virtual_buffer.h +++ b/src/common/virtual_buffer.h @@ -4,6 +4,7 @@ #pragma once +#include #include namespace Common { @@ -14,6 +15,11 @@ void FreeMemoryPages(void* base, std::size_t size) noexcept; template class VirtualBuffer final { public: + static_assert( + std::is_trivially_constructible_v, + "T must be trivially constructible, as non-trivial constructors will not be executed " + "with the current allocator"); + constexpr VirtualBuffer() = default; explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} { base_ptr = reinterpret_cast(AllocateMemoryPages(alloc_size)); -- cgit v1.2.3 From 412044960a39180bc9990f6b35e1872c6a69591b Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 19 Nov 2020 07:54:00 -0500 Subject: virtual_buffer: Do nothing on resize() calls with same sizes Prevents us from churning memory by freeing and reallocating a memory block that would have already been adequate as is. --- src/common/virtual_buffer.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/common/virtual_buffer.h') diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index 078e61c77..91d430036 100644 --- a/src/common/virtual_buffer.h +++ b/src/common/virtual_buffer.h @@ -43,9 +43,14 @@ public: } void resize(std::size_t count) { + const auto new_size = count * sizeof(T); + if (new_size == alloc_size) { + return; + } + FreeMemoryPages(base_ptr, alloc_size); - alloc_size = count * sizeof(T); + alloc_size = new_size; base_ptr = reinterpret_cast(AllocateMemoryPages(alloc_size)); } -- cgit v1.2.3 From b3587102d160fb74a12935a79f06ee8a12712f12 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Tue, 29 Dec 2020 21:16:57 -0300 Subject: core/memory: Read and write page table atomically Squash attributes into the pointer's integer, making them an uintptr_t pair containing 2 bits at the bottom and then the pointer. These bits are currently unused thanks to alignment requirements. Configure Dynarmic to mask out these bits on pointer reads. While we are at it, remove some unused attributes carried over from Citra. Read/Write and other hot functions use a two step unpacking process that is less readable to stop MSVC from emitting an extra AND instruction in the hot path: mov rdi,rcx shr rdx,0Ch mov r8,qword ptr [rax+8] mov rax,qword ptr [r8+rdx*8] mov rdx,rax -and al,3 and rdx,0FFFFFFFFFFFFFFFCh je Core::Memory::Memory::Impl::Read mov rax,qword ptr [vaddr] movzx eax,byte ptr [rdx+rax] --- src/common/virtual_buffer.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/common/virtual_buffer.h') diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index 91d430036..fb1a6f81f 100644 --- a/src/common/virtual_buffer.h +++ b/src/common/virtual_buffer.h @@ -15,10 +15,12 @@ void FreeMemoryPages(void* base, std::size_t size) noexcept; template class VirtualBuffer final { public: - static_assert( - std::is_trivially_constructible_v, - "T must be trivially constructible, as non-trivial constructors will not be executed " - "with the current allocator"); + // TODO: Uncomment this and change Common::PageTable::PageInfo to be trivially constructible + // using std::atomic_ref once libc++ has support for it + // static_assert( + // std::is_trivially_constructible_v, + // "T must be trivially constructible, as non-trivial constructors will not be executed " + // "with the current allocator"); constexpr VirtualBuffer() = default; explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} { -- cgit v1.2.3