mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-06 06:55:09 +00:00
orbis: implement physical memory emulation level & utils improvement
fix blockpool & dmem implementation modernize blockpool & dmem io devices use budgets per allocation add serialization support for MemoryTableWithPayload and AddressRange utils add format support for EnumBitSet util implemented trace formatter per syscall increased allowed reference count for Ref
This commit is contained in:
parent
479b09b2df
commit
d7ad77b406
70 changed files with 4268 additions and 3160 deletions
|
|
@ -20,7 +20,9 @@ Examples:
|
|||
Intersection (&) and symmetric difference (^) is also available.
|
||||
*/
|
||||
|
||||
#include "types.hpp"
|
||||
#include "format-base.hpp"
|
||||
#include "rx/refl.hpp"
|
||||
#include <type_traits>
|
||||
|
||||
namespace rx {
|
||||
template <typename T>
|
||||
|
|
@ -52,8 +54,8 @@ private:
|
|||
: m_data(data) {}
|
||||
|
||||
public:
|
||||
static constexpr usz bitmax = sizeof(T) * 8;
|
||||
static constexpr usz bitsize =
|
||||
static constexpr std::size_t bitmax = sizeof(T) * 8;
|
||||
static constexpr std::size_t bitsize =
|
||||
static_cast<underlying_type>(T::bitset_last) + 1;
|
||||
|
||||
static_assert(std::is_enum_v<T>,
|
||||
|
|
@ -69,7 +71,7 @@ public:
|
|||
<< static_cast<underlying_type>(value);
|
||||
}
|
||||
|
||||
EnumBitSet() = default;
|
||||
constexpr EnumBitSet() = default;
|
||||
|
||||
// Construct from a single bit
|
||||
constexpr EnumBitSet(T bit) noexcept : m_data(shift(bit)) {}
|
||||
|
|
@ -91,7 +93,9 @@ public:
|
|||
return m_data;
|
||||
}
|
||||
|
||||
constexpr detail::InvertedEnumBitSet<T> operator~() const { return {m_data}; }
|
||||
constexpr detail::InvertedEnumBitSet<T> operator~() const {
|
||||
return static_cast<underlying_type>(~m_data);
|
||||
}
|
||||
|
||||
[[deprecated("Use operator|=")]] constexpr EnumBitSet &
|
||||
operator+=(EnumBitSet rhs) {
|
||||
|
|
@ -126,6 +130,11 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
constexpr EnumBitSet &operator&=(detail::InvertedEnumBitSet<T> rhs) {
|
||||
m_data &= rhs.m_data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr EnumBitSet &operator^=(EnumBitSet rhs) {
|
||||
m_data ^= static_cast<underlying_type>(rhs);
|
||||
return *this;
|
||||
|
|
@ -191,7 +200,9 @@ public:
|
|||
return (m_data & arg.m_data) == 0;
|
||||
}
|
||||
|
||||
underlying_type &raw() { return m_data; }
|
||||
constexpr underlying_type &raw() { return m_data; }
|
||||
|
||||
constexpr auto operator<=>(const EnumBitSet &) const = default;
|
||||
};
|
||||
|
||||
template <BitSetEnum T> constexpr EnumBitSet<T> toBitSet(T bit) {
|
||||
|
|
@ -288,4 +299,50 @@ constexpr EnumBitSet<T> operator^(const U &lhs, T rhs) {
|
|||
} // namespace bitset
|
||||
} // namespace rx
|
||||
|
||||
template <typename T>
|
||||
requires requires(rx::format_parse_context &ctx) {
|
||||
rx::formatter<T>().parse(ctx);
|
||||
}
|
||||
struct rx::formatter<rx::EnumBitSet<T>> {
|
||||
constexpr rx::format_parse_context::iterator
|
||||
parse(rx::format_parse_context &ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
rx::format_context::iterator format(rx::EnumBitSet<T> bitSet,
|
||||
rx::format_context &ctx) const {
|
||||
auto raw = bitSet.toUnderlying();
|
||||
if (raw != 0) {
|
||||
bool first = true;
|
||||
for (std::size_t i = 0; i <= static_cast<std::size_t>(T::bitset_last);
|
||||
++i) {
|
||||
auto mask = 1ull << i;
|
||||
if (!(raw & mask)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
rx::format_to(ctx.out(), " | ");
|
||||
}
|
||||
|
||||
rx::format_to(ctx.out(), "{}", T(i));
|
||||
raw &= ~mask;
|
||||
}
|
||||
|
||||
if (raw) {
|
||||
if (!first) {
|
||||
rx::format_to(ctx.out(), " | ");
|
||||
}
|
||||
|
||||
rx::format_to(ctx.out(), "{:#x}", raw);
|
||||
}
|
||||
} else {
|
||||
rx::format_to(ctx.out(), "{}::None", rx::getNameOf<T>());
|
||||
}
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
using namespace rx::bitset;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public:
|
|||
: context(
|
||||
const_cast<std::remove_const_t<std::remove_cvref_t<T>> *>(&object)),
|
||||
invoke(+[](void *context, ArgsT... args) -> RT {
|
||||
return (*reinterpret_cast<T *>(context))(std::move(args)...);
|
||||
return (*reinterpret_cast<T *>(context))(args...);
|
||||
}) {}
|
||||
|
||||
template <typename... InvokeArgsT>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
namespace rx {
|
||||
class Mappable {
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
using NativeHandle = void *;
|
||||
static constexpr NativeHandle kInvalidHandle = nullptr;
|
||||
|
|
@ -16,9 +17,6 @@ class Mappable {
|
|||
static constexpr auto kInvalidHandle = NativeHandle(-1);
|
||||
#endif
|
||||
|
||||
NativeHandle m_handle = kInvalidHandle;
|
||||
|
||||
public:
|
||||
Mappable() = default;
|
||||
Mappable(Mappable &&other) noexcept { *this = std::move(other); }
|
||||
Mappable(const Mappable &) = delete;
|
||||
|
|
@ -33,6 +31,12 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
static Mappable CreateFromNativeHandle(NativeHandle handle) {
|
||||
Mappable result;
|
||||
result.m_handle = handle;
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::pair<Mappable, std::errc> CreateMemory(std::size_t size);
|
||||
static std::pair<Mappable, std::errc> CreateSwap(std::size_t size);
|
||||
std::errc map(rx::AddressRange virtualRange, std::size_t offset,
|
||||
|
|
@ -47,5 +51,7 @@ public:
|
|||
|
||||
private:
|
||||
void destroy();
|
||||
|
||||
NativeHandle m_handle = kInvalidHandle;
|
||||
};
|
||||
} // namespace rx
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "rx/AddressRange.hpp"
|
||||
#include "rx/Rc.hpp"
|
||||
#include "AddressRange.hpp"
|
||||
#include "Rc.hpp"
|
||||
#include "Serializer.hpp"
|
||||
#include <bit>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
|
|
@ -84,7 +85,7 @@ public:
|
|||
return {startAddress, endAddress};
|
||||
}
|
||||
|
||||
void map(rx::AddressRange range) {
|
||||
void map(AddressRange range) {
|
||||
auto [beginIt, beginInserted] =
|
||||
mAreas.emplace(range.beginAddress(), Kind::O);
|
||||
auto [endIt, endInserted] = mAreas.emplace(range.endAddress(), Kind::X);
|
||||
|
|
@ -311,6 +312,23 @@ public:
|
|||
assert(kind != Kind::X);
|
||||
kind = Kind::O;
|
||||
}
|
||||
|
||||
void serialize(Serializer &s) const
|
||||
requires Serializable<T>
|
||||
{
|
||||
s.serialize(kind);
|
||||
if (kind != Kind::X) {
|
||||
s.serialize(storage.data);
|
||||
}
|
||||
}
|
||||
void deserialize(Deserializer &d)
|
||||
requires Serializable<T>
|
||||
{
|
||||
d.deserialize(kind);
|
||||
if (kind != Kind::X && !d.failure()) {
|
||||
d.deserialize(storage.data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> class Payload<T *> {
|
||||
|
|
@ -365,6 +383,9 @@ public:
|
|||
assert(!isClose());
|
||||
value &= ~kCloseOpenBit;
|
||||
}
|
||||
|
||||
void serialize(Serializer &s) const { s.serialize(value); }
|
||||
void deserialize(Deserializer &d) { d.deserialize(value); }
|
||||
};
|
||||
|
||||
template <typename T> class Payload<Ref<T>> {
|
||||
|
|
@ -452,6 +473,9 @@ public:
|
|||
assert(!isClose());
|
||||
value &= ~kCloseOpenBit;
|
||||
}
|
||||
|
||||
void serialize(Serializer &s) const { s.serialize(value); }
|
||||
void deserialize(Deserializer &d) { d.deserialize(value); }
|
||||
};
|
||||
|
||||
template <typename PayloadT,
|
||||
|
|
@ -463,30 +487,28 @@ class MemoryTableWithPayload {
|
|||
mAreas;
|
||||
|
||||
public:
|
||||
class AreaInfo : public rx::AddressRange {
|
||||
Payload<PayloadT> &payload;
|
||||
template <typename T> class AreaInfo : public AddressRange {
|
||||
T &payload;
|
||||
|
||||
public:
|
||||
AreaInfo(Payload<PayloadT> &payload, rx::AddressRange range)
|
||||
AreaInfo(T &payload, AddressRange range)
|
||||
: payload(payload), AddressRange(range) {}
|
||||
|
||||
decltype(auto) operator->() { return &payload.get(); }
|
||||
decltype(auto) get() { return payload.get(); }
|
||||
};
|
||||
|
||||
class iterator {
|
||||
using map_iterator =
|
||||
typename std::map<std::uint64_t, payload_type>::iterator;
|
||||
map_iterator it;
|
||||
template <typename MapIterator, typename AreaInfo> class Iterator {
|
||||
MapIterator it;
|
||||
|
||||
public:
|
||||
iterator() = default;
|
||||
iterator(map_iterator it) : it(it) {}
|
||||
Iterator() = default;
|
||||
Iterator(MapIterator it) : it(it) {}
|
||||
|
||||
AreaInfo operator*() const { return {it->second, range()}; }
|
||||
|
||||
rx::AddressRange range() const {
|
||||
return rx::AddressRange::fromBeginEnd(beginAddress(), endAddress());
|
||||
AddressRange range() const {
|
||||
return AddressRange::fromBeginEnd(beginAddress(), endAddress());
|
||||
}
|
||||
|
||||
std::uint64_t beginAddress() const { return it->first; }
|
||||
|
|
@ -495,7 +517,8 @@ public:
|
|||
|
||||
decltype(auto) get() const { return it->second.get(); }
|
||||
decltype(auto) operator->() const { return &it->second.get(); }
|
||||
iterator &operator++() {
|
||||
|
||||
Iterator &operator++() {
|
||||
++it;
|
||||
|
||||
if (!it->second.isCloseOpen()) {
|
||||
|
|
@ -505,7 +528,7 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
iterator &operator--() {
|
||||
Iterator &operator--() {
|
||||
--it;
|
||||
|
||||
if (it->second.isClose()) {
|
||||
|
|
@ -515,18 +538,28 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(iterator other) const { return it == other.it; }
|
||||
bool operator!=(iterator other) const { return it != other.it; }
|
||||
bool operator==(Iterator other) const { return it == other.it; }
|
||||
|
||||
friend MemoryTableWithPayload;
|
||||
};
|
||||
|
||||
using iterator =
|
||||
Iterator<typename std::map<std::uint64_t, payload_type>::iterator,
|
||||
AreaInfo<payload_type>>;
|
||||
using const_iterator =
|
||||
Iterator<typename std::map<std::uint64_t, payload_type>::const_iterator,
|
||||
AreaInfo<const payload_type>>;
|
||||
|
||||
MemoryTableWithPayload() = default;
|
||||
MemoryTableWithPayload(MemoryTableWithPayload &&) = default;
|
||||
MemoryTableWithPayload &operator=(MemoryTableWithPayload &&) = default;
|
||||
MemoryTableWithPayload(const MemoryTableWithPayload &) = delete;
|
||||
MemoryTableWithPayload &operator=(const MemoryTableWithPayload &) = delete;
|
||||
|
||||
const_iterator cbegin() const { return const_iterator(mAreas.begin()); }
|
||||
const_iterator cend() const { return const_iterator(mAreas.end()); }
|
||||
const_iterator begin() const { return const_iterator(mAreas.cbegin()); }
|
||||
const_iterator end() const { return const_iterator(mAreas.cend()); }
|
||||
iterator begin() { return iterator(mAreas.begin()); }
|
||||
iterator end() { return iterator(mAreas.end()); }
|
||||
|
||||
|
|
@ -579,9 +612,9 @@ public:
|
|||
return endAddress < address ? mAreas.end() : it;
|
||||
}
|
||||
|
||||
iterator map(rx::AddressRange range, PayloadT payload, bool merge = true,
|
||||
iterator map(AddressRange range, PayloadT payload, bool merge = true,
|
||||
bool noOverride = false) {
|
||||
assert(range.beginAddress() < range.endAddress());
|
||||
assert(range.isValid());
|
||||
auto [beginIt, beginInserted] =
|
||||
mAreas.emplace(range.beginAddress(), payload_type::createOpen(payload));
|
||||
auto [endIt, endInserted] =
|
||||
|
|
@ -676,7 +709,7 @@ public:
|
|||
return origBegin;
|
||||
}
|
||||
|
||||
void unmap(iterator it) {
|
||||
iterator unmap(iterator it) {
|
||||
auto openIt = it.it;
|
||||
auto closeIt = openIt;
|
||||
++closeIt;
|
||||
|
|
@ -690,13 +723,49 @@ public:
|
|||
if (closeIt->second.isCloseOpen()) {
|
||||
closeIt->second.setOpen();
|
||||
} else {
|
||||
mAreas.erase(closeIt);
|
||||
closeIt = mAreas.erase(closeIt);
|
||||
}
|
||||
|
||||
return iterator(closeIt);
|
||||
}
|
||||
|
||||
void unmap(rx::AddressRange range) {
|
||||
iterator unmap(AddressRange range) {
|
||||
// FIXME: can be optimized
|
||||
unmap(map(range, PayloadT{}, false));
|
||||
return unmap(map(range, PayloadT{}, false));
|
||||
}
|
||||
|
||||
void serialize(Serializer &s) const
|
||||
requires Serializable<payload_type>
|
||||
{
|
||||
for (auto block : *this) {
|
||||
s.serialize(block.beginAddress());
|
||||
s.serialize(block.endAddress());
|
||||
s.serialize(block.get());
|
||||
}
|
||||
|
||||
s.serialize<std::uint64_t>(-1);
|
||||
s.serialize<std::uint64_t>(-1);
|
||||
}
|
||||
|
||||
void deserialize(Deserializer &d)
|
||||
requires Serializable<payload_type>
|
||||
{
|
||||
clear();
|
||||
|
||||
while (!d.failure()) {
|
||||
auto beginAddress = d.deserialize<std::uint64_t>();
|
||||
auto endAddress = d.deserialize<std::uint64_t>();
|
||||
|
||||
if (beginAddress == static_cast<std::uint64_t>(-1) &&
|
||||
endAddress == static_cast<std::uint64_t>(-1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto value = d.deserialize<PayloadT>();
|
||||
|
||||
map(AddressRange::fromBeginEnd(beginAddress, endAddress),
|
||||
std::move(value), false);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace rx
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ struct RcBase {
|
|||
virtual ~RcBase() = default;
|
||||
|
||||
void incRef() {
|
||||
if (references.fetch_add(1, std::memory_order::relaxed) > 4096) {
|
||||
if (references.fetch_add(1, std::memory_order::relaxed) > 100 * 1024 * 1024) {
|
||||
assert(!"too many references");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,19 +169,17 @@ struct Deserializer {
|
|||
if constexpr (requires {
|
||||
{ type::deserialize(*this) } -> std::convertible_to<type>;
|
||||
}) {
|
||||
return T::deserialize(*this);
|
||||
return type::deserialize(*this);
|
||||
} else if constexpr (requires(type &result) {
|
||||
type::deserialize(*this, result);
|
||||
}) {
|
||||
type result;
|
||||
T::deserialize(*this, result);
|
||||
type::deserialize(*this, result);
|
||||
return result;
|
||||
} else if constexpr (requires(type &result) {
|
||||
{
|
||||
result.deserialize(*this)
|
||||
} -> std::convertible_to<type>;
|
||||
result.deserialize(*this);
|
||||
}) {
|
||||
T result;
|
||||
type result;
|
||||
result.deserialize(*this);
|
||||
return result;
|
||||
} else if constexpr (requires(type &result) {
|
||||
|
|
|
|||
|
|
@ -174,13 +174,29 @@ constexpr auto calcFieldCount() {
|
|||
} else if constexpr (requires { EnumT::count; }) {
|
||||
return static_cast<std::size_t>(EnumT::count);
|
||||
} else if constexpr (!requires { getNameOf<EnumT(N)>()[0]; }) {
|
||||
return N;
|
||||
if constexpr (requires { getNameOf<EnumT(N + 1)>()[0]; }) {
|
||||
if constexpr (constexpr auto c = getNameOf<EnumT(N + 1)>()[0];
|
||||
c >= '0' && c <= '9') {
|
||||
return N;
|
||||
} else {
|
||||
return calcFieldCount<EnumT, N + 2>();
|
||||
}
|
||||
} else {
|
||||
return N;
|
||||
}
|
||||
} else {
|
||||
constexpr auto c = getNameOf<EnumT(N)>()[0];
|
||||
if constexpr (!requires { getNameOf<EnumT(N)>()[0]; }) {
|
||||
return N;
|
||||
} else if constexpr (c >= '0' && c <= '9') {
|
||||
return N;
|
||||
if constexpr (constexpr auto c = getNameOf<EnumT(N)>()[0];
|
||||
c >= '0' && c <= '9') {
|
||||
if constexpr (requires { getNameOf<EnumT(N + 1)>()[0]; }) {
|
||||
if constexpr (constexpr auto c = getNameOf<EnumT(N + 1)>()[0];
|
||||
c >= '0' && c <= '9') {
|
||||
return N;
|
||||
} else {
|
||||
return calcFieldCount<EnumT, N + 2>();
|
||||
}
|
||||
} else {
|
||||
return N;
|
||||
}
|
||||
} else {
|
||||
return calcFieldCount<EnumT, N + 1>();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue