diff --git a/include/xo/alloc2/alloc/AllocError.hpp b/include/xo/alloc2/AllocError.hpp similarity index 100% rename from include/xo/alloc2/alloc/AllocError.hpp rename to include/xo/alloc2/AllocError.hpp diff --git a/include/xo/alloc2/alloc/AllocHeader.hpp b/include/xo/alloc2/AllocHeader.hpp similarity index 100% rename from include/xo/alloc2/alloc/AllocHeader.hpp rename to include/xo/alloc2/AllocHeader.hpp diff --git a/include/xo/alloc2/alloc/AllocHeaderConfig.hpp b/include/xo/alloc2/AllocHeaderConfig.hpp similarity index 100% rename from include/xo/alloc2/alloc/AllocHeaderConfig.hpp rename to include/xo/alloc2/AllocHeaderConfig.hpp diff --git a/include/xo/alloc2/alloc/AllocInfo.hpp b/include/xo/alloc2/AllocInfo.hpp similarity index 100% rename from include/xo/alloc2/alloc/AllocInfo.hpp rename to include/xo/alloc2/AllocInfo.hpp diff --git a/include/xo/alloc2/alloc/AllocRange.hpp b/include/xo/alloc2/AllocRange.hpp similarity index 100% rename from include/xo/alloc2/alloc/AllocRange.hpp rename to include/xo/alloc2/AllocRange.hpp diff --git a/include/xo/alloc2/Collector.hpp b/include/xo/alloc2/Collector.hpp deleted file mode 100644 index 45c7fdb..0000000 --- a/include/xo/alloc2/Collector.hpp +++ /dev/null @@ -1,13 +0,0 @@ -/** @file Collector.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include "gc/ACollector.hpp" -#include "gc/ICollector_Any.hpp" -#include "gc/ICollector_Xfer.hpp" -#include "gc/RCollector.hpp" - -/* end Collector.hpp */ diff --git a/include/xo/alloc2/GCObject.hpp b/include/xo/alloc2/GCObject.hpp deleted file mode 100644 index edc89c3..0000000 --- a/include/xo/alloc2/GCObject.hpp +++ /dev/null @@ -1,13 +0,0 @@ -/** @file GCObject.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include "gcobject/AGCObject.hpp" -#include "gcobject/IGCObject_Any.hpp" -#include "gcobject/IGCObject_Xfer.hpp" -#include "gcobject/RGCObject.hpp" - -/* end GCObject.hpp */ diff --git a/include/xo/alloc2/alloc/AAllocIterator.hpp b/include/xo/alloc2/alloc/AAllocIterator.hpp index f2d332b..29be0a3 100644 --- a/include/xo/alloc2/alloc/AAllocIterator.hpp +++ b/include/xo/alloc2/alloc/AAllocIterator.hpp @@ -5,7 +5,7 @@ #pragma once -#include "alloc/AllocInfo.hpp" +#include "AllocInfo.hpp" #include "cmpresult.hpp" #include diff --git a/include/xo/alloc2/alloc/README b/include/xo/alloc2/alloc/README deleted file mode 100644 index 6efbf85..0000000 --- a/include/xo/alloc2/alloc/README +++ /dev/null @@ -1,4 +0,0 @@ -AAllocator |<-- IAllocator_Any (D=DVariantPlaceholder) - |<-- IAllocator_Xfer - -OObject |<-- RAllocator diff --git a/include/xo/alloc2/arena/ArenaConfig.hpp b/include/xo/alloc2/arena/ArenaConfig.hpp index 93fc35b..7c2b6f8 100644 --- a/include/xo/alloc2/arena/ArenaConfig.hpp +++ b/include/xo/alloc2/arena/ArenaConfig.hpp @@ -5,7 +5,7 @@ #pragma once -#include "alloc/AllocHeaderConfig.hpp" +#include "AllocHeaderConfig.hpp" //#include "alloc/AllocError.hpp" #include #include diff --git a/include/xo/alloc2/arena/DArena.hpp b/include/xo/alloc2/arena/DArena.hpp index e44b651..7c7196e 100644 --- a/include/xo/alloc2/arena/DArena.hpp +++ b/include/xo/alloc2/arena/DArena.hpp @@ -6,8 +6,8 @@ #pragma once #include "ArenaConfig.hpp" -#include "alloc/AllocError.hpp" -#include "alloc/AllocInfo.hpp" +#include "AllocError.hpp" +#include "AllocInfo.hpp" namespace xo { namespace mm { diff --git a/include/xo/alloc2/arena/DArenaIterator.hpp b/include/xo/alloc2/arena/DArenaIterator.hpp index 05cf7b7..e25fbb8 100644 --- a/include/xo/alloc2/arena/DArenaIterator.hpp +++ b/include/xo/alloc2/arena/DArenaIterator.hpp @@ -5,8 +5,8 @@ #pragma once -#include "alloc/AllocInfo.hpp" -#include "alloc/AllocHeader.hpp" +#include "AllocInfo.hpp" +#include "AllocHeader.hpp" #include "cmpresult.hpp" namespace xo { diff --git a/include/xo/alloc2/cmpresult.hpp b/include/xo/alloc2/cmpresult.hpp index 0cc445c..477e1dc 100644 --- a/include/xo/alloc2/cmpresult.hpp +++ b/include/xo/alloc2/cmpresult.hpp @@ -11,9 +11,9 @@ namespace xo { namespace mm { enum class comparison : int32_t { - invalid = -1, - comparable = 0, - incomparable = 1, + invalid = -1, + comparable = 0, + incomparable = +1, }; extern const char * comparison2str(comparison x); @@ -55,7 +55,7 @@ namespace xo { /* -1 -> invalid (sentinel) * 0 -> comparable - * 1 -> incomparable (e.g. iterators from different arenas) + * +1 -> incomparable (e.g. iterators from different arenas) */ comparison err_ = comparison::invalid; /* <0 -> lesser; 0 -> equal, >0 -> greater */ diff --git a/include/xo/alloc2/gc/ACollector.hpp b/include/xo/alloc2/gc/ACollector.hpp deleted file mode 100644 index da694e9..0000000 --- a/include/xo/alloc2/gc/ACollector.hpp +++ /dev/null @@ -1,60 +0,0 @@ -/** @file ACollector.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include "gcobject/IGCObject_Any.hpp" - -#include -#include -#include - -#include "gc/generation.hpp" -#include "gc/role.hpp" - -#include -#include - -namespace xo { - namespace mm { - using Copaque = const void *; - using Opaque = void *; - - struct IGCObject_Any; // see IGCObject_Any.hpp - - /** @class ACollector - * @brief Abstract facet for the XO garbage collector - * - * Collector also supports the @ref AAllocator facet, see also - **/ - struct ACollector { - using size_type = std::size_t; - - virtual int32_t _typeseq() const noexcept = 0; - - virtual size_type allocated(Copaque d, generation g, role r) const noexcept = 0; - virtual size_type reserved(Copaque d, generation g, role r) const noexcept = 0; - virtual size_type committed(Copaque d, generation g, role r) const noexcept = 0; - - /** install interface @p iface for representation with typeseq @p tseq - * in collector @p d. - * - * The type AGCObject_Any here is misleading. - * Will have been replaced by an instance of - * @c AGCObject_Xfer for some @c DFoo - * in which case calls through @c std::launder(&iface) - * will properly act on @c DFoo. - **/ - virtual void install_type(Opaque d, int32_t tseq, IGCObject_Any & iface) = 0; - virtual void add_gc_root(Opaque d, int32_t tseq, Opaque * root) = 0; - - /** evacuate @p *lhs to to-space and replace with forwarding pointer - * Require: gc in progress - **/ - virtual void forward_inplace(Opaque d, obj * lhs) = 0; - }; - } - -} /*namespace xo*/ diff --git a/include/xo/alloc2/gc/DX1Collector.hpp b/include/xo/alloc2/gc/DX1Collector.hpp deleted file mode 100644 index 5d2f614..0000000 --- a/include/xo/alloc2/gc/DX1Collector.hpp +++ /dev/null @@ -1,261 +0,0 @@ -/** @file DX1Collector.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include "arena/ArenaConfig.hpp" -#include "arena/DArena.hpp" -#include "gc/generation.hpp" -#include "gc/object_age.hpp" -#include "gc/role.hpp" -#include -#include - -namespace xo { - namespace mm { - template - using up = std::unique_ptr; - -#ifdef NOT_YET - /** State associated with a single DX1Collector generation - **/ - struct Generation { - Generation(uint8_t gen_id, up from_space, up to_space); - ~Generation() = default; - - /** identity of this generation. Generations are numbered from - * 0 (youngest) to N (oldest), with N <= c_max_generation - **/ - uint8_t gen_id_; - /** from-space. empty between collection episodes. - * During collection holds former to-space - **/ - up from_space_; - /** to-space. New allocations occur here **/ - up to_space_; - }; -#endif - - struct CollectorConfig { - using size_type = std::size_t; - -#ifdef OBSOLETE // get from arena_config_.header_ - /* - * alloc header - * TTTTTTTTTTTTGGGGGZZZZZZZZZZZZ - * < tseq >< size > - * - * masking - * - * ..432107654321076543210 bit - * - * > < .gen_bits - * 0..............01111111 gen_mask_unshifted - * 0..011111110..........0 gen_mask_shifted - * > < gen_shift - */ - //constexpr std::uint64_t gen_mult() const; - constexpr std::uint64_t gen_shift() const; - constexpr std::uint64_t gen_mask_unshifted() const; - constexpr std::uint64_t gen_mask_shifted() const; - - //constexpr std::uint64_t tseq_mult() const; - constexpr std::uint64_t tseq_shift() const; - constexpr std::uint64_t tseq_mask_unshifted() const; - constexpr std::uint64_t tseq_mask_shifted() const; -#endif - - generation age2gen(object_age age) const noexcept { - return generation(age % n_survive_threshold_); - } - - public: - // ----- Instance Variables ----- - - /** optional name, for diagnostics **/ - std::string name_; - - /** Configuration for collector spaces. - * Will have at least {nursery,tenured} x {from,to} spaces. - * Not using name_ member. - * - * REQUIRE: - * - arena_config_.store_header_flag_ must be true - **/ - ArenaConfig arena_config_; - - /** number of bits to represent generation **/ - std::uint64_t gen_bits_ = 8; - - /** number of bits to represent tseq **/ - std::uint64_t tseq_bits_ = 24; - - /** Number of generations. - * Must be at least 2. - **/ - uint32_t n_generation_ = 2; - - /** Number of promotion steps. - * An object that survives this number of collections - * advances to the next generation. - **/ - uint32_t n_survive_threshold_ = 2; - - /** Trigger garbage collection when to-space allocation for - * generation g reaches gc_trigger_v_[g] - **/ - std::array gc_trigger_v_; - - /** true -> enable incremental collection. - * false -> only do full collection. - * - * Incremental collection requires mutation logs. - **/ - bool allow_incremental_gc_ = true; - - /** If non-zero remember statistics for - * the last @p stats_history_z_ collections. - **/ - uint32_t stats_history_z_ = false; - - /** true to enable debug logging **/ - bool debug_flag_ = false; - }; - - // ----- GCRunState ----- - - /** @class GCRunState - * @brief encapsulate state needed while GC is running - **/ - struct GCRunState { - GCRunState() : gc_upto_{0} {} - explicit GCRunState(generation gc_upto); - - static GCRunState gc_not_running(); - static GCRunState gc_upto(generation g); - - bool is_running() const { return gc_upto_ > 0; } - - generation gc_upto() const { return gc_upto_; } - - private: - /** running gc collecting all generations gi < gc_upto **/ - generation gc_upto_; - }; - - struct DX1CollectorIterator; - - // ----- DX1Collector ----- - - struct DX1Collector { - using size_type = DArena::size_type; - using value_type = DArena::value_type; - using header_type = DArena::header_type; - - explicit DX1Collector(const CollectorConfig & cfg); - - const DArena * get_space(role r, generation g) const noexcept { return space_[r][g]; } - DArena * get_space(role r, generation g) noexcept { return space_[r][g]; } - DArena * from_space(generation g) noexcept { return get_space(role::from_space(), g); } - DArena * to_space(generation g) noexcept { return get_space(role::to_space(), g); } - DArena * new_space() noexcept { return to_space(generation{0}); } - - /** total reserved memory in bytes, across all {role, generation} **/ - size_type reserved_total() const noexcept; - /** total size in bytes (same as committed_total()) **/ - size_type size_total() const noexcept; - /** total committed memory in bytes, across all {role, generation} **/ - size_type committed_total() const noexcept; - /** total available memory in bytes, across all {role, generation} **/ - size_type available_total() const noexcept; - /** total allocated memory in bytes, across all {role, generation} **/ - size_type allocated_total() const noexcept; - - /** true iff address @p addr allocated from this collector - * in role @p r (according to current GC state) - **/ - bool contains(role r, const void * addr) const noexcept; - - /** return details from last error (will be in gen0 to-space) **/ - AllocError last_error() const noexcept; - - /** get allocation size from header **/ - std::size_t header2size(header_type hdr) const noexcept; - /** get generation counter from alloc header **/ - object_age header2age(header_type hdr) const noexcept; - /** get tseq from alloc header **/ - uint32_t header2tseq(header_type hdr) const noexcept; - - /** true iff original alloc has been replaced by a forwarding pointer **/ - bool is_forwarding_header(header_type hdr) const noexcept; - - /** Retreive bookkeeping info for allocation at @p mem. **/ - AllocInfo alloc_info(value_type mem) const noexcept; - - // ----- allocation ----- - - /** simple allocation. new allocs always in gen0 to-space **/ - value_type alloc(size_type z) noexcept; - /** compound allocation. To be followed immediately by: - * 1. zero or more calls to sub_alloc(zi, complete=false), then - * 2. exactly one call to sub_alloc(zi, complete=true) - * all the allocs in a compound allocation share the same - * allocation header. End state is equivalent to a single - * allocation with size z + sum(zi). - * New allocs always in gen0 to-space - **/ - value_type super_alloc(size_type z) noexcept; - /** sub-allocation with preceding compound allocation. - * New allocs always in gen0 to-space - **/ - value_type sub_alloc(size_type z, bool complete) noexcept; - /** expand gen0 committed size to at least @p z. - **/ - bool expand(size_type z) noexcept; - - // ----- iteration ----- - - /** alloc iterator at begin position **/ - DX1CollectorIterator begin() const noexcept; - /** alloc iterator at end position - * (valid, but cannot be dereferenced) - **/ - DX1CollectorIterator end() const noexcept; - - // ----- book-keeping ----- - - /** reverse to-space and from-space roles for generation g **/ - void reverse_roles(generation g) noexcept; - - /** discard all allocated memory **/ - void clear() noexcept; - - public: - /** garbage collector configuration **/ - CollectorConfig config_; - - /** current gc state **/ - GCRunState runstate_; - - /** collector-managed memory here. - * - space_[1] is from-space - * - space_[0] is to-space - * coordinates with role ingc/role.hpp, see also. - **/ - - /** arena objects for collector managed memory - * 1:1 with roles, but polarity reverses for each collection - **/ - std::array space_storage_[c_n_role]; - - /** arena pointers. The roles of space_storage_[0][g] and space_storage_[1][g] - * are reversed each time generation g gets collected. - **/ - std::array space_[c_n_role]; - }; - } /*namespace mm*/ -} /*namespace xo*/ - -/* end DX1Collector.hpp */ diff --git a/include/xo/alloc2/gc/DX1CollectorIterator.hpp b/include/xo/alloc2/gc/DX1CollectorIterator.hpp deleted file mode 100644 index b510d30..0000000 --- a/include/xo/alloc2/gc/DX1CollectorIterator.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/** @file DX1CollectorIterator.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include "alloc/AllocInfo.hpp" -#include "gc/generation.hpp" -#include "arena/DArenaIterator.hpp" -#include "cmpresult.hpp" - -namespace xo { - namespace mm { - struct DX1Collector; - - /** @class DX1CollectorIterator - * @brief Representation for alloc iterator over X1 collector - * - * Will iterate across all allocs in all generations - **/ - struct DX1CollectorIterator { - DX1CollectorIterator() = default; - DX1CollectorIterator(const DX1Collector * gc, - generation gen_ix, - generation gen_hi, - DArenaIterator arena_ix, - DArenaIterator arena_hi); - - /** Invalid iterator. Does not compare equal to anything, including itself **/ - static DX1CollectorIterator invalid() { return DX1CollectorIterator(); } - /** Create iterator pointing to the beginning of @p gc. - * Iterator cannot modify payload memory - **/ - static DX1CollectorIterator begin(DX1Collector * gc); - /** Create iterator pointing to the end of @p gc. - * Iterator cannot modify payload memory. - **/ - static DX1CollectorIterator end(DX1Collector * gc); - - /** true if iterator is invalid. invalid iterators are not comparable **/ - bool is_valid() const noexcept { return (gc_ != nullptr); } - bool is_invalid() const noexcept { return !is_valid(); } - - generation gen_ix() const { return gen_ix_; } - generation gen_hi() const { return gen_hi_; } - DArenaIterator arena_ix() const { return arena_ix_; } - DArenaIterator arena_hi() const { return arena_hi_; } - - /** fetch contents at current iterator position **/ - AllocInfo deref() const noexcept; - /** compare two iterators. To be comparable, - * iterators must refer to the same collector - **/ - cmpresult compare(const DX1CollectorIterator & other) const noexcept; - /** advance iterator to next allocation **/ - void next() noexcept; - - /** for *ix synonym for ix.deref() **/ - AllocInfo operator*() const noexcept { return this->deref(); } - - private: - /** if non-empty, normalize to state with arena_ix_ != arena_hi_ **/ - void normalize() noexcept; - - private: - /** Iterator visits allocations from this collector **/ - const DX1Collector * gc_ = nullptr; - /** Iterating over generations in [@p gen_ix_, @p gen_hi_). - * Current position is within arena for @p gen_ix_ to-space, - * Provided @p gen_ix_ < @p gen_hi_ - **/ - generation gen_ix_; - generation gen_hi_; - /** Iterating over allocs in [@p arena_ix_, @p arena_hi_). - * Current position is at @p arena_ix_ - **/ - DArenaIterator arena_ix_; - DArenaIterator arena_hi_; - }; - - inline bool - operator==(const DX1CollectorIterator & x, const DX1CollectorIterator & y) { - return x.compare(y).is_equal(); - } - - inline bool - operator!=(const DX1CollectorIterator & x, const DX1CollectorIterator & y) { - return !x.compare(y).is_equal(); - } - - } /*namespace mm*/ -} /*namespace xo*/ - -/* end DX1CollectorIterator.hpp */ diff --git a/include/xo/alloc2/gc/IAllocIterator_DX1CollectorIterator.hpp b/include/xo/alloc2/gc/IAllocIterator_DX1CollectorIterator.hpp deleted file mode 100644 index 686f9fc..0000000 --- a/include/xo/alloc2/gc/IAllocIterator_DX1CollectorIterator.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/** @file IAllocIterator_DX1Collector.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include "alloc/IAllocIterator_Xfer.hpp" -#include "gc/DX1CollectorIterator.hpp" - -namespace xo { - namespace mm { struct IAllocIterator_DX1CollectorIterator; } - - namespace facet { - template <> - struct FacetImplementation { - using ImplType = xo::mm::IAllocIterator_Xfer; - }; - } - - namespace mm { - /** @class IAllocIterator_DX1Collector - * @brief alloc iteration for the DX1Collector allocator - **/ - struct IAllocIterator_DX1CollectorIterator { - static AllocInfo deref(const DX1CollectorIterator &) noexcept; - static cmpresult compare(const DX1CollectorIterator &, - const obj & other) noexcept; - static void next(DX1CollectorIterator &) noexcept; - }; - } /*namespace mm*/ -} /*namespace xo*/ - -/* end IAllocIterator_DX1Collector.hpp */ diff --git a/include/xo/alloc2/gc/IAllocator_DX1Collector.hpp b/include/xo/alloc2/gc/IAllocator_DX1Collector.hpp deleted file mode 100644 index c525dad..0000000 --- a/include/xo/alloc2/gc/IAllocator_DX1Collector.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/** @file IAllocator_DX1Collector.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include "Allocator.hpp" -#include "DX1Collector.hpp" - -namespace xo { - namespace mm { struct IAllocator_DX1Collector; } - - namespace facet { - template <> - struct FacetImplementation - { - using ImplType = xo::mm::IAllocator_Xfer; - }; - } - - namespace mm { - /* changes here coordinate with - * AAllocator AAllocator.hpp - * IAllocator_Any IAllocator_Any.hpp - * IAllocator_Xfer IAllocator_Xfer.hpp - * RAllocator RCollector.hpp - */ - struct IAllocator_DX1Collector { - using size_type = std::size_t; - using value_type = std::byte *; - using range_type = AAllocator::range_type; - - // todo: available() - - static std::string_view name(const DX1Collector &) noexcept; - /** reserved memory across all {roles, generations} **/ - static size_type reserved(const DX1Collector &) noexcept; - /** 'size'. synonym for committed size **/ - static size_type size(const DX1Collector &) noexcept; - /** committed size accross all {roles, generations} **/ - static size_type committed(const DX1Collector &) noexcept; - /** available (committed but unused) space across all {roles, generations} **/ - static size_type available(const DX1Collector &) noexcept; - /** space used by @p d across all {roles, generations}. **/ - static size_type allocated(const DX1Collector &) noexcept; - /** true iff address @p p comes from collector @p d **/ - static bool contains(const DX1Collector & d, const void * p) noexcept; - /** report last error, if any, for collector @p d **/ - static AllocError last_error(const DX1Collector &) noexcept; - /** fetch allocation bookkeeping info **/ - static AllocInfo alloc_info(const DX1Collector & d, value_type mem) noexcept; - /** create alloc-iterator range over allocs in @d, - * with iterator working storage obtained from @p ialloc - **/ - static range_type alloc_range(const DX1Collector & d, DArena & ialloc) noexcept; - - /** always alloc in gen0 to-space **/ - static value_type alloc(DX1Collector & d, size_type z) noexcept; - static value_type super_alloc(DX1Collector & d, size_type z) noexcept; - static value_type sub_alloc(DX1Collector & d, size_type z, bool complete) noexcept; - /** expand gen0 spaces (both from-space and to-space) **/ - static bool expand(DX1Collector & d, size_type z) noexcept; - - /** reset to empty state; clears all generations **/ - static void clear(DX1Collector & d); - /** invoke destructor **/ - static void destruct_data(DX1Collector & d); - }; - - } /*namespace mm*/ -} /*namespace xo*/ - - -/* end IAllocator_DX1Collector.hpp */ diff --git a/include/xo/alloc2/gc/ICollector_Any.hpp b/include/xo/alloc2/gc/ICollector_Any.hpp deleted file mode 100644 index c977968..0000000 --- a/include/xo/alloc2/gc/ICollector_Any.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/** @file ICollector_Any.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include "ACollector.hpp" -//#include - -namespace xo { - namespace mm { struct ICollector_Any; } - - namespace facet { - template <> - struct FacetImplementation { - using ImplType = xo::mm::ICollector_Any; - }; - } - - namespace mm { - /** @class ICollector_Any - * @brief Stub Collector Implementation for empty variant instance - **/ - struct ICollector_Any : public ACollector { - using size_type = std::size_t; - - // from ACollector - int32_t _typeseq() const noexcept override { return s_typeseq; } - - // const methods - [[noreturn]] size_type allocated(Copaque, generation, role) const noexcept override { _fatal(); } - [[noreturn]] size_type reserved(Copaque, generation, role) const noexcept override { _fatal(); } - [[noreturn]] size_type committed(Copaque, generation, role) const noexcept override { _fatal(); } - - // non-const methods - [[noreturn]] void install_type(Opaque, int32_t, IGCObject_Any &) noexcept override { _fatal(); } - [[noreturn]] void add_gc_root(Opaque, int32_t, Opaque *) override { _fatal(); } - [[noreturn]] void forward_inplace(Opaque, obj *) override { _fatal(); } - - private: - [[noreturn]] static void _fatal(); - - public: - static int32_t s_typeseq; - static bool _valid; - }; - } /*namespace mm*/ -} /*namespace xo*/ - -/* end ICollector_Any.hpp */ diff --git a/include/xo/alloc2/gc/ICollector_DX1Collector.hpp b/include/xo/alloc2/gc/ICollector_DX1Collector.hpp deleted file mode 100644 index 9bc6e12..0000000 --- a/include/xo/alloc2/gc/ICollector_DX1Collector.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/** @file ICollector_DX1Collector.hpp -* - * @author Roland Conybeare, Dec 2025 - **/ - -#include "ACollector.hpp" -#include "ICollector_Xfer.hpp" -#include "DX1Collector.hpp" - -namespace xo { - namespace mm { struct ICollector_DX1Collector; } - - namespace facet { - template <> - struct FacetImplementation - { - using ImplType = xo::mm::ICollector_Xfer; - }; - } - - namespace mm { - /* changes here coordinate with - * ACollector ACollector.hpp - * ICollector_Any ICollector_Any.hpp - * ICollector_Xfer ICollector_Xfer.hpp - * RCollector RCollector.hpp - */ - struct ICollector_DX1Collector { - using size_type = std::size_t; - using header_type = DArena::header_type; - - static bool check_move_policy(const DX1Collector & d, - header_type alloc_hdr, - void * object_data); - - // todo: available() - - static size_type allocated(const DX1Collector & d, generation g, role r); - static size_type reserved(const DX1Collector & d, generation g, role r); - static size_type committed(const DX1Collector & d, generation g, role r); - - static void install_type(DX1Collector & d, - int32_t seq, IGCObject_Any & iface); - static void add_gc_root(DX1Collector & d, int32_t tseq, Opaque * root); - static void forward_inplace(DX1Collector & d, obj * lhs); - - static int32_t s_typeseq; - static bool _valid; - }; - } /*namespace mm*/ -} /*namespace xo*/ - -/* end ICollector_DX1_Collector.hpp */ diff --git a/include/xo/alloc2/gc/ICollector_Xfer.hpp b/include/xo/alloc2/gc/ICollector_Xfer.hpp deleted file mode 100644 index 2177b63..0000000 --- a/include/xo/alloc2/gc/ICollector_Xfer.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/** @file ICollector_Xfer.hpp - * - * @author Roland Conybeare, 2025 - **/ - -#pragma once - -#include "ACollector.hpp" - -namespace xo { - namespace mm { - /** @class ICollector_Xfer - * - * Adapts typed ACollector implementation @tparam ICollector_DRepr - * to type-erased @ref ACollector interface - * - * See for example - * @ref ICollector_DX1Collector - **/ - template - struct ICollector_Xfer : public ACollector { - public: - using Impl = ICollector_DRepr; - using size_type = ACollector::size_type; - - static const DRepr & _dcast(Copaque d) { return *(const DRepr *)d; } - static DRepr & _dcast(Opaque d) { return *(DRepr *)d; } - - // from ACollector - - // const methods - - int32_t _typeseq() const noexcept override { return s_typeseq; } - size_type allocated(Copaque d, generation g, role r) const noexcept override { - return I::allocated(_dcast(d), g, r); - } - size_type reserved(Copaque d, generation g, role r) const noexcept override { - return I::reserved(_dcast(d), g, r); - } - size_type committed(Copaque d, generation g, role r) const noexcept override { - return I::committed(_dcast(d), g, r); - } - - // non-const methods - - void install_type(Opaque d, int32_t tseq, IGCObject_Any & iface) override { - I::install_type(_dcast(d), tseq, iface); - } - void add_gc_root(Opaque d, int32_t tseq, Opaque * root) override { - I::add_gc_root(_dcast(d), tseq, root); - } - void forward_inplace(Opaque d, obj * lhs) override { - I::forward_inplace(_dcast(d), lhs); - } - - private: - using I = Impl; - - public: - static int32_t s_typeseq; - static bool _valid; - }; - - template - int32_t - ICollector_Xfer::s_typeseq = facet::typeseq::id(); - - template - bool - ICollector_Xfer::_valid = facet::valid_facet_implementation(); - - } /*namespace mm*/ -} /*namespace xo*/ - -/* end ICollector_Xfer.hpp */ diff --git a/include/xo/alloc2/gc/RCollector.hpp b/include/xo/alloc2/gc/RCollector.hpp deleted file mode 100644 index 753af3c..0000000 --- a/include/xo/alloc2/gc/RCollector.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/** @file RCollector.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#include "ACollector.hpp" -#include - -namespace xo { - namespace mm { - /** @class RCollector **/ - template - struct RCollector : public Object { - private: - using O = Object; - public: - using ObjectType = Object; - using DataPtr = Object::DataPtr; - using size_type = std::size_t; - //using value_type = std::byte *; - - RCollector() = default; - RCollector(DataPtr data) : Object{std::move(data)} {} - - int32_t _typeseq() const noexcept { return O::iface()->_typeseq(); } - size_type allocated(generation g, role r) const noexcept { return O::iface()->allocated(O::data(), g, r); } - size_type reserved(generation g, role r) const noexcept { return O::iface()->reserved(O::data(), g, r); } - size_type committed(generation g, role r) const noexcept { return O::iface()->committed(O::data(), g, r); } - - void install_type(int32_t tseq, IGCObject_Any & iface) { return O::iface()->install_type(O::data(), tseq, iface); } - void add_gc_root(int32_t tseq, Opaque * root) { O::iface()->add_gc_root(O::data(), tseq, root); } - - void forward_inplace(obj * lhs) { O::iface()->forward_inplace(O::data(), lhs); } - - static bool _valid; - }; - - template - bool - RCollector::_valid = facet::valid_object_router(); - } /*namespace mm*/ - - namespace facet { - template - struct RoutingFor { - using RoutingType = xo::mm::RCollector; - }; - } -} /*namespace xo*/ - -/* end RCollector.hpp */ diff --git a/include/xo/alloc2/gc/generation.hpp b/include/xo/alloc2/gc/generation.hpp deleted file mode 100644 index 12b36d0..0000000 --- a/include/xo/alloc2/gc/generation.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/** @file generation.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include -#include - -namespace xo { - namespace mm { - /** hard maximum number of generations **/ - static constexpr uint32_t c_max_generation = 16; - - /** @class generation - * @brief type-safe generation number - **/ - struct generation { - using value_type = std::uint32_t; - - constexpr generation() = default; - explicit constexpr generation(value_type x) : value_{x} {} - - static generation nursery() { return generation{0}; } - - constexpr operator value_type() const { return value_; } - - generation & operator++() { ++value_; return *this; } - - std::uint32_t value_ = 0; - }; - } -} - -/* end generation.hpp */ diff --git a/include/xo/alloc2/gc/object_age.hpp b/include/xo/alloc2/gc/object_age.hpp deleted file mode 100644 index ae876bd..0000000 --- a/include/xo/alloc2/gc/object_age.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/** @file object_age.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include - -namespace xo { - namespace mm { - /** hard maximum remembered object age **/ - static constexpr uint32_t c_max_object_age = 127; - - /** @class object_age - * @brief type-safe object age - * - * Object age measured in number of garbage collections survived. - **/ - struct object_age { - using value_type = std::uint32_t; - - explicit object_age(value_type x) : value_{x} {} - - operator value_type() const { return value_; } - - std::uint32_t value_; - }; - } -} - -/* end object_age.hpp */ diff --git a/include/xo/alloc2/gc/role.hpp b/include/xo/alloc2/gc/role.hpp deleted file mode 100644 index 58fc72a..0000000 --- a/include/xo/alloc2/gc/role.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/** @file role.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include -#include - -namespace xo { - namespace mm { - static constexpr uint32_t c_n_role = 2; - - struct role { - using value_type = std::uint32_t; - - explicit constexpr role(value_type x) : role_{x} {} - - static constexpr role to_space() { return role{0}; } - static constexpr role from_space() { return role{1}; } - - static constexpr std::array all() { return {{to_space(), from_space()}}; } - - static constexpr role begin() { return role{0}; } - static constexpr role end() { return role{2}; } - - operator value_type() const { return role_; } - - value_type role_ = 0; - }; - } /*namespace mm*/ -} /*namespace xo*/ - -/* end role.hpp */ diff --git a/include/xo/alloc2/gcobject/AGCObject.hpp b/include/xo/alloc2/gcobject/AGCObject.hpp deleted file mode 100644 index 1e0a6d4..0000000 --- a/include/xo/alloc2/gcobject/AGCObject.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/** @file AGCObject.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include "Allocator.hpp" -#include "xo/facet/facet_implementation.hpp" -#include "xo/facet/typeseq.hpp" -#include "xo/facet/obj.hpp" // for obj in shallow_copy -#include -#include - -namespace xo { - namespace mm { - using Copaque = const void *; - using Opaque = void *; - - /** @class AObject - * @brief Abstract facet for collector-eligible data - * - * Data that supports AGCObject can have memory managed - * by ACollector - **/ - struct AGCObject { - using size_type = std::size_t; - - /** RTTI: unique id# for actual runtime data representation **/ - virtual int32_t _typeseq() const noexcept = 0; - - virtual size_type shallow_size(Copaque d) const noexcept = 0; - virtual Opaque * shallow_copy(Copaque d, - obj mm) const noexcept = 0; - virtual size_type forward_children(Opaque d) const noexcept = 0; - }; - - // implementation IGCObject_DRepr of AGCObject for state DRepr - // should provide a specialization: - // - // template <> - // struct xo::facet::FacetImplementation { - // using ImplType = IGCObject_DRepr; - // }; - // - // then IGCObject_ImplType --> IGCObject_DRepr - // - template - using IGCObject_ImplType = xo::facet::FacetImplType; - } /*namespace mm*/ -} /*namespace xo*/ - -/* end AGCObject.hpp */ diff --git a/include/xo/alloc2/gcobject/IGCObject_Any.hpp b/include/xo/alloc2/gcobject/IGCObject_Any.hpp deleted file mode 100644 index 039a125..0000000 --- a/include/xo/alloc2/gcobject/IGCObject_Any.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/** @file IGCObject_Any.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include "AGCObject.hpp" -#include - -namespace xo { - namespace mm { struct IGCObject_Any; } - - namespace facet { - template <> - struct FacetImplementation { - using ImplType = xo::mm::IGCObject_Any; - }; - } - - namespace mm { - /** @class IGCObject_Any - * @brief AGCObject implementation for empty variant instance - **/ - struct IGCObject_Any : public AGCObject { - using size_type = std::size_t; - - const AGCObject * iface() const { return std::launder(this); } - - // from AGCObject - int32_t _typeseq() const noexcept override { return s_typeseq; } - - [[noreturn]] size_type shallow_size(Copaque) const noexcept override { _fatal(); } - [[noreturn]] Opaque * shallow_copy(Copaque, - obj) const noexcept override { _fatal(); } - [[noreturn]] size_type forward_children(Opaque) const noexcept override { _fatal(); } - - private: - [[noreturn]] static void _fatal(); - - public: - static int32_t s_typeseq; - static bool _valid; - }; - } /*namespace mm*/ -} /*namespace xo*/ - -/* end IGCObject_Any.hpp */ diff --git a/include/xo/alloc2/gcobject/IGCObject_Xfer.hpp b/include/xo/alloc2/gcobject/IGCObject_Xfer.hpp deleted file mode 100644 index 75f78fd..0000000 --- a/include/xo/alloc2/gcobject/IGCObject_Xfer.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/** @file IGCObject_Xfer.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include "AGCObject.hpp" - -namespace xo { - namespace mm { - /** @class IGCObject_Xfer - * - * Adapts typed GC object implementation @tparam IGCObject_DRepr - * to type-erased @ref AGCObject interface - **/ - template - struct IGCObject_Xfer : public AGCObject { - using Impl = IGCObject_DRepr; - using size_type = AGCObject::size_type; - - static const DRepr & _dcast(Copaque d) { return *(const DRepr *)d; } - static DRepr & _dcast(Opaque d) { return *(DRepr *)d; } - - // from AGCObject - - // const methods - - int32_t _typeseq() const noexcept override { return s_typeseq; } - size_type shallow_size(Copaque d) const noexcept override { - return I::shallow_copy(_dcast(d)); - } - Opaque * shallow_copy(Copaque d, obj mm) const noexcept override { - return I::shallow_size(_dcast(d), mm); - } - - // non-const methods - - size_type forward_children(Opaque d) const noexcept override { - return I::forward_children(d); - } - - private: - using I = Impl; - - public: - static int32_t s_typeseq; - static bool _valid; - }; - - template - int32_t - IGCObject_Xfer::s_typeseq = facet::typeseq::id(); - - template - bool - IGCObject_Xfer::_valid = facet::valid_facet_implementation(); - - } /*namespace mm*/ -} /*namespace xo*/ - -/* end IGCObject_Xfer.hpp */ diff --git a/include/xo/alloc2/gcobject/RGCObject.hpp b/include/xo/alloc2/gcobject/RGCObject.hpp deleted file mode 100644 index 054b995..0000000 --- a/include/xo/alloc2/gcobject/RGCObject.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/** @file RGCObject.hpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#pragma once - -#include "AGCObject.hpp" -#include - -namespace xo { - namespace mm { - /** @class RGCObject **/ - template - struct RGCObject : public Object { - private: - using O = Object; - public: - using ObjectType = Object; - using DataPtr = Object::DataPtr; - using size_type = std::size_t; - - RGCObject() = default; - RGCObject(Object::DataPtr data) : Object{std::move(data)} {} - - int32_t _typeseq() const noexcept { return O::iface()->_typeseq(); } - size_type shallow_size() const noexcept { O::iface()->shallow_size(O::data()); } - Opaque * shallow_copy(obj mm) const noexcept { O::iface()->shallow_copy(O::data(), mm); } - size_type forward_children() noexcept { O::iface()->forward_children(O::data()); } - - static bool _valid; - }; - - template - bool - RGCObject::_valid = facet::valid_object_router(); - } /*namespace mm*/ - - namespace facet { - template - struct RoutingFor { - using RoutingType = xo::mm::RGCObject; - }; - } -} /*namespace xo*/ - -/* end RGCObject.hpp */ diff --git a/src/alloc2/AllocInfo.cpp b/src/alloc2/AllocInfo.cpp index 76e899d..9c4c8e7 100644 --- a/src/alloc2/AllocInfo.cpp +++ b/src/alloc2/AllocInfo.cpp @@ -3,7 +3,7 @@ * @author Roland Conybeare, Dec 2025 **/ -#include "alloc/AllocInfo.hpp" +#include "AllocInfo.hpp" namespace xo { namespace mm { diff --git a/src/alloc2/CMakeLists.txt b/src/alloc2/CMakeLists.txt index 8732713..aabffe8 100644 --- a/src/alloc2/CMakeLists.txt +++ b/src/alloc2/CMakeLists.txt @@ -15,15 +15,6 @@ set(SELF_SRCS DArenaIterator.cpp IAllocIterator_DArenaIterator.cpp - ICollector_Any.cpp - IGCObject_Any.cpp - IAllocator_DX1Collector.cpp - ICollector_DX1Collector.cpp - IAllocIterator_DX1CollectorIterator.cpp - - DX1Collector.cpp - DX1CollectorIterator.cpp - ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) diff --git a/src/alloc2/DX1Collector.cpp b/src/alloc2/DX1Collector.cpp deleted file mode 100644 index 141ce61..0000000 --- a/src/alloc2/DX1Collector.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/** @file DX1Collector.cpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#include "Allocator.hpp" -#include "arena/IAllocator_DArena.hpp" -#include "gc/DX1Collector.hpp" -#include "gc/DX1CollectorIterator.hpp" -#include "gc/generation.hpp" -#include "gc/object_age.hpp" -#include -#include -#include -#include - -namespace xo { - using xo::mm::AAllocator; - using xo::facet::with_facet; - - namespace mm { -#ifdef NOT_USING - constexpr std::uint64_t - CollectorConfig::gen_mult() const { - return 1ul << arena_config_.header_size_bits_; - } -#endif - -#ifdef NOT_USING - constexpr std::uint64_t - CollectorConfig::tseq_mult() const { - return 1ul << (gen_bits_ + arena_config_.header_size_bits_); - } -#endif - - // ----- GCRunState ----- - - GCRunState::GCRunState(generation gc_upto) - : gc_upto_{gc_upto} - {} - - GCRunState - GCRunState::gc_not_running() - { - return GCRunState(generation(0)); - } - - GCRunState - GCRunState::gc_upto(generation g) - { - return GCRunState(generation(g + 1)); - } - - // ----- DX1Collector ----- - - using size_type = xo::mm::DX1Collector::size_type; - - DX1Collector::DX1Collector(const CollectorConfig & cfg) : config_{cfg} - { - assert(config_.arena_config_.header_.size_bits_ + - config_.arena_config_.header_.age_bits_ + - config_.arena_config_.header_.tseq_bits_ <= 64); - - for (uint32_t igen = 0, ngen = cfg.n_generation_; igen < ngen; ++igen) { - space_storage_[0][igen] = DArena::map(cfg.arena_config_); - space_storage_[1][igen] = DArena::map(cfg.arena_config_); - - space_[role::to_space()][igen] = &space_storage_[0][igen]; - space_[role::from_space()][igen] = &space_storage_[1][igen]; - } - - for (uint32_t igen = cfg.n_generation_; igen < c_max_generation; ++igen) { - space_[role::to_space()][igen] = nullptr; - space_[role::from_space()][igen] = nullptr; - } - } - - bool - DX1Collector::contains(role r, const void * addr) const noexcept - { - for (generation gi{0}; gi < config_.n_generation_; ++gi) { - const DArena * arena = get_space(r, gi); - - if (arena->contains(addr)) - return true; - } - - return false; - } - - AllocError - DX1Collector::last_error() const noexcept - { - // TODO: - // need to adjust here if runtime errors - // encountered during gc. - - return get_space(role::to_space(), generation::nursery())->last_error_; - } - - namespace { - size_type - accumulate_total_aux(const DX1Collector & d, - size_t (DArena::* get_stat_fn)() const) noexcept - { - size_t z = 0; - - for (role ri : role::all()) { - for (generation gj{0}; gj < d.config_.n_generation_; ++gj) { - const DArena * arena = d.get_space(ri, gj); - - assert(arena); - - z += (arena->*get_stat_fn)(); - } - } - - return z; - } - } - - size_type - DX1Collector::reserved_total() const noexcept - { - return accumulate_total_aux(*this, &DArena::reserved); - } - - size_type - DX1Collector::size_total() const noexcept - { - return committed_total(); - } - - size_type - DX1Collector::committed_total() const noexcept - { - return accumulate_total_aux(*this, &DArena::committed); - } - - size_type - DX1Collector::available_total() const noexcept - { - return accumulate_total_aux(*this, &DArena::available); - } - - size_type - DX1Collector::allocated_total() const noexcept - { - return accumulate_total_aux(*this, &DArena::allocated); - } - - size_type - DX1Collector::header2size(header_type hdr) const noexcept - { - uint32_t z = config_.arena_config_.header_.size(hdr); - - return z; - } - - object_age - DX1Collector::header2age(header_type hdr) const noexcept - { - uint32_t age = config_.arena_config_.header_.age(hdr); - - assert(age < c_max_object_age); - - return object_age(age); - } - - uint32_t - DX1Collector::header2tseq(header_type hdr) const noexcept - { - uint32_t tseq = config_.arena_config_.header_.tseq(hdr); - - return tseq; - } - - bool - DX1Collector::is_forwarding_header(header_type hdr) const noexcept - { - /** forwarding pointer encoded as sentinel tseq **/ - return config_.arena_config_.header_.is_forwarding_tseq(hdr); - } - - auto - DX1Collector::alloc(size_type z) noexcept -> value_type - { - return with_facet::mkobj(new_space()).alloc(z); - } - - auto - DX1Collector::super_alloc(size_type z) noexcept -> value_type { - return with_facet::mkobj(new_space()).super_alloc(z); - } - - auto - DX1Collector::sub_alloc(size_type z, bool complete) noexcept -> value_type { - return with_facet::mkobj(new_space()).sub_alloc(z, complete); - } - - bool - DX1Collector::expand(size_type z) noexcept - { - if (with_facet::mkobj(to_space(generation{0})).expand(z)) - return with_facet::mkobj(from_space(generation{0})).expand(z); - - return false; - } - - AllocInfo - DX1Collector::alloc_info(value_type mem) const noexcept { - for (role ri : role::all()) { - for (generation gj{0}; gj < config_.n_generation_; ++gj) { - const DArena * arena = this->get_space(ri, gj); - - assert(arena); - - if (arena->contains(mem)) { - return arena->alloc_info(mem); - } - } - } - - // deliberately attempt on nursery to-space, to capture error info + return sentinel - return this->get_space(role::to_space(), generation{0})->alloc_info(mem); - } - - DX1CollectorIterator - DX1Collector::begin() const noexcept - { - scope log(XO_DEBUG(false)); - - const DArena * arena - = get_space(role::to_space(), - generation{0}); - - return DX1CollectorIterator(this, - generation{0}, - generation{config_.n_generation_}, - arena->begin(), - arena->end()); - } - - DX1CollectorIterator - DX1Collector::end() const noexcept { - scope log(XO_DEBUG(false)); - - generation gen_hi = generation{config_.n_generation_}; - - /** valid iterator for end points to end of last DArena. - * otherwise will interfere with working compare - * (since invalid iterators are incomparable) - **/ - - const DArena * arena - = get_space(role::to_space(), - generation(config_.n_generation_ - 1)); - DArenaIterator arena_end = arena->end(); - - return DX1CollectorIterator(this, - gen_hi, - gen_hi, - arena_end, - arena_end); - } - - void - DX1Collector::reverse_roles(generation g) noexcept { - assert(g < config_.n_generation_); - - std::swap(space_[0][g], space_[1][g]); - } - - void - DX1Collector::clear() noexcept { - for (role ri : role::all()) { - for (generation gj{0}; gj < config_.n_generation_; ++gj) { - DArena * arena = this->get_space(ri, gj); - - assert(arena); - - arena->clear(); - } - } - } - } /*namespace mm*/ -} /*namespace xo*/ - -/* end DX1Collector.cpp */ diff --git a/src/alloc2/DX1CollectorIterator.cpp b/src/alloc2/DX1CollectorIterator.cpp deleted file mode 100644 index 1c351b2..0000000 --- a/src/alloc2/DX1CollectorIterator.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/** @file DX1CollectorIterator.cpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#include "gc/DX1CollectorIterator.hpp" -#include "gc/DX1Collector.hpp" -#include -#include - -namespace xo { - namespace mm { - DX1CollectorIterator::DX1CollectorIterator(const DX1Collector * gc, - generation gen_ix, - generation gen_hi, - DArenaIterator arena_ix, - DArenaIterator arena_hi) : gc_{gc}, - gen_ix_{gen_ix}, - gen_hi_{gen_hi}, - arena_ix_{arena_ix}, - arena_hi_{arena_hi} - { - this->normalize(); - } - - void - DX1CollectorIterator::normalize() noexcept - { - scope log(XO_DEBUG(false), - xtag("gen_ix", gen_ix_), - xtag("gen_hi", gen_hi_), - xtag("arena_ix.pos", arena_ix_.pos_), - xtag("arena_hi.pos", arena_hi_.pos_)); - - /* normalize: find lowest generation with non-empty to-space */ - if (arena_ix_.pos_ == arena_hi_.pos_) { - log && log(xtag("action", "look-lub-nonempty-gen")); - - if (gen_ix_ < gen_hi_) - ++gen_ix_; - - for (; gen_ix_ < gen_hi_; ++gen_ix_) { - const DArena * arena - = gc_->get_space(role::to_space(), gen_ix_); - - assert(arena); - - arena_ix_ = arena->begin(); - arena_hi_ = arena->end(); - - if (arena_ix_ != arena_hi_) { - // normalization achieved! - break; - } - } - - log && log(xtag("gen_ix", gen_ix_), - xtag("arena_ix.pos", arena_ix_.pos_), - xtag("arena_hi.pos", arena_hi_.pos_)); - } else { - log && log(xtag("action", "noop")); - } - } - - AllocInfo - DX1CollectorIterator::deref() const noexcept - { - return arena_ix_.deref(); - } - - cmpresult - DX1CollectorIterator::compare(const DX1CollectorIterator & other_ix) const noexcept - { - scope log(XO_DEBUG(false), - xtag("is_valid", is_valid()), - xtag("other_ix.is_valid", other_ix.is_valid()) ); - - if (is_invalid() || (gc_ != other_ix.gc_)) { - log && log("incomparable!"); - return cmpresult::incomparable(); - } - - if (gen_ix_ != other_ix.gen_ix_) { - log && log(xtag("gen", gen_ix_), xtag("other.gen", other_ix.gen_ix_)); - - /* same collector, different arenas -> compare based on gen# */ - - return cmpresult::from_cmp(gen_ix_, other_ix.gen_ix_); - } - - /* both iterators refer to the same arena, - * so can compare their arena iterators directly - */ - cmpresult retval = arena_ix_.compare(other_ix.arena_ix_); - - log && log(xtag("retval", retval)); - - return retval; - } - - void - DX1CollectorIterator::next() noexcept - { - scope log(XO_DEBUG(false), - xtag("arena_ix.arena", arena_ix_.arena_), - xtag("arena_ix.pos", arena_ix_.pos_), - xtag("arena_hi.arena", arena_hi_.arena_), - xtag("arena_hi.pos", arena_hi_.pos_)); - - if (arena_ix_ != arena_hi_) { - ++arena_ix_; - - log && log(xtag("++arena_ix.pos", arena_ix_.pos_)); - - this->normalize(); - - log && log(xtag("arena_ix.arena", arena_ix_.arena_), - xtag("arena_ix.pos", arena_ix_.pos_)); - } else { - log && log(xtag("action", "arena-at-end")); - } - } - } /*namespace mm*/ -} /*namespace xo*/ - -/* end DX1CollectorIterator.cpp */ diff --git a/src/alloc2/IAllocIterator_DX1CollectorIterator.cpp b/src/alloc2/IAllocIterator_DX1CollectorIterator.cpp deleted file mode 100644 index 85609f1..0000000 --- a/src/alloc2/IAllocIterator_DX1CollectorIterator.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/** @file IAllocIterator_DX1CollectorIterator.cpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#include "gc/IAllocIterator_DX1CollectorIterator.hpp" -#include "AllocIterator.hpp" -//#include - -namespace xo { - namespace mm { - AllocInfo - IAllocIterator_DX1CollectorIterator::deref(const DX1CollectorIterator & ix) noexcept - { - return ix.deref(); - } - - cmpresult - IAllocIterator_DX1CollectorIterator::compare(const DX1CollectorIterator & ix, - const obj & other_arg) noexcept - { - /* downcast from variant */ - auto other = obj::from(other_arg); - - if (!other) - return cmpresult::incomparable(); - - DX1CollectorIterator & other_ix = *other.data(); - - return ix.compare(other_ix); - } - - void - IAllocIterator_DX1CollectorIterator::next(DX1CollectorIterator & ix) noexcept - { - ix.next(); - } - } /*namespace mm*/ -} /*namespace xo*/ - -/* end IAllocIterator_DX1CollectorIterator.cpp */ diff --git a/src/alloc2/IAllocator_DX1Collector.cpp b/src/alloc2/IAllocator_DX1Collector.cpp deleted file mode 100644 index 5ab1b00..0000000 --- a/src/alloc2/IAllocator_DX1Collector.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/** @file IAllocator_DX1Collector.cpp - * - * @author Roland Conybeare, Dec 2025 - * - * See also ICollector_DX1Collector.cpp for collector facet - **/ - -#include "gc/IAllocator_DX1Collector.hpp" -#include "gc/IAllocIterator_DX1CollectorIterator.hpp" -#include "gc/DX1CollectorIterator.hpp" -#include "arena/IAllocator_DArena.hpp" - -namespace xo { - using xo::facet::with_facet; - using std::size_t; - using std::byte; - - namespace mm { - using value_type = IAllocator_DX1Collector::value_type; - - std::string_view - IAllocator_DX1Collector::name(const DX1Collector & d) noexcept - { - return d.config_.name_; - } - - auto - IAllocator_DX1Collector::reserved(const DX1Collector & d) noexcept -> size_type - { - return d.reserved_total(); - } - - auto - IAllocator_DX1Collector::size(const DX1Collector & d) noexcept -> size_type - { - return d.size_total(); - } - - auto - IAllocator_DX1Collector::committed(const DX1Collector & d) noexcept -> size_type - { - return d.committed_total(); - } - - auto - IAllocator_DX1Collector::available(const DX1Collector & d) noexcept -> size_type - { - return d.available_total(); - } - - auto - IAllocator_DX1Collector::allocated(const DX1Collector & d) noexcept -> size_type - { - return d.allocated_total(); - } - - bool - IAllocator_DX1Collector::contains(const DX1Collector & d, const void * addr) noexcept - { - return d.contains(role::to_space(), addr); - } - - AllocError - IAllocator_DX1Collector::last_error(const DX1Collector & d) noexcept - { - return d.last_error(); - } - - auto - IAllocator_DX1Collector::alloc_range(const DX1Collector & d, - DArena & ialloc) noexcept -> range_type - { - DX1CollectorIterator * begin_ix = construct_with(ialloc, d.begin()); - DX1CollectorIterator * end_ix = construct_with(ialloc, d.end()); - - obj begin_obj = with_facet::mkobj(begin_ix); - obj end_obj = with_facet::mkobj( end_ix); - - return AllocRange(std::make_pair(begin_obj, end_obj)); - } - - auto - IAllocator_DX1Collector::alloc(DX1Collector & d, size_type z) noexcept -> value_type - { - return d.alloc(z); - } - - auto - IAllocator_DX1Collector::super_alloc(DX1Collector & d, size_type z) noexcept -> value_type - { - return d.super_alloc(z); - } - - auto - IAllocator_DX1Collector::sub_alloc(DX1Collector & d, size_type z, bool complete) noexcept -> value_type - { - return d.sub_alloc(z, complete); - } - - bool - IAllocator_DX1Collector::expand(DX1Collector & d, size_type z) noexcept - { - return d.expand(z); - } - - AllocInfo - IAllocator_DX1Collector::alloc_info(const DX1Collector & d, value_type mem) noexcept - { - return d.alloc_info(mem); - } - - void - IAllocator_DX1Collector::clear(DX1Collector & d) - { - d.clear(); - } - - void - IAllocator_DX1Collector::destruct_data(DX1Collector & d) - { - d.~DX1Collector(); - } - - } /*namespace mm*/ -} /*namespace xo*/ - -/* end IAllocator_DX1Collector.cpp */ diff --git a/src/alloc2/ICollector_Any.cpp b/src/alloc2/ICollector_Any.cpp deleted file mode 100644 index 57700ad..0000000 --- a/src/alloc2/ICollector_Any.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/** @file ICollector_Any.cpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#include "gc/ICollector_Any.hpp" -#include - -namespace xo { - using xo::facet::DVariantPlaceholder; - using xo::facet::typeseq; - using xo::facet::valid_facet_implementation; - - namespace mm { - - void - ICollector_Any::_fatal() { - /* control here on uninitialized ICollector_Any. - * Initialized instance will have specific implementation type - * e.g. ICollector_Xfer - */ - - std::cerr << "fatal" - << ": attempt to call uninitialized" - << " ICollector_Any method" - << std::endl; - std::terminate(); - } - - int32_t - ICollector_Any::s_typeseq = typeseq::id(); - - bool - ICollector_Any::_valid = valid_facet_implementation(); - - } /*namespace mm*/ -} /*namespace xo*/ - -/** end ICollector_Any.cpp */ diff --git a/src/alloc2/ICollector_DX1Collector.cpp b/src/alloc2/ICollector_DX1Collector.cpp deleted file mode 100644 index 6be5696..0000000 --- a/src/alloc2/ICollector_DX1Collector.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/** @file ICollector_DX1Collector.cpp - * - * @author Roland Conybeare, Dec 2025 - * - * See also IAllocator_DX1Collector.cpp for allocator facet - **/ - -#include "gc/ICollector_DX1Collector.hpp" -#include "GCObject.hpp" - -namespace xo { - namespace mm { - using size_type = ICollector_DX1Collector::size_type; - using std::byte; - - namespace { - size_type - stat_helper(const DX1Collector & d, - size_type (DArena::* getter)() const, - generation g, - role r) - { - const DArena * arena = d.get_space(r, g); - - if (arena) [[likely]] - return (arena->*getter)(); - - return 0; - } - } - - size_type - ICollector_DX1Collector::reserved(const DX1Collector & d, generation g, role r) - { - return stat_helper(d, &DArena::reserved, g, r); - } - - size_type - ICollector_DX1Collector::allocated(const DX1Collector & d, generation g, role r) - { - return stat_helper(d, &DArena::allocated, g, r); - } - - size_type - ICollector_DX1Collector::committed(const DX1Collector & d, generation g, role r) - { - return stat_helper(d, &DArena::committed, g, r); - } - - void - ICollector_DX1Collector::install_type(DX1Collector & d, - std::int32_t tseq, - IGCObject_Any & iface) - { - (void)d; - (void)tseq; - (void)iface; - - assert(false); - } - - void - ICollector_DX1Collector::add_gc_root(DX1Collector & d, - int32_t tseq, - Opaque * root) - { - (void)d; - (void)tseq; - (void)root; - - assert(false); - } - - void - ICollector_DX1Collector::forward_inplace(DX1Collector & d, - obj * lhs) - { - assert(d.runstate_.is_running()); - - /* - * lhs obj - * | +---------+ +---+-+----+ - * \--->| .iface | | T |G|size| header - * +---------+ object_data +---+-+----+ - * | .data x----------------->| alloc | - * +---------+ | data | - * | for | - * | instance | - * | ... | - * +----------+ - */ - - void * object_data = (byte *)(*lhs).opaque_data(); - - if (!d.contains(role::from_space(), object_data)) { - /* *lhs isn't in GC-allocated space. - * - * This happens for a modest number of global - * constant, for example DBoolean {true, false}. - * - * It's important we recognize these up front. - * Since not allocated from GC, they don't have - * an alloc-header. - */ - return; - } - - /** NOTE: for form's sake: - * better to lookup actual arena that - * allocated object data. - * - **/ - DArena * some_arena = d.to_space(generation(0)); - - DArena::header_type * p_header - = some_arena->obj2hdr(object_data); - - DArena::header_type alloc_hdr = *p_header; - - /* recover allocation size */ - std::size_t alloc_z = some_arena->config_.header_.size(alloc_hdr); - - /* need to be able to fit forwarding pointer - * in place of forwarded object. - * - * This is guaranteed anyway, by alignment rules - */ - assert(alloc_z > sizeof(uintptr_t)); - - if (d.is_forwarding_header(alloc_hdr)) { - /* *lhs already refers to a forwarding pointer */ - - /* - * lhs obj - * | +---------+ +---+-+----+ - * \--->| .iface | |FWD|G|size| alloc_hdr - * +---------+ object_data +---+-+----+ - * | .data x----------------->| x--------> - * +---------+ | | dest - * | | - * +----------+ - */ - void * dest = *(void**)object_data; - - /* update *lhs in-place */ - (*lhs).reset_opaque(dest); - } else if (check_move_policy(d, alloc_hdr, object_data)) { - /* copy object *lhs + replace with forwarding pointer */ - - /* which arena are we writing to? need allocator interface */ - - assert(false); - -#ifdef NOT_YET - // to do this need IAllocator_DX1Collector fully implemented - - void * copy = (*lhs).shallow_copy(xxx); - - xxx mm xxx; -#endif - } else { - /* object doesn't need to move. - * e.g. incremental collection + object is tenured - */ - } - } - - bool - ICollector_DX1Collector::check_move_policy(const DX1Collector & d, - header_type alloc_hdr, - void * object_data) - { - (void)object_data; - - // when gc is moving objects, to- and from- spaces have been - // reversed: forwarding pointers are located in from-space and - // refer to to-space. - - object_age age = d.header2age(alloc_hdr); - - generation g = d.config_.age2gen(age); - - assert(d.runstate_.is_running()); - - return (g < d.runstate_.gc_upto()); - } - - } /*namespace mm*/ -} /*namespace xo*/ - -/* end ICollector_DX1Collector.cpp */ diff --git a/src/alloc2/IGCObject_Any.cpp b/src/alloc2/IGCObject_Any.cpp deleted file mode 100644 index 22e1cf4..0000000 --- a/src/alloc2/IGCObject_Any.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/** @file IGCObject_Any.cpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#include "gcobject/IGCObject_Any.hpp" -#include - -namespace xo { - using xo::facet::DVariantPlaceholder; - using xo::facet::typeseq; - using xo::facet::valid_facet_implementation; - - namespace mm { - - void - IGCObject_Any::_fatal() { - std::cerr << "fatal" - << ": attempt to call uninitialized" - << " IGCObject_Any method" - << std::endl; - std::terminate(); - } - - int32_t - IGCObject_Any::s_typeseq = typeseq::id(); - - bool - IGCObject_Any::_valid = valid_facet_implementation(); - - } /*namespace mm*/ -} /*namespace xo*/ - -/* end IGCObject_Any.cpp */ diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index ac5aa84..eacd19f 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -7,15 +7,15 @@ set(UTEST_SRCS objectmodel.test.cpp arena.test.cpp DArenaIterator.test.cpp - Collector.test.cpp - DX1CollectorIterator.test.cpp +# Collector.test.cpp +# DX1CollectorIterator.test.cpp random_allocs.cpp ) if (ENABLE_TESTING) xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS}) - xo_headeronly_dependency(${UTEST_EXE} randomgen) xo_self_dependency(${UTEST_EXE} xo_alloc2) + xo_headeronly_dependency(${UTEST_EXE} randomgen) xo_headeronly_dependency(${UTEST_EXE} indentlog) xo_headeronly_dependency(${UTEST_EXE} xo_facet) xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2) diff --git a/utest/Collector.test.cpp b/utest/Collector.test.cpp deleted file mode 100644 index 119fac0..0000000 --- a/utest/Collector.test.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/** @file Collector.test.cpp - * - * @author Roland Conybeare, Dec 2025 - * - * NOTE: properly unit testing gc behavior requires - * xo-object2 dependency; - * see xo-object2/utest - **/ - -#include "Allocator.hpp" -#include "Collector.hpp" -#include "random_allocs.hpp" -#include "gc/ICollector_DX1Collector.hpp" -#include "gc/IAllocator_DX1Collector.hpp" -//#include "gc/DX1Collector.hpp" -#include -#include -#include -#include -#include -#include - -namespace xo { - using xo::mm::AAllocator; - using xo::mm::ACollector; - using xo::mm::CollectorConfig; - using xo::mm::DX1Collector; - using xo::mm::ArenaConfig; - using xo::mm::AllocHeaderConfig; - using xo::mm::generation; - using xo::mm::c_max_generation; - using xo::facet::with_facet; - using xo::scope; - - namespace ut { - // checklist - // - obj constructible [ ] - // - obj truthy [ ] - // - obj constructible [ ] - // - // - obj constructible [ ] - // - obj allocation - - TEST_CASE("collector-any-null", "[alloc2][gc][ACollector]") - { - /* empty variant collector */ - obj gc1; - - REQUIRE(!gc1); - REQUIRE(gc1.iface() != nullptr); - REQUIRE(gc1.data() == nullptr); - } - - TEST_CASE("DX1Collector-1", "[alloc2][gc][DX1Collector]") - { - ArenaConfig arena_cfg = { .name_ = "_test_unused", - .size_ = 4*1024*1024, - .store_header_flag_ = true, - .header_ = AllocHeaderConfig(0 /*guard_z*/, - 0xfd /*guard_byte*/, - 0 /*tseq_bits*/, - 0 /*age_bits*/, - 16 /*size_bits*/), }; - CollectorConfig cfg = { .arena_config_ = arena_cfg, - .n_generation_ = 2, - .gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0}} }; - - DX1Collector gc = DX1Collector{cfg}; - - generation g0 = generation{0}; - REQUIRE(gc.to_space(g0)); - REQUIRE(gc.from_space(g0)); - REQUIRE(gc.to_space(g0)->is_mapped()); - REQUIRE(gc.from_space(g0)->is_mapped()); - - generation g1 = generation{1}; - REQUIRE(gc.to_space(g1)); - REQUIRE(gc.from_space(g1)); - REQUIRE(gc.to_space(g1)->is_mapped()); - REQUIRE(gc.from_space(g1)->is_mapped()); - - /* verify from/to x N/T are unique */ - REQUIRE(gc.to_space(g0) != gc.from_space(g0)); - REQUIRE(gc.to_space(g1) != gc.to_space(g0)); - REQUIRE(gc.from_space(g1) != gc.from_space(g0)); - REQUIRE(gc.to_space(g0) != gc.from_space(g1)); - - for (generation gi = generation(2); gi < c_max_generation; ++gi) { - INFO(xtag("gi", gi)); - - REQUIRE(!gc.to_space(gi)); - REQUIRE(!gc.from_space(gi)); - - REQUIRE(!gc.space_storage_[0][gi].is_mapped()); - REQUIRE(!gc.space_storage_[1][gi].is_mapped()); - } - } - - TEST_CASE("collector-x1-obj", "[alloc2][gc]") - { - ArenaConfig arena_cfg = { .name_ = "_test_unused", - .size_ = 4*1024*1024, - .store_header_flag_ = true, - .header_ = AllocHeaderConfig(0 /*guard_z*/, - 0xfd /*guard_byte*/, - 0 /*tseq_bits*/, - 0 /*age_bits*/, - 16 /*size_bits*/), }; - CollectorConfig cfg = { .arena_config_ = arena_cfg, - .n_generation_ = 2, - .gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0}} }; - - DX1Collector gc = DX1Collector{cfg}; - - /* typed collector -- repr known at compile time */ - obj x1(&gc); - - REQUIRE(x1.iface()); - REQUIRE(x1.data()); - } - - TEST_CASE("collector-x1-facet-mkobj", "[alloc2][gc]") - { - ArenaConfig arena_cfg = { .name_ = "_test_unused", - .size_ = 4*1024*1024, - .store_header_flag_ = true, - .header_ = AllocHeaderConfig(0 /*guard_z*/, - 0xfd /*guard_byte*/, - 0 /*tseq-bits*/, - 0 /*age-bits*/, - 16 /*size-bits*/), }; - CollectorConfig cfg = { .arena_config_ = arena_cfg, - .n_generation_ = 2, - .gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0}} }; - - DX1Collector gc = DX1Collector{cfg}; - - /* typed collector -- repr inferred at compile time */ - auto x1 = with_facet::mkobj(&gc); - - REQUIRE(x1.iface()); - REQUIRE(x1.data()); - } - - TEST_CASE("collector-x1-alloc", "[alloc2][gc]") - { - scope log(XO_DEBUG(false), "DX1Collector alloc test"); - - ArenaConfig arena_cfg = { .name_ = "_test_unused", - .size_ = 4*1024*1024, - .store_header_flag_ = true, - .header_ = AllocHeaderConfig(0 /*guard_z*/, - 0xfd /*guard-byte*/, - 0 /*tseq-bits*/, - 0 /*age-bits*/, - 16 /*size-bits*/), }; - - /* collector with one generation collapses to a non-generational copying collector */ - CollectorConfig cfg = { .arena_config_ = arena_cfg, - .n_generation_ = 1, - .gc_trigger_v_ = {{64*1024, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0}} }; - - DX1Collector x1state = DX1Collector{cfg}; - - /* typed collector */ - auto x1gc = with_facet::mkobj(&x1state); - auto x1alloc = with_facet::mkobj(&x1state); - - REQUIRE(x1gc.iface()); - REQUIRE(x1gc.data()); - - REQUIRE(x1alloc.iface()); - REQUIRE(x1alloc.data()); - - rng::Seed seed; - log && log(xtag("seed", seed)); - - auto rng = rng::xoshiro256ss(seed); - - bool catch_flag = false; - REQUIRE(utest::AllocUtil::random_allocs(25, catch_flag, &rng, x1alloc)); - } - - TEST_CASE("collector-x1-alloc2", "[alloc2][gc]") - { - scope log(XO_DEBUG(false), - "DX1Collector alloc test2"); - - ArenaConfig arena_cfg = { .name_ = "_test_unused", - .size_ = 4*1024*1024, - .store_header_flag_ = true, - .header_ = AllocHeaderConfig(8 /*guard_z*/, - 0xfd /*guard-byte*/, - 0 /*tseq-bits*/, - 0 /*age-bits*/, - 16 /*size-bits*/), - }; - - /* collector with one generation collapses to a non-generational copying collector */ - CollectorConfig cfg = { .arena_config_ = arena_cfg, - .n_generation_ = 1, - .gc_trigger_v_ = {{64*1024, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0}} }; - - /* X1 allocator+collector */ - DX1Collector x1state = DX1Collector{cfg}; - - /* typed collector i/face */ - auto x1gc = with_facet::mkobj(&x1state); - /* typed allocator i/face */ - auto x1alloc = with_facet::mkobj(&x1state); - - REQUIRE(x1gc.iface()); - REQUIRE(x1gc.data()); - - REQUIRE(x1alloc.iface()); - REQUIRE(x1alloc.data()); - - rng::Seed seed; - log && log("ratio: seed=", seed); - - auto rng = rng::xoshiro256ss(seed); - - REQUIRE(utest::AllocUtil::random_allocs(25, false, &rng, x1alloc)); - } - } -} - -/* end Collector.test.cpp */ diff --git a/utest/DX1CollectorIterator.test.cpp b/utest/DX1CollectorIterator.test.cpp deleted file mode 100644 index 3ae405e..0000000 --- a/utest/DX1CollectorIterator.test.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/** @file DX1CollectorIterator.test.cpp - * - * @author Roland Conybeare, Dec 2025 - **/ - -#include "Allocator.hpp" -#include "AllocIterator.hpp" -#include "gc/DX1CollectorIterator.hpp" -#include "gc/IAllocator_DX1Collector.hpp" -#include "gc/IAllocIterator_DX1CollectorIterator.hpp" -#include "arena/ArenaConfig.hpp" -#include "padding.hpp" -#include -#include -#include - -namespace xo { - using xo::mm::AAllocator; - using xo::mm::AAllocIterator; - using xo::mm::IAllocIterator_Any; - using xo::mm::IAllocIterator_Xfer; - using xo::mm::IAllocIterator_DX1CollectorIterator; - using xo::mm::DX1Collector; - using xo::mm::DX1CollectorIterator; - using xo::mm::DArena; - using xo::mm::DArenaIterator; - using xo::mm::CollectorConfig; - using xo::mm::ArenaConfig; - using xo::mm::AllocHeaderConfig; - using xo::mm::cmpresult; - using xo::mm::padding; - using xo::facet::with_facet; - using std::byte; - - namespace ut { - TEST_CASE("IAllocIterator_Xfer_DX1CollectorIterator", "[alloc2]") - { - /* verify IAllocIterator_Xfer is constructible + satisfies concept checks */ - IAllocIterator_Xfer xfer; - REQUIRE(IAllocIterator_Xfer::_valid); - } - - TEST_CASE("DX1CollectorIterator-1", "[alloc2][gc][DX1Collector]") - { - ArenaConfig arena_cfg = { .name_ = "_test_unused", - .size_ = 4*1024*1024, - .store_header_flag_ = true, - .header_ = AllocHeaderConfig(0 /*guard_z*/, - 0xfd /*guard_byte*/, - 0 /*tseq_bits*/, - 0 /*age_bits*/, - 16 /*size_bits*/), }; - CollectorConfig cfg = { .arena_config_ = arena_cfg, - .n_generation_ = 2, - .gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0}} }; - - DX1Collector gc = DX1Collector{cfg}; - - auto ix = gc.begin(); - auto end_ix = gc.end(); - - REQUIRE(ix.is_valid()); - REQUIRE(end_ix.is_valid()); - REQUIRE(ix == end_ix); - - /* verify obj 'fat pointer' packaging */ - obj ix_vt{&ix}; - obj end_ix_vt{&end_ix}; - - REQUIRE(ix_vt.iface()); - REQUIRE(ix_vt.data()); - REQUIRE(end_ix_vt.iface()); - REQUIRE(end_ix_vt.data()); - - cmpresult cmp = ix_vt.compare(end_ix_vt); - - REQUIRE(cmp.is_equal()); - REQUIRE(ix_vt == end_ix_vt); - } - - TEST_CASE("DX1CollectorIterator-2", "[alloc2][gc][DX1Collector]") - { - scope log(XO_DEBUG(false)); - - ArenaConfig arena_cfg = { .name_ = "_test_unused", - .size_ = 4*1024*1024, - .store_header_flag_ = true, - .header_ = AllocHeaderConfig(0 /*guard_z*/, - 0xfd /*guard_byte*/, - 0 /*tseq_bits*/, - 0 /*age_bits*/, - 16 /*size_bits*/), }; - CollectorConfig cfg = { .arena_config_ = arena_cfg, - .n_generation_ = 2, - .gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0}} }; - - DX1Collector gc = DX1Collector{cfg}; - obj a1o{&gc}; - - REQUIRE(a1o.reserved() >= arena_cfg.size_); - REQUIRE(a1o.committed() == 0); - REQUIRE(a1o.available() == 0); - REQUIRE(a1o.allocated() == 0); - - size_t req_z = 13; - byte * mem = gc.alloc(req_z); - - REQUIRE(mem != nullptr); - - log && log("should have iterators separated by one alloc"); - - { - auto ix = gc.begin(); - auto end_ix = gc.end(); - - REQUIRE(ix.is_valid()); - REQUIRE(end_ix.is_valid()); - REQUIRE(ix != end_ix); - - /* verify obj 'fat pointer' packaging */ - auto ix_vt = with_facet::mkobj(&ix); - auto end_ix_vt = with_facet::mkobj(&end_ix); - - REQUIRE(ix_vt.iface()); - REQUIRE(ix_vt.data()); - REQUIRE(end_ix_vt.iface()); - REQUIRE(end_ix_vt.data()); - - cmpresult cmp = ix_vt.compare(end_ix_vt); - - REQUIRE(cmp.is_lesser()); - REQUIRE(ix_vt != end_ix_vt); - - /* we only did one alloc, should be able - * to visit it - */ - auto info = ix_vt.deref(); - - REQUIRE(info.is_valid()); - REQUIRE(info.payload().first == mem); - REQUIRE(info.size() == padding::with_padding(req_z)); - - ix_vt.next(); - - log && log(xtag("ix.gen", ix.gen_ix()), - xtag("ix.arena_ix.arena", ix.arena_ix().arena_)); - log && log(xtag("end_ix.gen", end_ix.gen_ix()), - xtag("end_ix.arena_ix.arena", end_ix.arena_ix().arena_)); - - REQUIRE(ix_vt == end_ix_vt); - } - - { - //auto range = gc.alloc_range - - DArena scratch_mm - = DArena::map( - ArenaConfig{ - .size_ = 4*1024, - .hugepage_z_ = 4*1024}); - - auto range = a1o.alloc_range(scratch_mm); - - obj ix = range.begin(); - obj end_ix = range.end(); - - REQUIRE(ix.iface()); - REQUIRE(ix.data()); - REQUIRE(end_ix.iface()); - REQUIRE(end_ix.data()); - - REQUIRE(scratch_mm.allocated() >= 2*sizeof(DArenaIterator)); - REQUIRE(scratch_mm.available() > 0); - - REQUIRE(ix.compare(ix).is_equal()); - - REQUIRE(ix != end_ix); - - { - REQUIRE(ix.deref().is_valid()); - REQUIRE(ix.deref().size() == padding::with_padding(req_z)); - - auto [payload_lo, payload_hi] = ix.deref().payload(); - - REQUIRE(payload_lo == mem); - REQUIRE(payload_hi == mem + ix.deref().size()); - } - - { - ++ix; - - REQUIRE(ix == end_ix); - } - } - - // repeat, this time using range iteration - { - DArena scratch_mm - = DArena::map( - ArenaConfig{ - .size_ = 4*1024, - .hugepage_z_ = 4*1024}); - - for (const auto & info : a1o.alloc_range(scratch_mm)) { - REQUIRE(info.is_valid()); - REQUIRE(info.size() == padding::with_padding(req_z)); - REQUIRE(info.payload().first == mem); - REQUIRE(info.payload().second == mem + info.size()); - } - } - } - } /*namespace ut*/ -} /*namespace xo*/ - -/* end DX1CollectorIterator.test.cpp */