xo-gc stack: coverage improvement + related tidying

This commit is contained in:
Roland Conybeare 2026-05-11 09:27:24 -04:00
commit e1e48612af
6 changed files with 157 additions and 1 deletions

View file

@ -80,8 +80,10 @@ namespace xo {
void ** lhs_data, void ** lhs_data,
AGCObject * rhs_iface, AGCObject * rhs_iface,
void * rhs_data); void * rhs_data);
#ifdef OBSOLETE
/** invoke destructor **/ /** invoke destructor **/
static void destruct_data(DX1Collector & d); static void destruct_data(DX1Collector & d);
#endif
}; };
} /*namespace mm*/ } /*namespace mm*/

View file

@ -144,11 +144,13 @@ namespace xo {
d.barrier_assign_aux(parent, lhs_iface, lhs_data, rhs_iface, rhs_data); d.barrier_assign_aux(parent, lhs_iface, lhs_data, rhs_iface, rhs_data);
} }
#ifdef OBSOLETE
void void
IAllocator_DX1Collector::destruct_data(DX1Collector & d) IAllocator_DX1Collector::destruct_data(DX1Collector & d)
{ {
d.~DX1Collector(); d.~DX1Collector();
} }
#endif
} /*namespace mm*/ } /*namespace mm*/
} /*namespace xo*/ } /*namespace xo*/

View file

@ -14,6 +14,7 @@ set(UTEST_SRCS
DMockCollector.cpp DMockCollector.cpp
ICollector_DMockCollector.cpp ICollector_DMockCollector.cpp
MockCollector.test.cpp
MlsTestutil.cpp MlsTestutil.cpp
GcosTestutil.cpp GcosTestutil.cpp

View file

@ -58,6 +58,7 @@ namespace xo {
/* empty variant collector */ /* empty variant collector */
obj<ACollector> gc1; obj<ACollector> gc1;
REQUIRE(!gc1._has_null_vptr());
REQUIRE(!gc1); REQUIRE(!gc1);
REQUIRE(gc1.iface() != nullptr); REQUIRE(gc1.iface() != nullptr);
REQUIRE(gc1.data() == nullptr); REQUIRE(gc1.data() == nullptr);
@ -150,6 +151,12 @@ namespace xo {
/* typed collector -- repr known at compile time */ /* typed collector -- repr known at compile time */
obj<ACollector, DX1Collector> x1(&gc); obj<ACollector, DX1Collector> x1(&gc);
REQUIRE(!x1._has_null_vptr());
REQUIRE(x1.iface());
REQUIRE(x1.data());
x1._drop();
REQUIRE(x1.iface()); REQUIRE(x1.iface());
REQUIRE(x1.data()); REQUIRE(x1.data());
} }
@ -182,6 +189,11 @@ namespace xo {
REQUIRE(x1.iface()); REQUIRE(x1.iface());
REQUIRE(x1.data()); REQUIRE(x1.data());
x1._drop();
REQUIRE(x1.iface());
REQUIRE(x1.data());
} }
TEST_CASE("collector-x1-alloc", "[alloc2][gc]") TEST_CASE("collector-x1-alloc", "[alloc2][gc]")
@ -238,6 +250,11 @@ namespace xo {
bool catch_flag = false; bool catch_flag = false;
REQUIRE(utest::AllocUtil::random_allocs(c_n_alloc, c_max_alloc_payload, REQUIRE(utest::AllocUtil::random_allocs(c_n_alloc, c_max_alloc_payload,
catch_flag, &rng, x1alloc)); catch_flag, &rng, x1alloc));
x1gc._drop();
REQUIRE(x1gc.iface());
REQUIRE(x1gc.data());
} }
TEST_CASE("collector-x1-alloc2", "[alloc2][gc]") TEST_CASE("collector-x1-alloc2", "[alloc2][gc]")
@ -298,6 +315,11 @@ namespace xo {
// just testing ability to work as a low-level allocator // just testing ability to work as a low-level allocator
REQUIRE(utest::AllocUtil::random_allocs(c_n_alloc, c_max_alloc_payload, REQUIRE(utest::AllocUtil::random_allocs(c_n_alloc, c_max_alloc_payload,
c_debug_flag, &rng, x1alloc)); c_debug_flag, &rng, x1alloc));
x1gc._drop();
REQUIRE(x1gc.iface());
REQUIRE(x1gc.data());
} }
namespace { namespace {

View file

@ -0,0 +1,119 @@
/** @file MockCollector.test.cpp
*
* @author Roland Conybeare, May 2026
**/
#include "MockCollector.hpp"
#include <xo/gc/X1VerifyStats.hpp>
#include <xo/object2/Integer.hpp>
#include <xo/alloc2/Collector.hpp>
#include <xo/alloc2/Arena.hpp>
#include <catch2/catch.hpp>
namespace ut {
using xo::scm::DInteger;
using xo::mm::ACollector;
using xo::mm::DMockCollector;
using xo::mm::MutationLogConfig;
using xo::mm::MutationLogStore;
using xo::mm::GCObjectStoreConfig;
using xo::mm::GCObjectStore;
using xo::mm::AGCObject;
using xo::mm::Generation;
using xo::mm::Role;
using xo::mm::X1VerifyStats;
using xo::mm::AAllocator;
using xo::mm::ArenaConfig;
using xo::mm::DArena;
using xo::facet::obj;
// Gilding the lily here.
// The only reason to 'test' MockCollector is to suppress
// false positives on coverage reports.
// Don't care about MockCollector itself, but it also shows up
// in ICollector_Xfer, at least on the osx/clang toolchain
TEST_CASE("MockCollector-1", "[MockCollector]")
{
// need to create a {gcos, mls} pair
constexpr uint32_t c_space_z = 64*1024;
constexpr uint32_t c_n_gen = 1;
constexpr uint32_t c_n_survive = 0;
X1VerifyStats verify_stats;
GCObjectStoreConfig gcos_config{ArenaConfig()
.with_name("gcos-arena-name-notused")
.with_size(c_space_z)
.with_store_header_flag(true),
c_n_gen,
c_n_survive,
64*1024 /*object_type_z*/,
false /*debug_flag*/};
DArena report_arena{ArenaConfig().with_name("report-arena")
.with_size(64*1024)
.with_store_header_flag(true)};
DArena error_arena{ArenaConfig().with_name("error-arena")
.with_size(64*1024)
.with_store_header_flag(true)};
MutationLogConfig mls_config{c_n_gen,
1024 /*mlog_z*/,
false /*mlog_enabled_flag*/,
false /*debug_flag*/};
GCObjectStore gcos{gcos_config, &verify_stats};
MutationLogStore mls{mls_config, &gcos};
DMockCollector mock(&mls, &gcos);
auto mockgc = obj<ACollector,DMockCollector>(&mock);
auto report_mm = obj<AAllocator,DArena>(&report_arena);
auto error_mm = obj<AAllocator,DArena>(&error_arena);
REQUIRE(mockgc.reserved(Generation::g0(), Role::to_space()) == c_space_z);
{
int dummy;
REQUIRE(mockgc.locate_address(&dummy) == -1);
REQUIRE(mockgc.contains(Role::to_space(), &dummy) == false);
}
{
obj<AGCObject> rpt;
{
// stub
REQUIRE(mockgc.report_statistics(report_mm, error_mm, &rpt) == false);
REQUIRE(report_mm.allocated() == 0);
}
{
mockgc.report_object_types(report_mm, error_mm, &rpt);
REQUIRE(rpt);
rpt.reset();
report_mm.clear();
}
{
mockgc.report_object_ages(report_mm, error_mm, &rpt);
REQUIRE(rpt);
rpt.reset();
report_mm.clear();
}
}
{
auto g0_from = gcos.from_space(Generation::g0());
REQUIRE(g0_from);
auto g0_from_mm = obj<AAllocator,DArena>(g0_from);
// note: we don't need object types in gcos for this test,
// since we're not traversing the object graph
auto x = DInteger::box(g0_from_mm, 42);
REQUIRE(x);
auto x_copy = mockgc.alloc_copy((std::byte*)x.data());
REQUIRE(x_copy);
}
}
} /*namespace ut*/
/* end MockCollector.test.cpp */

View file

@ -119,7 +119,8 @@ namespace ut {
DX1Collector gc(cfg); DX1Collector gc(cfg);
CollectorTypeRegistry::instance().install_types(obj<ACollector,DX1Collector>(&gc)); CollectorTypeRegistry::instance()
.install_types(obj<ACollector,DX1Collector>(&gc));
DArena * to_0 = nullptr; DArena * to_0 = nullptr;
@ -219,6 +220,9 @@ namespace ut {
+ sizeof(AllocHeader) + sizeof(DInteger) + sizeof(AllocHeader) + sizeof(DInteger)
+ sizeof(AllocHeader) + sizeof(DList))); + sizeof(AllocHeader) + sizeof(DList)));
auto to0_commit_z = to_0->committed();
auto to0_reserved_z = to_0->reserved();
{ {
{ {
REQUIRE(x0_o.iface() != nullptr); REQUIRE(x0_o.iface() != nullptr);
@ -285,6 +289,12 @@ namespace ut {
REQUIRE((void*)l0_o.data()->head_.data() == (void*)x0_o.data()); REQUIRE((void*)l0_o.data()->head_.data() == (void*)x0_o.data());
REQUIRE((void*)l0_o.data()->rest_ == (void*)DList::_nil()); REQUIRE((void*)l0_o.data()->rest_ == (void*)DList::_nil());
Generation g0 = Generation::g0();
REQUIRE(c_o.committed(g0, Role::to_space()) == to0_commit_z);
REQUIRE(c_o.reserved(g0, Role::to_space()) == to0_reserved_z);
REQUIRE(c_o.locate_address(x0_o.data()) >= 0);
REQUIRE(c_o.contains(Role::to_space(), x0_o.data()));
} catch (std::exception & ex) { } catch (std::exception & ex) {
std::cerr << "caught exception: " << ex.what() << std::endl; std::cerr << "caught exception: " << ex.what() << std::endl;
REQUIRE(false); REQUIRE(false);