xo-alloc/xo-allocutil/include/xo/allocutil/IObject.hpp

136 lines
4.6 KiB
C++

/** @file IObject.hpp
*
* @author Roland Conybeare, Nov 2025
**/
#pragma once
#include <cstddef>
#include <cstdint>
namespace xo {
namespace gc { class IAlloc; }
/** @class IObject
* @brief Base interface for GC interaction
*
* Classes that can be collected inherit this api
* indirectly via xo::Object (see xo/alloc/Object.hpp)
**/
class IObject {
public:
/** impl inheriting this class must provide gc hooks **/
static constexpr bool _requires_gc_hooks = true;
/** impl inheriting this class must use write barriers
* (so that GC allocator can remember cross-generational pointers)
**/
static constexpr bool _requires_write_barrier = true;
/** GC write barrier:
* assign value @p rhs to member @p *lhs of @p parent.
* Identifiy and remember cross-generational pointers.
*
* Expect Allocator is xo::gc::allocator<T> (see IAlloc.hpp)
**/
template <typename T, typename Allocator>
void _gc_assign_member(T ** lhs,
T * rhs,
Allocator & alloc)
{
static_assert(std::is_convertible_v<decltype(*lhs), IObject*>);
alloc.impl_.mm_->assign_member(this, reinterpret_cast<IObject **>(lhs), rhs);
}
/** true iff this object represents a forwarding pointer.
* Forwarding pointers are exclusively created by the garbage collector;
* forwarding pointers (and only forwarding pointers) return true here.
**/
virtual bool _is_forwarded() const { return false; }
/** offset for uncommon situation where pointer address is offset from object
* base address
**/
virtual IObject * _offset_destination(IObject * src) const { return src; };
/** replace this object with a forwarding pointer referring to @p dest.
**/
virtual void _forward_to(IObject * dest) = 0;
/** if this object represents a forwarding pointer, return its new location.
* forwarding pointers belong to the garbage collector implementation.
* (if you have to ask -- no, your class is not a forwarding pointer)
* all other objects return nullptr here.
**/
virtual IObject * _destination() { return nullptr; }
/** return amount of storage (including padding) consumed by this object,
* excluding immediate Object-pointer children
**/
virtual std::size_t _shallow_size() const = 0;
/** if subject is allocated by GC:
* - create copy C in to-space
* - destination C will be nursery|tenured depending on location of this.
* else
* - return this to disengage from GC
*
* Require: @ref mm is an instance of @ref gc::GC
**/
virtual IObject * _shallow_copy(gc::IAlloc * gc) const = 0;
/** update child pointers that refer to forwarding pointers,
* replacing them with the correct destination.
* See @ref Object::deep_move
*
* this gray object, located in to-space.
* fwd1 forwarding objects.
* Located in from-space. Invalid at end of GC cycle.
* p1,p2 source pointers.
* D1,D2 already-forwarded objects. located in to-space.
*
* before:
* this fwd1
* +----+ +-+
* | p1 ----->|x|-------> D1
* | | +-+
* | |
* | p2 ----------------> D2
* +----+
*
* after:
* this
* +----+
* | p1 ----------------> D1
* | |
* | |
* | p2 ----------------> D2
* +----+
*
* this is now white
*
* @return shallow size of *this. Must exactly match the amount of memory in to-space
* allocated by @ref _shallow_move
*
**/
virtual std::size_t _forward_children(gc::IAlloc * gc) = 0;
};
static_assert(std::is_destructible_v<IObject>, "IObject must be destructible");
/** @class Cpof
* @brief argument to operator new used for garbage collector evacuation phase
*
* Tag overloaded operator new to activate allocation policy based on location
* in memory of source object.
**/
class Cpof {
public:
explicit Cpof(gc::IAlloc * mm, const IObject * src) : mm_{mm}, src_{src} {}
gc::IAlloc * mm_ = nullptr;
const void * src_ = nullptr;
};
}
/* end IObject.hpp */