diff --git a/include/xo/alloc2/AllocHeaderConfig.hpp b/include/xo/alloc2/AllocHeaderConfig.hpp index 3c2a8f7..754a5c9 100644 --- a/include/xo/alloc2/AllocHeaderConfig.hpp +++ b/include/xo/alloc2/AllocHeaderConfig.hpp @@ -51,6 +51,19 @@ namespace xo { age_bits_{a}, size_bits_{z} {} + /** create header tuple (@p t, @p a, @p z) + * with typeseq @p t, age @p a, size @p z + **/ + std::uint64_t mkheader(std::uint64_t t, + std::uint64_t a, + std::uint64_t z) const noexcept { + uint64_t tseq_bits = (t << (age_bits_ + size_bits_)) & tseq_mask(); + uint64_t age_bits = (a << size_bits_) & age_mask(); + uint64_t size_bits = z & size_mask();; + + return (tseq_bits | age_bits | size_bits); + } + std::uint64_t tseq_mask() const noexcept { // e.g. // FF FF FF 00 00 00 00 00 diff --git a/include/xo/alloc2/alloc/AAllocator.hpp b/include/xo/alloc2/alloc/AAllocator.hpp index 26056fb..0fce475 100644 --- a/include/xo/alloc2/alloc/AAllocator.hpp +++ b/include/xo/alloc2/alloc/AAllocator.hpp @@ -135,6 +135,11 @@ namespace xo { * zero @p z. **/ virtual value_type sub_alloc(Opaque d, size_type z, bool complete_flag) const = 0; + /** Allocate copy of an existing object @p src. + * Existing object must be contained in @p d. + * NOTE: load bearing for copying garbage collector. + **/ + virtual value_type alloc_copy(Opaque d, value_type src) const = 0; /** reset allocator @p d to empty state. **/ virtual void clear(Opaque d) const = 0; /** Destruct allocator @p d. diff --git a/include/xo/alloc2/alloc/IAllocator_Any.hpp b/include/xo/alloc2/alloc/IAllocator_Any.hpp index df3d18e..b45e765 100644 --- a/include/xo/alloc2/alloc/IAllocator_Any.hpp +++ b/include/xo/alloc2/alloc/IAllocator_Any.hpp @@ -53,6 +53,7 @@ namespace xo { [[noreturn]] value_type alloc(Opaque, typeseq, std::size_t) const override { _fatal(); } [[noreturn]] value_type super_alloc(Opaque, typeseq, std::size_t) const override { _fatal(); } [[noreturn]] value_type sub_alloc(Opaque, std::size_t, bool) const override { _fatal(); } + [[noreturn]] value_type alloc_copy(Opaque, value_type) const override { _fatal(); } [[noreturn]] void clear(Opaque) const override { _fatal(); } [[noreturn]] void destruct_data(Opaque) const override { _fatal(); } diff --git a/include/xo/alloc2/alloc/IAllocator_Xfer.hpp b/include/xo/alloc2/alloc/IAllocator_Xfer.hpp index 7d23f2d..790bcdc 100644 --- a/include/xo/alloc2/alloc/IAllocator_Xfer.hpp +++ b/include/xo/alloc2/alloc/IAllocator_Xfer.hpp @@ -70,6 +70,8 @@ namespace xo { bool complete_flag) const override { return I::sub_alloc(_dcast(d), z, complete_flag); } + value_type alloc_copy(Opaque d, + value_type src) const override { return I::alloc_copy(_dcast(d), src); } void clear(Opaque d) const override { return I::clear(_dcast(d)); } void destruct_data(Opaque d) const override { return I::destruct_data(_dcast(d)); } ///@} diff --git a/include/xo/alloc2/alloc/RAllocator.hpp b/include/xo/alloc2/alloc/RAllocator.hpp index e39afe8..2e9e7a8 100644 --- a/include/xo/alloc2/alloc/RAllocator.hpp +++ b/include/xo/alloc2/alloc/RAllocator.hpp @@ -45,6 +45,7 @@ namespace xo { value_type sub_alloc(size_type z, bool complete_flag) noexcept { return O::iface()->sub_alloc(O::data(), z, complete_flag); } + value_type alloc_copy(value_type src) noexcept { return O::iface()->alloc_copy(O::data(), src); } bool expand(size_type z) { return O::iface()->expand(O::data(), z); } static bool _valid; diff --git a/include/xo/alloc2/arena/DArena.hpp b/include/xo/alloc2/arena/DArena.hpp index efaf768..45556d9 100644 --- a/include/xo/alloc2/arena/DArena.hpp +++ b/include/xo/alloc2/arena/DArena.hpp @@ -190,12 +190,18 @@ namespace xo { **/ value_type sub_alloc(size_type z, bool complete_flag); + /** alloc copy of @p src **/ + value_type alloc_copy(value_type src); + /** capture error information: advance error count + set last_error **/ void capture_error(error err, size_type target_z = 0) const; /** alloc driver. shared by alloc(), super_alloc(), sub_alloc() **/ - value_type _alloc(std::size_t req_z, alloc_mode mode); + value_type _alloc(std::size_t req_z, + alloc_mode mode, + typeseq tseq, + uint32_t age); /** expand committed space in arena @p d * to size at least @p z diff --git a/include/xo/alloc2/arena/IAllocator_DArena.hpp b/include/xo/alloc2/arena/IAllocator_DArena.hpp index d7d5c58..9f18adc 100644 --- a/include/xo/alloc2/arena/IAllocator_DArena.hpp +++ b/include/xo/alloc2/arena/IAllocator_DArena.hpp @@ -70,14 +70,10 @@ namespace xo { * @p complete_flag to true. **/ static value_type sub_alloc(DArena &, size_type z, bool complete_flag); + /** allocate copy of @p src in arena @p d. **/ + static value_type alloc_copy(DArena & d, value_type src); static void clear(DArena &); static void destruct_data(DArena &); - - private: - /** alloc driver. shared by alloc(), super_alloc(), sub_alloc() **/ - static value_type _alloc(DArena &, - size_type z, - DArena::alloc_mode mode); }; // template <> diff --git a/src/alloc2/DArena.cpp b/src/alloc2/DArena.cpp index 62dce15..82557e4 100644 --- a/src/alloc2/DArena.cpp +++ b/src/alloc2/DArena.cpp @@ -17,6 +17,8 @@ namespace xo { using xo::facet::typeseq; using std::byte; + using std::cerr; + using std::endl; using std::size_t; namespace mm { @@ -241,8 +243,8 @@ namespace xo { last_error_ = AllocError(); } - DArena::header_type * - DArena::obj2hdr(void * obj) noexcept + auto + DArena::obj2hdr(void * obj) noexcept -> header_type * { assert(config_.store_header_flag_); @@ -260,9 +262,11 @@ namespace xo { byte * header_mem = mem - sizeof(AllocHeader); +#ifdef OBSOLETE // relying on cross-alloc header shenanigans in DX1Collector if (!this->contains(header_mem)) { this->capture_error(error::alloc_info_address); } +#endif AllocHeader * header = (AllocHeader *)header_mem; @@ -320,10 +324,7 @@ namespace xo { * exactly 1 header per alloc() call. * - store_header_flag follows configuration */ - - (void)t; - - return _alloc(req_z, alloc_mode::standard); + return _alloc(req_z, alloc_mode::standard, t, 0 /*age*/); } std::byte * @@ -338,7 +339,9 @@ namespace xo { (void)t; return _alloc(req_z, - alloc_mode::super); + alloc_mode::super, + t, + 0 /*age*/); } std::byte * @@ -354,8 +357,29 @@ namespace xo { return _alloc(req_z, (complete_flag ? alloc_mode::sub_complete - : alloc_mode::sub_incomplete)); + : alloc_mode::sub_incomplete), + typeseq::anon() /*typeseq: ignored*/, + 0 /*age - ignored */); + } + std::byte * + DArena::alloc_copy(std::byte * src) + { + /* NOTE: allocator that owns src must have the same header configuration */ + + assert(config_.store_header_flag_); + + /* src will come from an allocator other than this one; + * we rely on header layout from destination + * allocator -> assumes compatible header config + */ + AllocInfo src_info = alloc_info(src); + + size_t req_z = src_info.size(); + typeseq tseq = typeseq(src_info.tseq()); + uint32_t age = src_info.age(); + + return _alloc(req_z, alloc_mode::standard, tseq, age + 1); } void @@ -373,7 +397,10 @@ namespace xo { } byte * - DArena::_alloc(std::size_t req_z, alloc_mode mode) + DArena::_alloc(std::size_t req_z, + alloc_mode mode, + typeseq tseq, + uint32_t age) { scope log(XO_DEBUG(config_.debug_flag_)); @@ -433,11 +460,12 @@ namespace xo { * reminder: * important to store padded size for correct arena iteration */ - uint64_t header = req_z + dz; + uint64_t header = (req_z + dz); if (store_header_flag) { if (config_.header_.is_size_enabled()) [[likely]] { + header = this->config_.header_.mkheader(tseq.seqno(), age, req_z + dz); hz = sizeof(header); } else { /* req_z doesn't fit in configured header_size_mask bits */ diff --git a/src/alloc2/IAllocator_DArena.cpp b/src/alloc2/IAllocator_DArena.cpp index 12a4a40..ed95624 100644 --- a/src/alloc2/IAllocator_DArena.cpp +++ b/src/alloc2/IAllocator_DArena.cpp @@ -133,12 +133,11 @@ namespace xo { return s.sub_alloc(req_z, complete_flag); } - byte * - IAllocator_DArena::_alloc(DArena & s, - std::size_t req_z, - DArena::alloc_mode mode) + std::byte * + IAllocator_DArena::alloc_copy(DArena &s, + value_type src) { - return s._alloc(req_z, mode); + return s.alloc_copy(src); } void