diff --git a/xo-gc/include/xo/gc/DX1Collector.hpp b/xo-gc/include/xo/gc/DX1Collector.hpp index 429d2204..9c7c69da 100644 --- a/xo-gc/include/xo/gc/DX1Collector.hpp +++ b/xo-gc/include/xo/gc/DX1Collector.hpp @@ -204,6 +204,12 @@ namespace xo { /** true iff original alloc has been replaced by a forwarding pointer **/ bool is_forwarding_header(header_type hdr) const noexcept; + /** true iff type with id @p tseq has known metadata + * (i.e. has appeared in preceding call to install_type + * for this collector) + **/ + bool is_type_installed(typeseq tseq) const noexcept; + /** Retreive bookkeeping info for allocation at @p mem. **/ AllocInfo alloc_info(value_type mem) const noexcept; diff --git a/xo-gc/include/xo/gc/detail/ACollector.hpp b/xo-gc/include/xo/gc/detail/ACollector.hpp index 0298ad2e..69f10085 100644 --- a/xo-gc/include/xo/gc/detail/ACollector.hpp +++ b/xo-gc/include/xo/gc/detail/ACollector.hpp @@ -42,6 +42,8 @@ namespace xo { generation g, role r) const noexcept = 0; virtual size_type committed(Copaque d, generation g, role r) const noexcept = 0; + virtual bool is_type_installed(Copaque d, + typeseq tseq) const noexcept = 0; /** install interface @p iface for representation with typeseq @p tseq * in collector @p d. diff --git a/xo-gc/include/xo/gc/detail/ICollector_Any.hpp b/xo-gc/include/xo/gc/detail/ICollector_Any.hpp index 5b0ce66d..3b0b10a0 100644 --- a/xo-gc/include/xo/gc/detail/ICollector_Any.hpp +++ b/xo-gc/include/xo/gc/detail/ICollector_Any.hpp @@ -34,6 +34,7 @@ namespace xo { [[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(); } + [[noreturn]] bool is_type_installed(Copaque, typeseq) const noexcept override { _fatal(); } // non-const methods [[noreturn]] bool install_type(Opaque, const AGCObject &) noexcept override { _fatal(); } diff --git a/xo-gc/include/xo/gc/detail/ICollector_DX1Collector.hpp b/xo-gc/include/xo/gc/detail/ICollector_DX1Collector.hpp index 19392896..233eeba0 100644 --- a/xo-gc/include/xo/gc/detail/ICollector_DX1Collector.hpp +++ b/xo-gc/include/xo/gc/detail/ICollector_DX1Collector.hpp @@ -30,6 +30,7 @@ namespace xo { struct ICollector_DX1Collector { using size_type = std::size_t; using header_type = DArena::header_type; + using typeseq = xo::facet::typeseq; static bool check_move_policy(const DX1Collector & d, header_type alloc_hdr, @@ -40,6 +41,7 @@ namespace xo { 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 bool is_type_installed(const DX1Collector & d, typeseq tseq); static bool install_type(DX1Collector & d, const AGCObject & iface); static void add_gc_root(DX1Collector & d, int32_t tseq, Opaque * root); diff --git a/xo-gc/include/xo/gc/detail/ICollector_Xfer.hpp b/xo-gc/include/xo/gc/detail/ICollector_Xfer.hpp index d184cb9b..352dc82f 100644 --- a/xo-gc/include/xo/gc/detail/ICollector_Xfer.hpp +++ b/xo-gc/include/xo/gc/detail/ICollector_Xfer.hpp @@ -41,6 +41,9 @@ namespace xo { size_type committed(Copaque d, generation g, role r) const noexcept override { return I::committed(_dcast(d), g, r); } + bool is_type_installed(Copaque d, typeseq tseq) const noexcept override { + return I::is_type_installed(_dcast(d), tseq); + } // non-const methods diff --git a/xo-gc/include/xo/gc/detail/RCollector.hpp b/xo-gc/include/xo/gc/detail/RCollector.hpp index e6eeca6a..bd28dc66 100644 --- a/xo-gc/include/xo/gc/detail/RCollector.hpp +++ b/xo-gc/include/xo/gc/detail/RCollector.hpp @@ -17,6 +17,7 @@ namespace xo { using ObjectType = Object; using DataPtr = Object::DataPtr; using size_type = std::size_t; + using typeseq = ACollector::typeseq; //using value_type = std::byte *; RCollector() = default; @@ -26,6 +27,7 @@ namespace xo { 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); } + bool is_type_installed(typeseq tseq) const noexcept { return O::iface()->is_type_installed(O::data(), tseq); } bool install_type(const AGCObject & iface) { return O::iface()->install_type(O::data(), iface); } void add_gc_root(int32_t tseq, Opaque * root) { O::iface()->add_gc_root(O::data(), tseq, root); } diff --git a/xo-gc/src/gc/DX1Collector.cpp b/xo-gc/src/gc/DX1Collector.cpp index edfd842c..d9e7e283 100644 --- a/xo-gc/src/gc/DX1Collector.cpp +++ b/xo-gc/src/gc/DX1Collector.cpp @@ -198,6 +198,19 @@ namespace xo { return config_.arena_config_.header_.is_forwarding_tseq(hdr); } + bool + DX1Collector::is_type_installed(typeseq tseq) const noexcept + { + if (object_types_.committed() < sizeof(AGCObject) * (tseq.seqno() + 1)) + return false; + + AGCObject * v = reinterpret_cast(object_types_.lo_); + + void * vtable = *(void **)&(v[tseq.seqno()]); + + return (vtable != nullptr); + } + bool DX1Collector::install_type(const AGCObject & meta) noexcept { diff --git a/xo-gc/src/gc/ICollector_DX1Collector.cpp b/xo-gc/src/gc/ICollector_DX1Collector.cpp index 5428e75b..82e5e937 100644 --- a/xo-gc/src/gc/ICollector_DX1Collector.cpp +++ b/xo-gc/src/gc/ICollector_DX1Collector.cpp @@ -47,6 +47,12 @@ namespace xo { return stat_helper(d, &DArena::committed, g, r); } + bool + ICollector_DX1Collector::is_type_installed(const DX1Collector & d, typeseq tseq) + { + return d.is_type_installed(tseq); + } + bool ICollector_DX1Collector::install_type(DX1Collector & d, const AGCObject & iface) diff --git a/xo-object2/utest/X1Collector.test.cpp b/xo-object2/utest/X1Collector.test.cpp index 742e460c..2afe158d 100644 --- a/xo-object2/utest/X1Collector.test.cpp +++ b/xo-object2/utest/X1Collector.test.cpp @@ -5,22 +5,29 @@ #include "DFloat.hpp" #include "DList.hpp" +#include "object2_register_types.hpp" #include "IGCObject_DFloat.hpp" #include "IGCObject_DList.hpp" #include #include + #include +#include + #include #include #include namespace ut { + using xo::scm::object2_register_types; using xo::scm::DList; using xo::scm::DFloat; using xo::mm::AAllocator; + using xo::mm::ACollector; + using xo::mm::AllocHeader; using xo::mm::AllocInfo; using xo::mm::AGCObject; using xo::mm::DX1Collector; @@ -79,6 +86,8 @@ namespace ut { DX1Collector gc(cfg); + DArena * to_0 = nullptr; + /* verify initial collector state */ { REQUIRE(gc.name() == "x1_test"); @@ -95,21 +104,25 @@ namespace ut { REQUIRE(from_0->reserved() >= tc.tenured_z_); REQUIRE(from_0->reserved() < tc.tenured_z_ + from_0->page_z_); REQUIRE(from_0->reserved() % from_0->page_z_ == 0); + REQUIRE(from_0->allocated() == 0); DArena * from_1 = gc.get_space(role::from_space(), generation{1}); REQUIRE(from_1 != nullptr); REQUIRE(from_1->reserved() == from_0->reserved()); + REQUIRE(from_1->allocated() == 0); - DArena * to_0 = gc.get_space(role::to_space(), generation{0}); + to_0 = gc.get_space(role::to_space(), generation{0}); REQUIRE(to_0 != nullptr); REQUIRE(to_0->reserved() == from_0->reserved()); + REQUIRE(to_0->allocated() == 0); DArena * to_1 = gc.get_space(role::to_space(), generation{1}); REQUIRE(to_1 != nullptr); REQUIRE(to_1->reserved() == to_0->reserved()); + REQUIRE(to_1->allocated() == 0); DArena * from_2 = gc.get_space(role::from_space(), generation{2}); @@ -125,13 +138,30 @@ namespace ut { /* attempt allocation */ auto gc_o = with_facet::mkobj(&gc); + auto c_o = with_facet::mkobj(&gc); + + /* register object types */ + bool ok = object2_register_types(c_o); + + REQUIRE(ok); + + ok = c_o.is_type_installed(typeseq::id()); + REQUIRE(ok); + + ok = c_o.is_type_installed(typeseq::id()); + REQUIRE(ok); DFloat * x0 = DFloat::make(gc_o, 3.1415927); auto x0_o = with_facet::mkobj(x0); + REQUIRE(to_0->allocated() == sizeof(AllocHeader) + sizeof(DFloat)); + DList * l0 = DList::list(gc_o, x0_o); auto l0_o = with_facet::mkobj(l0); + REQUIRE(to_0->allocated() == (sizeof(AllocHeader) + sizeof(DFloat) + + sizeof(AllocHeader) + sizeof(DList))); + { { REQUIRE(x0_o.iface() != nullptr); @@ -152,6 +182,7 @@ namespace ut { REQUIRE(l0_o.data() != nullptr); REQUIRE(gc.contains(role::to_space(), l0_o.data())); + /* check alloc info for newly-allocated object */ AllocInfo info = gc.alloc_info((std::byte *)l0_o.data()); REQUIRE(info.age() == 0); @@ -162,6 +193,7 @@ namespace ut { } } + /* no GC roots, so GC is trivial */ } catch (std::exception & ex) { std::cerr << "caught exception: " << ex.what() << std::endl; REQUIRE(false);