diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index 302d9c0a..ed3fd59c 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -175,6 +175,8 @@ namespace xo { virtual void checkpoint() final override; virtual std::byte * alloc(std::size_t z) final override; + virtual bool check_owned(Object * src) const final override; + ArenaAlloc & operator=(const ArenaAlloc &) = delete; ArenaAlloc & operator=(ArenaAlloc &&) = delete; diff --git a/include/xo/alloc/Forwarding1.hpp b/include/xo/alloc/Forwarding1.hpp index 77e081f9..88ca849a 100644 --- a/include/xo/alloc/Forwarding1.hpp +++ b/include/xo/alloc/Forwarding1.hpp @@ -32,7 +32,7 @@ namespace xo { /** required by Object i/face, but never called on Forwarding1 **/ virtual Object * _shallow_copy(gc::IAlloc * mm) const final override; /** required by Object i/face, but never called on Forwarding1 **/ - virtual std::size_t _forward_children() final override; + virtual std::size_t _forward_children(gc::GC * mm) final override; private: /** the object that used to be located at this address (i.e. @c this) diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index 8e12990e..423dd2f8 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -308,6 +308,15 @@ namespace xo { **/ virtual void assign_member(Object * parent, Object ** lhs, Object* rhs) final override; + /** during GC check for source objects owned by GC. + * See Object::_shallow_move. + **/ + virtual bool check_owned(Object * src) const final override; + /** queries during GC to determine if object at address @p src should move: + * - full GC -> always + * - incr GC -> if not tenured + **/ + virtual bool check_move(Object * src) const final override; virtual std::byte * alloc(std::size_t z) final override; virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override; diff --git a/include/xo/alloc/IAlloc.hpp b/include/xo/alloc/IAlloc.hpp index 0b6791f0..fceaca94 100644 --- a/include/xo/alloc/IAlloc.hpp +++ b/include/xo/alloc/IAlloc.hpp @@ -16,7 +16,12 @@ namespace xo { namespace gc { /** @class IAllocator - * @brief memory allocation interface with limited garbaga collector support + * @brief memory allocation interface with limited garbage collector support + * + * Garbage collector support methods: + * - checkpoint() + * - assign_member() + * - alloc_gc_copy() **/ class IAlloc { public: @@ -56,14 +61,28 @@ namespace xo { /** @return true iff debug logging enabled **/ virtual bool debug_flag() const = 0; - /** reset allocator to empty state. **/ - virtual void clear() = 0; /** remember allocator state. All currently-allocated addresses xo * will satisfy is_before_checkpoint(x). Subsequent allocations x * will fail is_before_checkpoint(x), until checkpoint superseded * by @ref clear or another call to @ref checkpoint **/ virtual void checkpoint() = 0; + + /** allocate @p z bytes of memory. returns pointer to first address **/ + virtual std::byte * alloc(std::size_t z) = 0; + /** reset allocator to empty state. **/ + virtual void clear() = 0; + + // ----- GC-specific methods ----- + + /** true iff this allocator owns object at address @p src. + * Use to assist Object::_shallow_move + **/ + virtual bool check_owned(Object * src) const; + /** true iff object at address @p src must move as part of + * in-progress collection phase + **/ + virtual bool check_move(Object * src) const; /** perform assignment * @code * *lhs = rhs @@ -72,8 +91,6 @@ namespace xo { * Default implementation just does the assignment. **/ virtual void assign_member(Object * parent, Object ** lhs, Object * rhs); - /** allocate @p z bytes of memory. returns pointer to first address **/ - virtual std::byte * alloc(std::size_t z) = 0; /** allocate @p z bytes for copy of object at @p src. * Only used in @ref GC. Default implementation asserts and returns nullptr **/ diff --git a/include/xo/alloc/Object.hpp b/include/xo/alloc/Object.hpp index 849cf9bb..f1d03225 100644 --- a/include/xo/alloc/Object.hpp +++ b/include/xo/alloc/Object.hpp @@ -122,15 +122,15 @@ namespace xo { static Object * _forward(Object * src, gc::GC * gc); template - static void _forward_inplace(T ** src_addr) { - Object * fwd = _forward(*src_addr, _gc()); + static void _forward_inplace(T ** src_addr, gc::GC * gc) { + Object * fwd = _forward(*src_addr, gc); *src_addr = reinterpret_cast(fwd); } template - static void _forward_inplace(gp & src) { - _forward_inplace(src.ptr_address()); + static void _forward_inplace(gp & src, gc::GC * gc) { + _forward_inplace(src.ptr_address(), gc); } /** primary workhorse for garbage collection. @@ -156,10 +156,10 @@ namespace xo { **/ static Object * _deep_move(Object * src, gc::GC * gc, gc::ObjectStatistics * stats); - /** copy @p src to to-space, and replace original with forwarding pointer to new location. + /** copy @p src to to-space. Overwrite original with forwarding pointer to new location. * return the new location **/ - static Object * _shallow_move(Object * src, gc::GC * gc); + static Object * _shallow_move(Object * src, gc::IAlloc * gc); // Reflection support @@ -207,7 +207,7 @@ namespace xo { * * Require: @ref mm is an instance of @ref gc::GC **/ - virtual Object * _shallow_copy(gc::IAlloc * mm) const = 0; + virtual Object * _shallow_copy(gc::IAlloc * gc) const = 0; /** update child pointers that refer to forwarding pointers, * replacing them with the correct destination. @@ -243,7 +243,7 @@ namespace xo { * allocated by @ref _shallow_move * **/ - virtual std::size_t _forward_children() = 0; + virtual std::size_t _forward_children(gc::GC * gc) = 0; }; template diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index c06b9518..15078a0e 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -356,6 +356,14 @@ namespace xo { return free_ptr_ - checkpoint_; } + bool + ArenaAlloc::check_owned(Object * src) const + { + byte * addr = reinterpret_cast(src); + + return (lo_ <= addr) && (addr < hi_); + } + bool ArenaAlloc::debug_flag() const { diff --git a/src/alloc/Forwarding1.cpp b/src/alloc/Forwarding1.cpp index b4a44ff6..2cc183d5 100644 --- a/src/alloc/Forwarding1.cpp +++ b/src/alloc/Forwarding1.cpp @@ -60,7 +60,7 @@ namespace xo { // LCOV_EXCL_START std::size_t - Forwarding1::_forward_children() { + Forwarding1::_forward_children(gc::GC *) { assert(false); return 0; } diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index c78768fb..bb556620 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -559,6 +559,19 @@ namespace xo { } } + bool + GC::check_owned(Object * src) const + { + return this->fromspace_contains(src); + } + + bool + GC::check_move(Object * src) const + { + return (this->runstate().full_move() + || (this->tospace_generation_of(src) != gc::generation_result::tenured)); + } + void GC::swap_nursery() { diff --git a/src/alloc/IAlloc.cpp b/src/alloc/IAlloc.cpp index 8fe4789a..9754fb47 100644 --- a/src/alloc/IAlloc.cpp +++ b/src/alloc/IAlloc.cpp @@ -47,6 +47,18 @@ namespace xo { *lhs = rhs; } + bool + IAlloc::check_owned(Object * /*obj*/) const + { + return false; + } + + bool + IAlloc::check_move(Object * /*obj*/) const + { + return false; + } + // LCOV_EXCL_START std::byte * IAlloc::alloc_gc_copy(std::size_t /*z*/, const void * /*src*/) diff --git a/src/alloc/Object.cpp b/src/alloc/Object.cpp index 309e0886..560f941b 100644 --- a/src/alloc/Object.cpp +++ b/src/alloc/Object.cpp @@ -14,9 +14,9 @@ operator new (std::size_t z, const xo::Cpof & cpof) { using xo::gc::GC; - GC * gc = reinterpret_cast(cpof.mm_); + //GC * gc = reinterpret_cast(cpof.mm_); - return gc->alloc_gc_copy(z, cpof.src_); + return cpof.mm_->alloc_gc_copy(z, cpof.src_); } namespace xo { @@ -32,18 +32,15 @@ namespace xo { if (src->_is_forwarded()) return src->_offset_destination(src); - bool full_move = gc->runstate().full_move(); + if (gc->check_move(src)) { + Object::_shallow_move(src, gc); - if (!full_move && (gc->tospace_generation_of(src) == gc::generation_result::tenured)) { + /* *src is now a forwarding pointer to a copy in to-space */ + return src->_offset_destination(src); + } else { /* don't move tenured objects during incremental collection */ return src; } - - Object::_shallow_move(src, gc); - - /* *src is now a forwarding pointer to copy in to-space */ - - return src->_offset_destination(src); } Object * @@ -59,9 +56,7 @@ namespace xo { if (retval) return retval; - bool full_move = gc->runstate().full_move(); - - if (!full_move && gc->tospace_generation_of(from_src) == gc::generation_result::tenured) { + if (!gc->check_move(from_src)) { /** incremental collection does not move already-tenured objects **/ return from_src; } @@ -70,7 +65,8 @@ namespace xo { * To-space: * * to_lo = start of to-space - * w,W = white objects. An object x is white if x + all immediate children of x are in to-space + * w,W = white objects. An object x is white if x + * + all immediate children of x are in to-space * (also implies this GC cycle put it there) * g,G = grey objects. An object x is gray if it's in to-space, * but possibly has >0 black children @@ -141,7 +137,7 @@ namespace xo { // update per-class stats here - std::size_t xz = x->_forward_children(); + std::size_t xz = x->_forward_children(gc); // must pad xz to multiple of word size, // to match behavior of LinearAlloc::alloc() @@ -163,12 +159,12 @@ namespace xo { } /*deep_move*/ Object * - Object::_shallow_move(Object * src, gc::GC * gc) + Object::_shallow_move(Object * src, gc::IAlloc * gc) { /* filter for source objects that are owned by GC. * Care required though -- during GC from/to spaces have been swapped already */ - if (gc->fromspace_contains(src)) + if (gc->check_owned(src)) { Object * dest = src->_shallow_copy(gc);