From 3a263d7f9850b56136cf9da844b178fc5dab90e2 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 29 Mar 2026 13:44:19 -0400 Subject: [PATCH] xo-gc stack: + request-gc-statistics() primitive 1. xo-gc now depends on xo-object2. 2. use genfacet for ICollector_DX1Collector 3. moves xo-gc utest previously in xo-object2 to more natural location in xo-gc/ --- idl/Collector.json5 | 29 +++++++++++++++++------- include/xo/alloc2/gc/ACollector.hpp | 5 ++++ include/xo/alloc2/gc/ICollector_Any.hpp | 1 + include/xo/alloc2/gc/ICollector_Xfer.hpp | 3 +++ include/xo/alloc2/gc/RCollector.hpp | 3 +++ include/xo/alloc2/generation.hpp | 2 +- 6 files changed, 34 insertions(+), 9 deletions(-) diff --git a/idl/Collector.json5 b/idl/Collector.json5 index 1d34445..865d992 100644 --- a/idl/Collector.json5 +++ b/idl/Collector.json5 @@ -29,12 +29,6 @@ "A collector must also suppose the @ref AAllocator facet, see also" ], types: [ - // using typeseq = xo::facet::typeseq; // I think this is automatically provided -// { -// name: "typeseq", -// doc: ["type for an amount of memory"], -// definition: "std::size_t", -// }, // using size_type = std::size_t; { name: "size_type", @@ -87,7 +81,7 @@ name: "contains", doc: ["true if gc responsible for data at @p addr, and data belongs to role @p r"], return_type: "bool", - args:[ + args: [ {type: "role", name: "r"}, {type: "const void *", name: "addr"}, ], @@ -100,13 +94,32 @@ name: "is_type_installed", doc: ["true iff gc-aware object of type @p tseq is installed in this collector"], return_type: "bool", - args:[ + args: [ {type: "typeseq", name: "tseq"}, ], const: true, noexcept: true, attributes: [], }, + // obj summary() const noexcept; + { + name: "report_statistics", + doc: [ + "Report gc statistics, at discretion of collector implementation.", + "Creates dictionary using memory from @p report_mm.", + "If unable to comply (e.g. oom), return runtime error allocated from @p error_mm.", + "Avoiding obj return type to avoid #include cycle" + ], + return_type: "bool", + args: [ + {type: "obj", name: "report_mm"}, + {type: "obj", name: "error_mm"}, + {type: "obj *", name: "output"}, + ], + const: true, + noexcept: true, + attributes: [], + }, ], nonconst_methods: [ // bool install_type(const AGCObject & iface) diff --git a/include/xo/alloc2/gc/ACollector.hpp b/include/xo/alloc2/gc/ACollector.hpp index 0f5f91f..f156a4e 100644 --- a/include/xo/alloc2/gc/ACollector.hpp +++ b/include/xo/alloc2/gc/ACollector.hpp @@ -69,6 +69,11 @@ public: virtual bool contains(Copaque data, role r, const void * addr) const noexcept = 0; /** true iff gc-aware object of type @p tseq is installed in this collector **/ virtual bool is_type_installed(Copaque data, typeseq tseq) const noexcept = 0; + /** Report gc statistics, at discretion of collector implementation. +Creates dictionary using memory from @p report_mm. +If unable to comply (e.g. oom), return runtime error allocated from @p error_mm. +Avoiding obj return type to avoid #include cycle **/ + virtual bool report_statistics(Copaque data, obj report_mm, obj error_mm, obj * output) const noexcept = 0; // nonconst methods /** install interface @p iface for representation with typeseq @p tseq diff --git a/include/xo/alloc2/gc/ICollector_Any.hpp b/include/xo/alloc2/gc/ICollector_Any.hpp index 285467c..34f9035 100644 --- a/include/xo/alloc2/gc/ICollector_Any.hpp +++ b/include/xo/alloc2/gc/ICollector_Any.hpp @@ -64,6 +64,7 @@ namespace mm { [[noreturn]] size_type reserved(Copaque, Generation, role) const noexcept override { _fatal(); } [[noreturn]] bool contains(Copaque, role, const void *) const noexcept override { _fatal(); } [[noreturn]] bool is_type_installed(Copaque, typeseq) const noexcept override { _fatal(); } + [[noreturn]] bool report_statistics(Copaque, obj, obj, obj *) const noexcept override { _fatal(); } // nonconst methods [[noreturn]] bool install_type(Opaque, const AGCObject &) override; diff --git a/include/xo/alloc2/gc/ICollector_Xfer.hpp b/include/xo/alloc2/gc/ICollector_Xfer.hpp index b1df145..2df6006 100644 --- a/include/xo/alloc2/gc/ICollector_Xfer.hpp +++ b/include/xo/alloc2/gc/ICollector_Xfer.hpp @@ -61,6 +61,9 @@ namespace mm { bool is_type_installed(Copaque data, typeseq tseq) const noexcept override { return I::is_type_installed(_dcast(data), tseq); } + bool report_statistics(Copaque data, obj report_mm, obj error_mm, obj * output) const noexcept override { + return I::report_statistics(_dcast(data), report_mm, error_mm, output); + } // non-const methods bool install_type(Opaque data, const AGCObject & iface) override { diff --git a/include/xo/alloc2/gc/RCollector.hpp b/include/xo/alloc2/gc/RCollector.hpp index 345eb1f..ad51485 100644 --- a/include/xo/alloc2/gc/RCollector.hpp +++ b/include/xo/alloc2/gc/RCollector.hpp @@ -94,6 +94,9 @@ public: bool is_type_installed(typeseq tseq) const noexcept { return O::iface()->is_type_installed(O::data(), tseq); } + bool report_statistics(obj report_mm, obj error_mm, obj * output) const noexcept { + return O::iface()->report_statistics(O::data(), report_mm, error_mm, output); + } // non-const methods (still const in router!) bool install_type(const AGCObject & iface) { diff --git a/include/xo/alloc2/generation.hpp b/include/xo/alloc2/generation.hpp index 76ad1a8..2c83485 100644 --- a/include/xo/alloc2/generation.hpp +++ b/include/xo/alloc2/generation.hpp @@ -11,7 +11,7 @@ namespace xo { namespace mm { /** hard maximum number of generations **/ - static constexpr uint32_t c_max_generation = 2; + static constexpr uint32_t c_max_generation = 3; /** @class generation * @brief type-safe generation number