chore(feat): Optimize GuestMemory and GuestMemoryScoped classes for performance and maintainability

- Refactored `GuestMemory` and `GuestMemoryScoped` to remove redundant code and improve clarity.
- Introduced `allocateBackupOrCopy` helper function to handle memory backup or copy operations.
- Moved data writing logic into a dedicated `writeData` function in `GuestMemoryScoped` to reduce repetition.
- Marked functions `noexcept` where applicable to optimize performance and indicate exception safety.
- Used `constexpr if` to reduce unnecessary runtime checks.
- Improved resource management by adding move semantics for constructors and assignment operators in `GuestMemory`.
- General improvements to code maintainability and efficiency without changing functionality.
This commit is contained in:
Phoenix 2024-09-11 19:23:56 +10:00
parent b9599e203b
commit 25b8a93db0

View File

@ -8,7 +8,6 @@
#include <optional>
#include <span>
#include <vector>
#include "common/assert.h"
#include "common/scratch_buffer.h"
@ -43,72 +42,33 @@ class GuestMemory {
public:
GuestMemory() = delete;
explicit GuestMemory(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
: m_memory{&memory}, m_addr{addr}, m_size{size} {
Common::ScratchBuffer<T>* backup = nullptr) noexcept
: m_memory{&memory}, m_addr{addr}, m_size{size}, m_is_data_copy{false}, m_addr_changed{false} {
static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
backup->resize_destructive(this->size());
m_data_span = *backup;
m_span_valid = true;
m_is_data_copy = true;
} else {
m_data_copy.resize(this->size());
m_data_span = std::span(m_data_copy);
m_span_valid = true;
m_is_data_copy = true;
}
allocateBackupOrCopy(backup);
}
} else if constexpr (FLAGS & GuestMemoryFlags::Read) {
} else {
Read(addr, size, backup);
}
}
~GuestMemory() = default;
GuestMemory(GuestMemory&& rhs) noexcept = default;
GuestMemory& operator=(GuestMemory&& rhs) noexcept = default;
GuestMemory(GuestMemory&& rhs) = default;
GuestMemory& operator=(GuestMemory&& rhs) = default;
T* data() noexcept { return m_data_span.data(); }
const T* data() const noexcept { return m_data_span.data(); }
size_t size() const noexcept { return m_size; }
size_t size_bytes() const noexcept { return this->size() * sizeof(T); }
T* data() noexcept {
return m_data_span.data();
}
T* begin() noexcept { return this->data(); }
const T* begin() const noexcept { return this->data(); }
T* end() noexcept { return this->data() + this->size(); }
const T* end() const noexcept { return this->data() + this->size(); }
const T* data() const noexcept {
return m_data_span.data();
}
size_t size() const noexcept {
return m_size;
}
size_t size_bytes() const noexcept {
return this->size() * sizeof(T);
}
[[nodiscard]] T* begin() noexcept {
return this->data();
}
[[nodiscard]] const T* begin() const noexcept {
return this->data();
}
[[nodiscard]] T* end() noexcept {
return this->data() + this->size();
}
[[nodiscard]] const T* end() const noexcept {
return this->data() + this->size();
}
T& operator[](size_t index) noexcept {
return m_data_span[index];
}
const T& operator[](size_t index) const noexcept {
return m_data_span[index];
}
T& operator[](size_t index) noexcept { return m_data_span[index]; }
const T& operator[](size_t index) const noexcept { return m_data_span[index]; }
void SetAddressAndSize(u64 addr, std::size_t size) noexcept {
m_addr = addr;
@ -116,10 +76,10 @@ public:
m_addr_changed = true;
}
std::span<T> Read(u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr) noexcept {
std::span<T> Read(u64 addr, std::size_t size, Common::ScratchBuffer<T>* backup = nullptr) noexcept {
m_addr = addr;
m_size = size;
if (m_size == 0) {
m_is_data_copy = true;
return {};
@ -130,15 +90,7 @@ public:
m_memory->FlushRegion(m_addr, this->size_bytes());
}
} else {
if (backup) {
backup->resize_destructive(this->size());
m_data_span = *backup;
} else {
m_data_copy.resize(this->size());
m_data_span = std::span(m_data_copy);
}
m_is_data_copy = true;
m_span_valid = true;
allocateBackupOrCopy(backup);
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory->ReadBlock(m_addr, this->data(), this->size_bytes());
} else {
@ -169,12 +121,19 @@ public:
}
protected:
bool IsDataCopy() const noexcept {
return m_is_data_copy;
}
bool IsDataCopy() const noexcept { return m_is_data_copy; }
bool AddressChanged() const noexcept { return m_addr_changed; }
bool AddressChanged() const noexcept {
return m_addr_changed;
void allocateBackupOrCopy(Common::ScratchBuffer<T>* backup) {
if (backup) {
backup->resize_destructive(this->size());
m_data_span = *backup;
} else {
m_data_copy.resize(this->size());
m_data_span = std::span(m_data_copy);
}
m_is_data_copy = true;
m_span_valid = true;
}
M* m_memory;
@ -192,33 +151,34 @@ class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> {
public:
GuestMemoryScoped() = delete;
explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
Common::ScratchBuffer<T>* backup = nullptr) noexcept
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {}
~GuestMemoryScoped() {
~GuestMemoryScoped() noexcept {
if constexpr (FLAGS & GuestMemoryFlags::Write) {
if (this->size() == 0) [[unlikely]] {
if (this->size() == 0 || !this->m_span_valid) [[unlikely]] {
return;
}
if (this->AddressChanged() || this->IsDataCopy()) {
ASSERT(this->m_span_valid);
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
this->m_memory->WriteBlockCached(this->m_addr, this->data(),
this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
this->m_memory->WriteBlock(this->m_addr, this->data(), this->size_bytes());
} else {
this->m_memory->WriteBlockUnsafe(this->m_addr, this->data(),
this->size_bytes());
}
} else if constexpr ((FLAGS & GuestMemoryFlags::Safe) ||
(FLAGS & GuestMemoryFlags::Cached)) {
this->writeData();
} else if constexpr ((FLAGS & GuestMemoryFlags::Safe) || (FLAGS & GuestMemoryFlags::Cached)) {
this->m_memory->InvalidateRegion(this->m_addr, this->size_bytes());
}
}
}
};
} // namespace
} // namespace Core::Memory
private:
void writeData() noexcept {
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
this->m_memory->WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
this->m_memory->WriteBlock(this->m_addr, this->data(), this->size_bytes());
} else {
this->m_memory->WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
}
}
};
} // namespace
} // namespace Core::Memory