xo-interpreter: refactor for explicit gc::GC* dep

This commit is contained in:
Roland Conybeare 2025-11-24 09:55:43 -05:00
commit 2f2cb735f3
10 changed files with 89 additions and 32 deletions

View file

@ -175,6 +175,8 @@ namespace xo {
virtual void checkpoint() final override; virtual void checkpoint() final override;
virtual std::byte * alloc(std::size_t z) 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=(const ArenaAlloc &) = delete;
ArenaAlloc & operator=(ArenaAlloc &&) = delete; ArenaAlloc & operator=(ArenaAlloc &&) = delete;

View file

@ -32,7 +32,7 @@ namespace xo {
/** required by Object i/face, but never called on Forwarding1 **/ /** required by Object i/face, but never called on Forwarding1 **/
virtual Object * _shallow_copy(gc::IAlloc * mm) const final override; virtual Object * _shallow_copy(gc::IAlloc * mm) const final override;
/** required by Object i/face, but never called on Forwarding1 **/ /** 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: private:
/** the object that used to be located at this address (i.e. @c this) /** the object that used to be located at this address (i.e. @c this)

View file

@ -308,6 +308,15 @@ namespace xo {
**/ **/
virtual void assign_member(Object * parent, Object ** lhs, Object* rhs) final override; 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(std::size_t z) final override;
virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override; virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override;

View file

@ -16,7 +16,12 @@ namespace xo {
namespace gc { namespace gc {
/** @class IAllocator /** @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 { class IAlloc {
public: public:
@ -56,14 +61,28 @@ namespace xo {
/** @return true iff debug logging enabled **/ /** @return true iff debug logging enabled **/
virtual bool debug_flag() const = 0; virtual bool debug_flag() const = 0;
/** reset allocator to empty state. **/
virtual void clear() = 0;
/** remember allocator state. All currently-allocated addresses xo /** remember allocator state. All currently-allocated addresses xo
* will satisfy is_before_checkpoint(x). Subsequent allocations x * will satisfy is_before_checkpoint(x). Subsequent allocations x
* will fail is_before_checkpoint(x), until checkpoint superseded * will fail is_before_checkpoint(x), until checkpoint superseded
* by @ref clear or another call to @ref checkpoint * by @ref clear or another call to @ref checkpoint
**/ **/
virtual void checkpoint() = 0; 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 /** perform assignment
* @code * @code
* *lhs = rhs * *lhs = rhs
@ -72,8 +91,6 @@ namespace xo {
* Default implementation just does the assignment. * Default implementation just does the assignment.
**/ **/
virtual void assign_member(Object * parent, Object ** lhs, Object * rhs); 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. /** allocate @p z bytes for copy of object at @p src.
* Only used in @ref GC. Default implementation asserts and returns nullptr * Only used in @ref GC. Default implementation asserts and returns nullptr
**/ **/

View file

@ -122,15 +122,15 @@ namespace xo {
static Object * _forward(Object * src, gc::GC * gc); static Object * _forward(Object * src, gc::GC * gc);
template <typename T> template <typename T>
static void _forward_inplace(T ** src_addr) { static void _forward_inplace(T ** src_addr, gc::GC * gc) {
Object * fwd = _forward(*src_addr, _gc()); Object * fwd = _forward(*src_addr, gc);
*src_addr = reinterpret_cast<T *>(fwd); *src_addr = reinterpret_cast<T *>(fwd);
} }
template <typename T> template <typename T>
static void _forward_inplace(gp<T> & src) { static void _forward_inplace(gp<T> & src, gc::GC * gc) {
_forward_inplace<T>(src.ptr_address()); _forward_inplace<T>(src.ptr_address(), gc);
} }
/** primary workhorse for garbage collection. /** primary workhorse for garbage collection.
@ -156,10 +156,10 @@ namespace xo {
**/ **/
static Object * _deep_move(Object * src, gc::GC * gc, gc::ObjectStatistics * stats); 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 * return the new location
**/ **/
static Object * _shallow_move(Object * src, gc::GC * gc); static Object * _shallow_move(Object * src, gc::IAlloc * gc);
// Reflection support // Reflection support
@ -207,7 +207,7 @@ namespace xo {
* *
* Require: @ref mm is an instance of @ref gc::GC * 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, /** update child pointers that refer to forwarding pointers,
* replacing them with the correct destination. * replacing them with the correct destination.
@ -243,7 +243,7 @@ namespace xo {
* allocated by @ref _shallow_move * allocated by @ref _shallow_move
* *
**/ **/
virtual std::size_t _forward_children() = 0; virtual std::size_t _forward_children(gc::GC * gc) = 0;
}; };
template <typename T> template <typename T>

View file

@ -356,6 +356,14 @@ namespace xo {
return free_ptr_ - checkpoint_; return free_ptr_ - checkpoint_;
} }
bool
ArenaAlloc::check_owned(Object * src) const
{
byte * addr = reinterpret_cast<byte *>(src);
return (lo_ <= addr) && (addr < hi_);
}
bool bool
ArenaAlloc::debug_flag() const ArenaAlloc::debug_flag() const
{ {

View file

@ -60,7 +60,7 @@ namespace xo {
// LCOV_EXCL_START // LCOV_EXCL_START
std::size_t std::size_t
Forwarding1::_forward_children() { Forwarding1::_forward_children(gc::GC *) {
assert(false); assert(false);
return 0; return 0;
} }

View file

@ -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 void
GC::swap_nursery() GC::swap_nursery()
{ {

View file

@ -47,6 +47,18 @@ namespace xo {
*lhs = rhs; *lhs = rhs;
} }
bool
IAlloc::check_owned(Object * /*obj*/) const
{
return false;
}
bool
IAlloc::check_move(Object * /*obj*/) const
{
return false;
}
// LCOV_EXCL_START // LCOV_EXCL_START
std::byte * std::byte *
IAlloc::alloc_gc_copy(std::size_t /*z*/, const void * /*src*/) IAlloc::alloc_gc_copy(std::size_t /*z*/, const void * /*src*/)

View file

@ -14,9 +14,9 @@ operator new (std::size_t z, const xo::Cpof & cpof)
{ {
using xo::gc::GC; using xo::gc::GC;
GC * gc = reinterpret_cast<GC *>(cpof.mm_); //GC * gc = reinterpret_cast<GC *>(cpof.mm_);
return gc->alloc_gc_copy(z, cpof.src_); return cpof.mm_->alloc_gc_copy(z, cpof.src_);
} }
namespace xo { namespace xo {
@ -32,18 +32,15 @@ namespace xo {
if (src->_is_forwarded()) if (src->_is_forwarded())
return src->_offset_destination(src); 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 */ /* don't move tenured objects during incremental collection */
return src; return src;
} }
Object::_shallow_move(src, gc);
/* *src is now a forwarding pointer to copy in to-space */
return src->_offset_destination(src);
} }
Object * Object *
@ -59,9 +56,7 @@ namespace xo {
if (retval) if (retval)
return retval; return retval;
bool full_move = gc->runstate().full_move(); if (!gc->check_move(from_src)) {
if (!full_move && gc->tospace_generation_of(from_src) == gc::generation_result::tenured) {
/** incremental collection does not move already-tenured objects **/ /** incremental collection does not move already-tenured objects **/
return from_src; return from_src;
} }
@ -70,7 +65,8 @@ namespace xo {
* To-space: * To-space:
* *
* to_lo = start of 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) * (also implies this GC cycle put it there)
* g,G = grey objects. An object x is gray if it's in to-space, * g,G = grey objects. An object x is gray if it's in to-space,
* but possibly has >0 black children * but possibly has >0 black children
@ -141,7 +137,7 @@ namespace xo {
// update per-class stats here // 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, // must pad xz to multiple of word size,
// to match behavior of LinearAlloc::alloc() // to match behavior of LinearAlloc::alloc()
@ -163,12 +159,12 @@ namespace xo {
} /*deep_move*/ } /*deep_move*/
Object * 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. /* filter for source objects that are owned by GC.
* Care required though -- during GC from/to spaces have been swapped already * 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); Object * dest = src->_shallow_copy(gc);