From 81f729226934078732e9994116ceb29adf52ea68 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 17 Nov 2020 19:43:24 -0500 Subject: [PATCH 1/4] page_table: Remove unnecessary header inclusions Prevents indirect inclusions for these headers. --- src/common/page_table.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/common/page_table.h b/src/common/page_table.h index cf5eed780d..9908947ac6 100644 --- a/src/common/page_table.h +++ b/src/common/page_table.h @@ -4,10 +4,6 @@ #pragma once -#include - -#include - #include "common/common_types.h" #include "common/memory_hook.h" #include "common/virtual_buffer.h" From 60b72b1debde587546f6f0b03bcef19c185cb091 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 17 Nov 2020 19:45:17 -0500 Subject: [PATCH 2/4] page_table: Add missing doxygen parameters to Resize() Resolves two -Wdocumentation warnings. --- src/common/page_table.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/page_table.h b/src/common/page_table.h index 9908947ac6..a5be7a668a 100644 --- a/src/common/page_table.h +++ b/src/common/page_table.h @@ -54,6 +54,8 @@ struct PageTable { * a given address space. * * @param address_space_width_in_bits The address size width in bits. + * @param page_size_in_bits The page size in bits. + * @param has_attribute Whether or not this page has any backing attributes. */ void Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits, bool has_attribute); From b9b02276ebd81b0579784c97006ce9d9cc18fb06 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 17 Nov 2020 19:58:41 -0500 Subject: [PATCH 3/4] 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/page_table.cpp | 2 +- src/common/page_table.h | 10 +++++++++- src/common/virtual_buffer.cpp | 4 ++-- src/common/virtual_buffer.h | 23 ++++++++++++++++++----- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/common/page_table.cpp b/src/common/page_table.cpp index e5d3090d53..bccea08945 100644 --- a/src/common/page_table.cpp +++ b/src/common/page_table.cpp @@ -8,7 +8,7 @@ namespace Common { PageTable::PageTable() = default; -PageTable::~PageTable() = default; +PageTable::~PageTable() noexcept = default; void PageTable::Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits, bool has_attribute) { diff --git a/src/common/page_table.h b/src/common/page_table.h index a5be7a668a..9754fabf91 100644 --- a/src/common/page_table.h +++ b/src/common/page_table.h @@ -4,6 +4,8 @@ #pragma once +#include + #include "common/common_types.h" #include "common/memory_hook.h" #include "common/virtual_buffer.h" @@ -47,7 +49,13 @@ struct SpecialRegion { */ struct PageTable { PageTable(); - ~PageTable(); + ~PageTable() noexcept; + + PageTable(const PageTable&) = delete; + PageTable& operator=(const PageTable&) = delete; + + PageTable(PageTable&&) noexcept = default; + PageTable& operator=(PageTable&&) noexcept = default; /** * Resizes the page table to be able to accomodate enough pages within diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index b009cb5007..e3ca292581 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -13,7 +13,7 @@ namespace Common { -void* AllocateMemoryPages(std::size_t size) { +void* AllocateMemoryPages(std::size_t size) noexcept { #ifdef _WIN32 void* base{VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE)}; #else @@ -29,7 +29,7 @@ void* AllocateMemoryPages(std::size_t size) { return base; } -void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) { +void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept { if (!base) { return; } diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index 125cb42f09..363913d452 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); From d02005bbe9f97bbad973d47a91acee9b3e5f8c3f Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 17 Nov 2020 20:09:55 -0500 Subject: [PATCH 4/4] 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(+) diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index 363913d452..078e61c775 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));