xo-object2: utest: ++ allocation in collector utest
This commit is contained in:
parent
6bd33bd900
commit
3f1470f938
18 changed files with 196 additions and 26 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -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)); }
|
||||
///@}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 <>
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -237,6 +237,11 @@ namespace xo {
|
|||
* New allocs always in gen0 to-space
|
||||
**/
|
||||
value_type sub_alloc(size_type z, bool complete) noexcept;
|
||||
/** Allocate copy of source object at @p src.
|
||||
* Source must be owned by this collector instance.
|
||||
* Copy will have incremented age.
|
||||
**/
|
||||
value_type alloc_copy(value_type src) noexcept;
|
||||
/** expand gen0 committed size to at least @p z.
|
||||
**/
|
||||
bool expand(size_type z) noexcept;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ namespace xo {
|
|||
static value_type alloc(DX1Collector & d, typeseq t, size_type z) noexcept;
|
||||
static value_type super_alloc(DX1Collector & d, typeseq t, size_type z) noexcept;
|
||||
static value_type sub_alloc(DX1Collector & d, size_type z, bool complete) noexcept;
|
||||
static value_type alloc_copy(DX1Collector & d, value_type src) noexcept;
|
||||
/** expand gen0 spaces (both from-space and to-space) **/
|
||||
static bool expand(DX1Collector & d, size_type z) noexcept;
|
||||
|
||||
|
|
|
|||
|
|
@ -231,6 +231,11 @@ namespace xo {
|
|||
return with_facet<AAllocator>::mkobj(new_space()).sub_alloc(z, complete);
|
||||
}
|
||||
|
||||
auto
|
||||
DX1Collector::alloc_copy(value_type src) noexcept -> value_type {
|
||||
return with_facet<AAllocator>::mkobj(new_space()).alloc_copy(src);
|
||||
}
|
||||
|
||||
bool
|
||||
DX1Collector::expand(size_type z) noexcept
|
||||
{
|
||||
|
|
|
|||
|
|
@ -102,6 +102,12 @@ namespace xo {
|
|||
return d.sub_alloc(z, complete);
|
||||
}
|
||||
|
||||
auto
|
||||
IAllocator_DX1Collector::alloc_copy(DX1Collector & d, value_type src) noexcept -> value_type
|
||||
{
|
||||
return d.alloc_copy(src);
|
||||
}
|
||||
|
||||
bool
|
||||
IAllocator_DX1Collector::expand(DX1Collector & d, size_type z) noexcept
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,10 +5,29 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <xo/alloc2/Allocator.hpp>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
using DFloat = double;
|
||||
} /*nmaespace obj*/
|
||||
struct DFloat {
|
||||
using AAllocator = xo::mm::AAllocator;
|
||||
|
||||
explicit DFloat(double x) : value_{x} {}
|
||||
|
||||
/** allocate boxed value @p x using memory from @p mm **/
|
||||
static DFloat * make(obj<AAllocator> mm,
|
||||
double x);
|
||||
|
||||
double value() const noexcept { return value_; }
|
||||
|
||||
operator double() const noexcept { return value_; }
|
||||
|
||||
private:
|
||||
|
||||
/** boxed floating-oint value **/
|
||||
double value_;
|
||||
};
|
||||
} /*nmaespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end DFloat.hpp */
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@
|
|||
* @author Roland Conybeare, Dec 2025
|
||||
**/
|
||||
|
||||
#include "xo/gc/GCObject.hpp"
|
||||
#pragma once
|
||||
|
||||
#include <xo/gc/GCObject.hpp>
|
||||
//#include "xo/alloc2/gcobject/RGCObject.hpp"
|
||||
#include "xo/facet/obj.hpp"
|
||||
#include <xo/facet/obj.hpp>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ set(SELF_SRCS
|
|||
ISequence_Any.cpp
|
||||
ISequence_DList.cpp
|
||||
DList.cpp
|
||||
DFloat.cpp
|
||||
object2_register_types.cpp
|
||||
)
|
||||
|
||||
|
|
|
|||
24
xo-object2/src/object2/DFloat.cpp
Normal file
24
xo-object2/src/object2/DFloat.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/** @file DFloat.cpp
|
||||
*
|
||||
* @author Roland Conybeare, Dec 2025
|
||||
**/
|
||||
|
||||
#include "DFloat.hpp"
|
||||
|
||||
namespace xo {
|
||||
using xo::facet::typeseq;
|
||||
|
||||
namespace scm {
|
||||
DFloat *
|
||||
DFloat::make(obj<AAllocator> mm,
|
||||
double x)
|
||||
{
|
||||
void * mem = mm.alloc(typeseq::id<DFloat>(),
|
||||
sizeof(DFloat));
|
||||
|
||||
return new (mem) DFloat(x);
|
||||
}
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end DFloat.cpp */
|
||||
|
|
@ -3,17 +3,35 @@
|
|||
* @author Roland Conybeare, Dec 2025
|
||||
**/
|
||||
|
||||
#include "DFloat.hpp"
|
||||
#include "DList.hpp"
|
||||
|
||||
#include "IGCObject_DFloat.hpp"
|
||||
#include "IGCObject_DList.hpp"
|
||||
|
||||
#include <xo/gc/Collector.hpp>
|
||||
#include <xo/gc/DX1Collector.hpp>
|
||||
#include <xo/gc/detail/IAllocator_DX1Collector.hpp>
|
||||
#include <xo/alloc2/AllocInfo.hpp>
|
||||
#include <xo/alloc2/padding.hpp>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace ut {
|
||||
using xo::scm::DList;
|
||||
using xo::scm::DFloat;
|
||||
using xo::mm::AAllocator;
|
||||
using xo::mm::AllocInfo;
|
||||
using xo::mm::AGCObject;
|
||||
using xo::mm::DX1Collector;
|
||||
using xo::mm::DArena;
|
||||
using xo::mm::CollectorConfig;
|
||||
using xo::mm::ArenaConfig;
|
||||
using xo::mm::generation;
|
||||
using xo::mm::role;
|
||||
using xo::mm::padding;
|
||||
using xo::facet::with_facet;
|
||||
using xo::facet::typeseq;
|
||||
|
||||
namespace {
|
||||
struct testcase_x1 {
|
||||
|
|
@ -61,6 +79,7 @@ namespace ut {
|
|||
|
||||
DX1Collector gc(cfg);
|
||||
|
||||
/* verify initial collector state */
|
||||
{
|
||||
REQUIRE(gc.name() == "x1_test");
|
||||
|
||||
|
|
@ -105,6 +124,43 @@ namespace ut {
|
|||
}
|
||||
|
||||
/* attempt allocation */
|
||||
auto gc_o = with_facet<AAllocator>::mkobj(&gc);
|
||||
|
||||
DFloat * x0 = DFloat::make(gc_o, 3.1415927);
|
||||
auto x0_o = with_facet<AGCObject>::mkobj(x0);
|
||||
|
||||
DList * l0 = DList::list(gc_o, x0_o);
|
||||
auto l0_o = with_facet<AGCObject>::mkobj(l0);
|
||||
|
||||
{
|
||||
{
|
||||
REQUIRE(x0_o.iface() != nullptr);
|
||||
REQUIRE(x0_o.data() != nullptr);
|
||||
REQUIRE(gc.contains(role::to_space(), x0_o.data()));
|
||||
|
||||
/* check alloc info for newly-allocated object */
|
||||
AllocInfo info = gc.alloc_info((std::byte *)x0_o.data());
|
||||
|
||||
REQUIRE(info.age() == 0);
|
||||
REQUIRE(info.tseq() == typeseq::id<DFloat>().seqno());
|
||||
REQUIRE(info.size() >= sizeof(DFloat));
|
||||
REQUIRE(info.size() < sizeof(DFloat) + padding::c_alloc_alignment);
|
||||
}
|
||||
|
||||
{
|
||||
REQUIRE(l0_o.iface() != nullptr);
|
||||
REQUIRE(l0_o.data() != nullptr);
|
||||
REQUIRE(gc.contains(role::to_space(), l0_o.data()));
|
||||
|
||||
AllocInfo info = gc.alloc_info((std::byte *)l0_o.data());
|
||||
|
||||
REQUIRE(info.age() == 0);
|
||||
REQUIRE(info.tseq() == typeseq::id<DList>().seqno());
|
||||
REQUIRE(info.size() >= sizeof(DList));
|
||||
REQUIRE(info.size() < sizeof(DList) + padding::c_alloc_alignment);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} catch (std::exception & ex) {
|
||||
std::cerr << "caught exception: " << ex.what() << std::endl;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue