xo-alloc + xo-allocutil: refactor to shrink dep surface area
This commit is contained in:
parent
8d4649c6cf
commit
540b43d971
34 changed files with 479 additions and 323 deletions
|
|
@ -90,6 +90,7 @@ add_subdirectory(xo-unit)
|
||||||
add_subdirectory(xo-pyunit)
|
add_subdirectory(xo-pyunit)
|
||||||
add_subdirectory(xo-callback)
|
add_subdirectory(xo-callback)
|
||||||
#
|
#
|
||||||
|
add_subdirectory(xo-allocutil)
|
||||||
add_subdirectory(xo-alloc)
|
add_subdirectory(xo-alloc)
|
||||||
add_subdirectory(xo-object)
|
add_subdirectory(xo-object)
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "IAlloc.hpp"
|
#include "xo/allocutil/IAlloc.hpp"
|
||||||
#include "ObjectStatistics.hpp"
|
#include "ObjectStatistics.hpp"
|
||||||
|
|
||||||
namespace xo {
|
namespace xo {
|
||||||
|
|
@ -175,8 +175,8 @@ namespace xo {
|
||||||
virtual void clear() final override;
|
virtual void clear() final override;
|
||||||
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(IObject * src) const 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;
|
||||||
|
|
|
||||||
|
|
@ -19,18 +19,18 @@ namespace xo {
|
||||||
**/
|
**/
|
||||||
class Forwarding1 : public Object {
|
class Forwarding1 : public Object {
|
||||||
public:
|
public:
|
||||||
explicit Forwarding1(gp<Object> dest);
|
explicit Forwarding1(gp<IObject> dest);
|
||||||
|
|
||||||
// inherited from Object..
|
// inherited from Object..
|
||||||
virtual TaggedPtr self_tp() const final override;
|
virtual TaggedPtr self_tp() const final override;
|
||||||
virtual void display(std::ostream & os) const final override;
|
virtual void display(std::ostream & os) const final override;
|
||||||
virtual bool _is_forwarded() const final override { return true; }
|
virtual bool _is_forwarded() const final override { return true; }
|
||||||
virtual Object * _offset_destination(Object * src) const final override;
|
virtual IObject * _offset_destination(IObject * src) const final override;
|
||||||
virtual Object * _destination() final override;
|
virtual IObject * _destination() 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 _shallow_size() const final override;
|
virtual std::size_t _shallow_size() const final override;
|
||||||
/** 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 IObject * _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(gc::IAlloc * mm) final override;
|
virtual std::size_t _forward_children(gc::IAlloc * mm) final override;
|
||||||
|
|
||||||
|
|
@ -47,7 +47,7 @@ namespace xo {
|
||||||
* UB revealed when GC traverses a pointer that relies on the 2nd
|
* UB revealed when GC traverses a pointer that relies on the 2nd
|
||||||
* vtable to index virtual methods.
|
* vtable to index virtual methods.
|
||||||
**/
|
**/
|
||||||
gp<Object> dest_;
|
gp<IObject> dest_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /*namespace obj*/
|
} /*namespace obj*/
|
||||||
|
|
|
||||||
|
|
@ -88,29 +88,30 @@ namespace xo {
|
||||||
|
|
||||||
class MutationLogEntry {
|
class MutationLogEntry {
|
||||||
public:
|
public:
|
||||||
MutationLogEntry(Object * parent, Object ** lhs) : parent_{parent}, lhs_{lhs} {}
|
MutationLogEntry(IObject * parent, IObject ** lhs)
|
||||||
|
: parent_{parent}, lhs_{lhs} {}
|
||||||
|
|
||||||
Object * parent() const { return parent_; }
|
IObject * parent() const { return parent_; }
|
||||||
Object ** lhs() const { return lhs_; }
|
IObject ** lhs() const { return lhs_; }
|
||||||
|
|
||||||
Object * child() const { return *lhs_; }
|
IObject * child() const { return *lhs_; }
|
||||||
|
|
||||||
bool is_child_forwarded() const;
|
bool is_child_forwarded() const;
|
||||||
bool is_parent_forwarded() const;
|
bool is_parent_forwarded() const;
|
||||||
|
|
||||||
Object * parent_destination() const;
|
IObject * parent_destination() const;
|
||||||
|
|
||||||
/** Flag obsolete mutation.
|
/** Flag obsolete mutation.
|
||||||
* Future proofing, never happens for regular objects
|
* Future proofing, never happens for regular objects
|
||||||
**/
|
**/
|
||||||
bool is_dead() const { return false; }
|
bool is_dead() const { return false; }
|
||||||
|
|
||||||
MutationLogEntry update_parent_moved(Object * parent_to) const;
|
MutationLogEntry update_parent_moved(IObject * parent_to) const;
|
||||||
void fixup_parent_child_moved(Object * child_to) { *lhs_ = child_to; }
|
void fixup_parent_child_moved(IObject * child_to) { *lhs_ = child_to; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Object * parent_;
|
IObject * parent_ = nullptr;
|
||||||
Object ** lhs_;
|
IObject ** lhs_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
using MutationLog = std::vector<MutationLogEntry>;
|
using MutationLog = std::vector<MutationLogEntry>;
|
||||||
|
|
@ -235,15 +236,15 @@ namespace xo {
|
||||||
/** add gc root at address @p addr . Gc will keep alive anything reachable
|
/** add gc root at address @p addr . Gc will keep alive anything reachable
|
||||||
* from @c *addr
|
* from @c *addr
|
||||||
**/
|
**/
|
||||||
void add_gc_root(Object ** addr);
|
void add_gc_root(IObject ** addr);
|
||||||
/** reverse the effect of previous call to @ref add_gc_root **/
|
/** reverse the effect of previous call to @ref add_gc_root **/
|
||||||
void remove_gc_root(Object ** addr);
|
void remove_gc_root(IObject ** addr);
|
||||||
|
|
||||||
/** convenience wrapper **/
|
/** convenience wrapper **/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void add_gc_root_dwim(gp<T> * p) { this->add_gc_root(reinterpret_cast<Object**>(p->ptr_address())); }
|
void add_gc_root_dwim(gp<T> * p) { this->add_gc_root(reinterpret_cast<IObject**>(p->ptr_address())); }
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void remove_gc_root_dwim(gp<T> * p) { this->remove_gc_root(reinterpret_cast<Object**>(p->ptr_address())); }
|
void remove_gc_root_dwim(gp<T> * p) { this->remove_gc_root(reinterpret_cast<IObject**>(p->ptr_address())); }
|
||||||
|
|
||||||
/** may optionally use this to observe GC copy phase.
|
/** may optionally use this to observe GC copy phase.
|
||||||
* Will be invoked once _per surviving object_, so not cheap.
|
* Will be invoked once _per surviving object_, so not cheap.
|
||||||
|
|
@ -308,17 +309,17 @@ namespace xo {
|
||||||
* @param lhs. address of a member variable within the allocation of @p parent.
|
* @param lhs. address of a member variable within the allocation of @p parent.
|
||||||
* @param rhs. new target for @p *lhs
|
* @param rhs. new target for @p *lhs
|
||||||
**/
|
**/
|
||||||
virtual void assign_member(Object * parent, Object ** lhs, Object* rhs) final override;
|
virtual void assign_member(IObject * parent, IObject ** lhs, IObject* rhs) final override;
|
||||||
|
|
||||||
/** during GC check for source objects owned by GC.
|
/** during GC check for source objects owned by GC.
|
||||||
* See Object::_shallow_move.
|
* See Object::_shallow_move.
|
||||||
**/
|
**/
|
||||||
virtual bool check_owned(Object * src) const final override;
|
virtual bool check_owned(IObject * src) const final override;
|
||||||
/** queries during GC to determine if object at address @p src should move:
|
/** queries during GC to determine if object at address @p src should move:
|
||||||
* - full GC -> always
|
* - full GC -> always
|
||||||
* - incr GC -> if not tenured
|
* - incr GC -> if not tenured
|
||||||
**/
|
**/
|
||||||
virtual bool check_move(Object * src) const final override;
|
virtual bool check_move(IObject * 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;
|
||||||
|
|
||||||
|
|
@ -349,7 +350,7 @@ namespace xo {
|
||||||
/** scan to-space for object statistics before GC */
|
/** scan to-space for object statistics before GC */
|
||||||
void capture_object_statistics(generation upto, capture_phase phase);
|
void capture_object_statistics(generation upto, capture_phase phase);
|
||||||
/** copy object **/
|
/** copy object **/
|
||||||
void copy_object(Object ** addr, generation upto, ObjectStatistics * object_stats);
|
void copy_object(IObject ** addr, generation upto, ObjectStatistics * object_stats);
|
||||||
/** copy everything reachable from global gc roots **/
|
/** copy everything reachable from global gc roots **/
|
||||||
void copy_globals(generation g);
|
void copy_globals(generation g);
|
||||||
/** review mutation log; may discover+rescue reachable objects.
|
/** review mutation log; may discover+rescue reachable objects.
|
||||||
|
|
@ -426,7 +427,7 @@ namespace xo {
|
||||||
* Application can introduce new root object pointers at any time provided GC not running,
|
* Application can introduce new root object pointers at any time provided GC not running,
|
||||||
* but cannot withdraw them.
|
* but cannot withdraw them.
|
||||||
**/
|
**/
|
||||||
std::vector<Object**> gc_root_v_;
|
std::vector<IObject**> gc_root_v_;
|
||||||
|
|
||||||
/** log cross-generational and cross-checkpoint mutations.
|
/** log cross-generational and cross-checkpoint mutations.
|
||||||
* These need to be adjusted on next incremental collection
|
* These need to be adjusted on next incremental collection
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#include "xo/reflect/TaggedPtr.hpp"
|
#include "xo/reflect/TaggedPtr.hpp"
|
||||||
#include "IAlloc.hpp"
|
#include "IAlloc.hpp"
|
||||||
|
#include "xo/allocutil/IObject.hpp"
|
||||||
|
#include "xo/allocutil/gc_ptr.hpp"
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
@ -16,71 +18,6 @@ namespace xo {
|
||||||
class ObjectStatistics;
|
class ObjectStatistics;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class gc_ptr;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
using gp = gc_ptr<T>;
|
|
||||||
|
|
||||||
/** wrapper for a pointer to garbage-collector-eligible T.
|
|
||||||
* Application code will usually use the alias template gp<T>
|
|
||||||
**/
|
|
||||||
template <typename T>
|
|
||||||
class gc_ptr {
|
|
||||||
public:
|
|
||||||
using element_type = T;
|
|
||||||
|
|
||||||
public:
|
|
||||||
gc_ptr() = default;
|
|
||||||
gc_ptr(T * p) : ptr_{p} {}
|
|
||||||
gc_ptr(const gc_ptr & x) : ptr_{x.ptr_} {}
|
|
||||||
|
|
||||||
/** create from gc_ptr to some related type @tparam S **/
|
|
||||||
template <typename S>
|
|
||||||
gc_ptr(const gc_ptr<S> & x) : ptr_{x.ptr()} {}
|
|
||||||
|
|
||||||
/** runtime downcast. shorthand for dynamic_cast<T*> **/
|
|
||||||
template <typename S>
|
|
||||||
static gc_ptr<T> from(const gc_ptr<S> & x) { return gc_ptr<T>{dynamic_cast<T*>(x.ptr())}; }
|
|
||||||
|
|
||||||
/** convenience for static asserts **/
|
|
||||||
static constexpr bool is_gc_ptr = true;
|
|
||||||
/** see also: xo/refcnt/Refcounted.hpp **/
|
|
||||||
static constexpr bool is_rc_ptr = false;
|
|
||||||
|
|
||||||
static bool is_eq(gc_ptr x1, gc_ptr x2) {
|
|
||||||
std::uintptr_t u1 = reinterpret_cast<std::uintptr_t>(x1.ptr());
|
|
||||||
std::uintptr_t u2 = reinterpret_cast<std::uintptr_t>(x2.ptr());
|
|
||||||
|
|
||||||
// multiple inheritance shenanigans.
|
|
||||||
// (allow interface pointers separated by one pointer)
|
|
||||||
|
|
||||||
if (u1 >= u2)
|
|
||||||
return (u1 <= u2 + sizeof(std::uintptr_t));
|
|
||||||
else
|
|
||||||
return (u2 <= u1 + sizeof(std::uintptr_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** (for consistency's sake) **/
|
|
||||||
T * get() const { return ptr_; }
|
|
||||||
|
|
||||||
T * ptr() const { return ptr_; }
|
|
||||||
T ** ptr_address() { return &ptr_; }
|
|
||||||
|
|
||||||
bool is_null() const { return ptr_ == nullptr; }
|
|
||||||
void make_null() { ptr_ = nullptr; }
|
|
||||||
|
|
||||||
void assign_ptr(T * x) { ptr_ = x; }
|
|
||||||
|
|
||||||
gc_ptr & operator=(const gc_ptr & x) { ptr_ = x.ptr(); return *this; }
|
|
||||||
|
|
||||||
T * operator->() const { return ptr_; }
|
|
||||||
T & operator*() const { return *ptr_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
T * ptr_ = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Root class for all xo GC-collectable objects.
|
/** Root class for all xo GC-collectable objects.
|
||||||
*
|
*
|
||||||
* Design note:
|
* Design note:
|
||||||
|
|
@ -92,11 +29,15 @@ namespace xo {
|
||||||
* Would be feasible to relax the must-inherit-from-Object constraint
|
* Would be feasible to relax the must-inherit-from-Object constraint
|
||||||
* by having GC use its own wrapper, at cost of an extra layer of indirection
|
* by having GC use its own wrapper, at cost of an extra layer of indirection
|
||||||
**/
|
**/
|
||||||
class Object {
|
class Object : public IObject {
|
||||||
public:
|
public:
|
||||||
using TaggedPtr = xo::reflect::TaggedPtr;
|
using TaggedPtr = xo::reflect::TaggedPtr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static gp<Object> from(gp<IObject> x) {
|
||||||
|
return dynamic_cast<Object*>(x.ptr());
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~Object() = default;
|
virtual ~Object() = default;
|
||||||
|
|
||||||
/** memory allocator for objects. Likely this will be a GC instance,
|
/** memory allocator for objects. Likely this will be a GC instance,
|
||||||
|
|
@ -111,7 +52,7 @@ namespace xo {
|
||||||
* add mutation log entry
|
* add mutation log entry
|
||||||
**/
|
**/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void assign_member(gp<Object> parent, gp<T> * lhs, gp<Object> rhs);
|
static void assign_member(gp<IObject> parent, gp<T> * lhs, gp<IObject> rhs);
|
||||||
|
|
||||||
/** use from GC aux functions **/
|
/** use from GC aux functions **/
|
||||||
static gc::GC * _gc() { return reinterpret_cast<gc::GC*>(mm); }
|
static gc::GC * _gc() { return reinterpret_cast<gc::GC*>(mm); }
|
||||||
|
|
@ -125,11 +66,11 @@ namespace xo {
|
||||||
* @p src. source object to be forwarded
|
* @p src. source object to be forwarded
|
||||||
* @p gc. garbage collector
|
* @p gc. garbage collector
|
||||||
*/
|
*/
|
||||||
static Object * _forward(Object * src, gc::IAlloc * gc);
|
static IObject * _forward(IObject * src, gc::IAlloc * gc);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void _forward_inplace(T ** src_addr, gc::IAlloc * gc) {
|
static void _forward_inplace(T ** src_addr, gc::IAlloc * gc) {
|
||||||
Object * fwd = _forward(*src_addr, gc);
|
IObject * fwd = _forward(*src_addr, gc);
|
||||||
|
|
||||||
*src_addr = reinterpret_cast<T *>(fwd);
|
*src_addr = reinterpret_cast<T *>(fwd);
|
||||||
}
|
}
|
||||||
|
|
@ -160,12 +101,12 @@ namespace xo {
|
||||||
* @param gc garbage collector
|
* @param gc garbage collector
|
||||||
* @param stats per-object-type GC statistics
|
* @param stats per-object-type GC statistics
|
||||||
**/
|
**/
|
||||||
static Object * _deep_move(Object * src, gc::GC * gc, gc::ObjectStatistics * stats);
|
static IObject * _deep_move(IObject * src, gc::GC * gc, gc::ObjectStatistics * stats);
|
||||||
|
|
||||||
/** copy @p src to to-space. Overwrite 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::IAlloc * gc);
|
static IObject * _shallow_move(IObject * src, gc::IAlloc * gc);
|
||||||
|
|
||||||
// Reflection support
|
// Reflection support
|
||||||
|
|
||||||
|
|
@ -176,89 +117,25 @@ namespace xo {
|
||||||
/** print on stream @p os **/
|
/** print on stream @p os **/
|
||||||
virtual void display(std::ostream & os) const = 0;
|
virtual void display(std::ostream & os) const = 0;
|
||||||
|
|
||||||
// GC support
|
// Inherited from IObject..
|
||||||
|
|
||||||
/** true iff this object represents a forwarding pointer.
|
//virtual bool _is_forwarded() const override { return false; }
|
||||||
* Forwarding pointers are exclusively created by the garbage collector;
|
//virtual IObject * _offset_destination(IObject * src) const override { return src; };
|
||||||
* forwarding pointers (and only forwarding pointers) return true here.
|
virtual void _forward_to(IObject * dest) override;
|
||||||
**/
|
//virtual IObject * _destination() override { return nullptr; }
|
||||||
virtual bool _is_forwarded() const { return false; }
|
|
||||||
|
|
||||||
/** offset for uncommon situation where pointer address is offset from object
|
virtual std::size_t _shallow_size() const override = 0;
|
||||||
* base address
|
virtual IObject * _shallow_copy(gc::IAlloc * gc) const override = 0;
|
||||||
**/
|
virtual std::size_t _forward_children(gc::IAlloc * gc) override = 0;
|
||||||
virtual Object * _offset_destination(Object * src) const { return src; };
|
|
||||||
|
|
||||||
/** replace this object with a forwarding pointer referring to @p dest.
|
|
||||||
**/
|
|
||||||
virtual void _forward_to(Object * dest);
|
|
||||||
|
|
||||||
/** 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 Object * _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 Object * _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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void
|
void
|
||||||
Object::assign_member(gp<Object> parent, gp<T> * lhs, gp<Object> rhs)
|
Object::assign_member(gp<IObject> parent, gp<T> * lhs, gp<IObject> rhs)
|
||||||
{
|
{
|
||||||
Object::mm->assign_member(parent.ptr(),
|
Object::mm->assign_member(reinterpret_cast<IObject *>(parent.ptr()),
|
||||||
reinterpret_cast<Object **>(lhs->ptr_address()),
|
reinterpret_cast<IObject **>(lhs->ptr_address()),
|
||||||
rhs.ptr());
|
reinterpret_cast<IObject *>(rhs.ptr()));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream &
|
std::ostream &
|
||||||
|
|
|
||||||
|
|
@ -357,7 +357,7 @@ namespace xo {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ArenaAlloc::check_owned(Object * src) const
|
ArenaAlloc::check_owned(IObject * src) const
|
||||||
{
|
{
|
||||||
byte * addr = reinterpret_cast<byte *>(src);
|
byte * addr = reinterpret_cast<byte *>(src);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include "Blob.hpp"
|
#include "Blob.hpp"
|
||||||
#include "xo/reflect/Reflect.hpp"
|
#include "xo/reflect/Reflect.hpp"
|
||||||
#include "xo/alloc/IAlloc.hpp"
|
#include "xo/allocutil/IAlloc.hpp"
|
||||||
|
|
||||||
namespace xo {
|
namespace xo {
|
||||||
using xo::reflect::Reflect;
|
using xo::reflect::Reflect;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
set(SELF_LIB xo_alloc)
|
set(SELF_LIB xo_alloc)
|
||||||
set(SELF_SRCS
|
set(SELF_SRCS
|
||||||
IAlloc.cpp
|
|
||||||
ArenaAlloc.cpp
|
ArenaAlloc.cpp
|
||||||
ListAlloc.cpp
|
ListAlloc.cpp
|
||||||
GC.cpp
|
GC.cpp
|
||||||
|
|
@ -15,6 +14,7 @@ set(SELF_SRCS
|
||||||
)
|
)
|
||||||
|
|
||||||
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
|
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
|
||||||
|
xo_headeronly_dependency(${SELF_LIB} xo_allocutil)
|
||||||
# xo-unit used for time measurement
|
# xo-unit used for time measurement
|
||||||
xo_headeronly_dependency(${SELF_LIB} xo_unit)
|
xo_headeronly_dependency(${SELF_LIB} xo_unit)
|
||||||
xo_dependency(${SELF_LIB} indentlog)
|
xo_dependency(${SELF_LIB} indentlog)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace xo {
|
||||||
using xo::reflect::TaggedPtr;
|
using xo::reflect::TaggedPtr;
|
||||||
|
|
||||||
namespace obj {
|
namespace obj {
|
||||||
Forwarding1::Forwarding1(gp<Object> dest)
|
Forwarding1::Forwarding1(gp<IObject> dest)
|
||||||
: dest_{dest}
|
: dest_{dest}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
@ -26,18 +26,21 @@ namespace xo {
|
||||||
void
|
void
|
||||||
Forwarding1::display(std::ostream & os) const
|
Forwarding1::display(std::ostream & os) const
|
||||||
{
|
{
|
||||||
os << "<fwd" << xtag("dest-td", dest_->self_tp().td()->short_name()) << ">";
|
os << "<fwd"
|
||||||
|
<< xtag("dest", (void*)dest_.ptr())
|
||||||
|
// << xtag("dest-td", dest_->self_tp().td()->short_name())
|
||||||
|
<< ">";
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *
|
IObject *
|
||||||
Forwarding1::_offset_destination(Object * src) const
|
Forwarding1::_offset_destination(IObject * src) const
|
||||||
{
|
{
|
||||||
intptr_t offset = src - static_cast<const Object *>(this);
|
intptr_t offset = src - static_cast<const IObject *>(this);
|
||||||
|
|
||||||
return dest_.ptr() + offset;
|
return dest_.ptr() + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *
|
IObject *
|
||||||
Forwarding1::_destination() {
|
Forwarding1::_destination() {
|
||||||
return dest_.ptr();
|
return dest_.ptr();
|
||||||
}
|
}
|
||||||
|
|
@ -51,8 +54,10 @@ namespace xo {
|
||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
|
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
Object *
|
IObject *
|
||||||
Forwarding1::_shallow_copy(gc::IAlloc *) const {
|
Forwarding1::_shallow_copy(gc::IAlloc *) const {
|
||||||
|
/* forwarding objects are never copied */
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -61,6 +66,8 @@ namespace xo {
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
std::size_t
|
std::size_t
|
||||||
Forwarding1::_forward_children(gc::IAlloc *) {
|
Forwarding1::_forward_children(gc::IAlloc *) {
|
||||||
|
/* forwarding objects are never traced */
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace xo {
|
||||||
return parent_->_is_forwarded();
|
return parent_->_is_forwarded();
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *
|
IObject *
|
||||||
MutationLogEntry::parent_destination() const
|
MutationLogEntry::parent_destination() const
|
||||||
{
|
{
|
||||||
//const bool c_debug_flag = true;
|
//const bool c_debug_flag = true;
|
||||||
|
|
@ -45,7 +45,7 @@ namespace xo {
|
||||||
}
|
}
|
||||||
|
|
||||||
MutationLogEntry
|
MutationLogEntry
|
||||||
MutationLogEntry::update_parent_moved(Object * parent_to) const
|
MutationLogEntry::update_parent_moved(IObject * parent_to) const
|
||||||
{
|
{
|
||||||
std::byte * parent_from = reinterpret_cast<std::byte *>(parent_);
|
std::byte * parent_from = reinterpret_cast<std::byte *>(parent_);
|
||||||
std::byte * lhs_from = reinterpret_cast<std::byte *>(lhs_);
|
std::byte * lhs_from = reinterpret_cast<std::byte *>(lhs_);
|
||||||
|
|
@ -55,7 +55,7 @@ namespace xo {
|
||||||
std::byte * lhs_to = reinterpret_cast<std::byte *>(parent_to) + offset;
|
std::byte * lhs_to = reinterpret_cast<std::byte *>(parent_to) + offset;
|
||||||
|
|
||||||
return MutationLogEntry(parent_to,
|
return MutationLogEntry(parent_to,
|
||||||
reinterpret_cast<Object **>(lhs_to));
|
reinterpret_cast<IObject **>(lhs_to));
|
||||||
}
|
}
|
||||||
|
|
||||||
GC::GC(const Config & config)
|
GC::GC(const Config & config)
|
||||||
|
|
@ -395,13 +395,13 @@ namespace xo {
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GC::add_gc_root(Object ** addr)
|
GC::add_gc_root(IObject ** addr)
|
||||||
{
|
{
|
||||||
gc_root_v_.push_back(addr);
|
gc_root_v_.push_back(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GC::remove_gc_root(Object ** addr)
|
GC::remove_gc_root(IObject ** addr)
|
||||||
{
|
{
|
||||||
/* Multithreaded GC not supported */
|
/* Multithreaded GC not supported */
|
||||||
|
|
||||||
|
|
@ -450,7 +450,9 @@ namespace xo {
|
||||||
std::byte *
|
std::byte *
|
||||||
GC::alloc_gc_copy(std::size_t z, const void * src)
|
GC::alloc_gc_copy(std::size_t z, const void * src)
|
||||||
{
|
{
|
||||||
scope log(XO_DEBUG(config_.debug_flag_), xtag("z", z), xtag("+pad", IAlloc::alloc_padding(z)));
|
scope log(XO_DEBUG(config_.debug_flag_),
|
||||||
|
xtag("z", z),
|
||||||
|
xtag("+pad", IAlloc::alloc_padding(z)));
|
||||||
|
|
||||||
generation_result src_gr = this->fromspace_generation_of(src);
|
generation_result src_gr = this->fromspace_generation_of(src);
|
||||||
|
|
||||||
|
|
@ -483,7 +485,8 @@ namespace xo {
|
||||||
gc_copy_cbset_.invoke(&GcCopyCallback::notify_gc_copy,
|
gc_copy_cbset_.invoke(&GcCopyCallback::notify_gc_copy,
|
||||||
z, src, retval, generation::nursery, generation::tenured);
|
z, src, retval, generation::nursery, generation::tenured);
|
||||||
|
|
||||||
this->gc_statistics_.total_promoted_ += IAlloc::with_padding(z);
|
this->gc_statistics_.total_promoted_
|
||||||
|
+= IAlloc::with_padding(z);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
log && log("nursery");
|
log && log("nursery");
|
||||||
|
|
@ -509,7 +512,7 @@ namespace xo {
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GC::assign_member(Object * parent, Object ** lhs, Object * rhs)
|
GC::assign_member(IObject * parent, IObject ** lhs, IObject * rhs)
|
||||||
{
|
{
|
||||||
++gc_statistics_.n_mutation_;
|
++gc_statistics_.n_mutation_;
|
||||||
|
|
||||||
|
|
@ -566,13 +569,13 @@ namespace xo {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GC::check_owned(Object * src) const
|
GC::check_owned(IObject * src) const
|
||||||
{
|
{
|
||||||
return this->fromspace_contains(src);
|
return this->fromspace_contains(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GC::check_move(Object * src) const
|
GC::check_move(IObject * src) const
|
||||||
{
|
{
|
||||||
return (this->runstate().full_move()
|
return (this->runstate().full_move()
|
||||||
|| (this->tospace_generation_of(src) != gc::generation_result::tenured));
|
|| (this->tospace_generation_of(src) != gc::generation_result::tenured));
|
||||||
|
|
@ -682,7 +685,9 @@ namespace xo {
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GC::copy_object(Object ** pp_object, generation upto, ObjectStatistics * object_stats)
|
GC::copy_object(IObject ** pp_object,
|
||||||
|
generation upto,
|
||||||
|
ObjectStatistics * object_stats)
|
||||||
{
|
{
|
||||||
void * object_address = *pp_object;
|
void * object_address = *pp_object;
|
||||||
|
|
||||||
|
|
@ -707,7 +712,7 @@ namespace xo {
|
||||||
scope log(XO_DEBUG(config_.debug_flag_),
|
scope log(XO_DEBUG(config_.debug_flag_),
|
||||||
xtag("roots", gc_root_v_.size()));
|
xtag("roots", gc_root_v_.size()));
|
||||||
|
|
||||||
for (Object ** pp_root : gc_root_v_) {
|
for (IObject ** pp_root : gc_root_v_) {
|
||||||
this->copy_object(pp_root, upto,
|
this->copy_object(pp_root, upto,
|
||||||
&object_statistics_sae_[gen2int(upto)]);
|
&object_statistics_sae_[gen2int(upto)]);
|
||||||
}
|
}
|
||||||
|
|
@ -778,7 +783,7 @@ namespace xo {
|
||||||
// obsolete mutation -- no longer belongs to parent, discard
|
// obsolete mutation -- no longer belongs to parent, discard
|
||||||
} else {
|
} else {
|
||||||
// note: child obtained (as it must be) by reading from parent's memory _now_.
|
// note: child obtained (as it must be) by reading from parent's memory _now_.
|
||||||
Object * child_from = from_entry.child();
|
IObject * child_from = from_entry.child();
|
||||||
|
|
||||||
if (child_from) {
|
if (child_from) {
|
||||||
if (!child_from->_is_forwarded()) {
|
if (!child_from->_is_forwarded()) {
|
||||||
|
|
@ -813,7 +818,7 @@ namespace xo {
|
||||||
// P->C, C moved to C'
|
// P->C, C moved to C'
|
||||||
// Includes cases (a),(c) from above
|
// Includes cases (a),(c) from above
|
||||||
|
|
||||||
Object * child_to = child_from->_destination();
|
IObject * child_to = child_from->_destination();
|
||||||
|
|
||||||
from_entry.fixup_parent_child_moved(child_to);
|
from_entry.fixup_parent_child_moved(child_to);
|
||||||
|
|
||||||
|
|
@ -843,7 +848,7 @@ namespace xo {
|
||||||
// follows that loc(P') = T
|
// follows that loc(P') = T
|
||||||
// already have P'->C' when parent moved separately
|
// already have P'->C' when parent moved separately
|
||||||
|
|
||||||
Object * parent_to = from_entry.parent_destination();
|
IObject * parent_to = from_entry.parent_destination();
|
||||||
|
|
||||||
log && log(xtag("parent_to", (void*)parent_to));
|
log && log(xtag("parent_to", (void*)parent_to));
|
||||||
|
|
||||||
|
|
@ -851,7 +856,7 @@ namespace xo {
|
||||||
|
|
||||||
MutationLogEntry to_entry = from_entry.update_parent_moved(parent_to);
|
MutationLogEntry to_entry = from_entry.update_parent_moved(parent_to);
|
||||||
|
|
||||||
Object * child_to = to_entry.child(); // after moving
|
IObject * child_to = to_entry.child(); // after moving
|
||||||
|
|
||||||
if (tospace_generation_of(child_to) == generation_result::nursery) {
|
if (tospace_generation_of(child_to) == generation_result::nursery) {
|
||||||
if (to_entry.is_dead()) {
|
if (to_entry.is_dead()) {
|
||||||
|
|
@ -954,7 +959,7 @@ namespace xo {
|
||||||
log && (i_from % 10000 == 0) && log(xtag("i_from", i_from));
|
log && (i_from % 10000 == 0) && log(xtag("i_from", i_from));
|
||||||
|
|
||||||
if (from_entry.is_parent_forwarded()) {
|
if (from_entry.is_parent_forwarded()) {
|
||||||
Object * parent_to = from_entry.parent_destination();
|
IObject * parent_to = from_entry.parent_destination();
|
||||||
|
|
||||||
log && log(xtag("parent_to", (void*)parent_to));
|
log && log(xtag("parent_to", (void*)parent_to));
|
||||||
|
|
||||||
|
|
@ -964,7 +969,7 @@ namespace xo {
|
||||||
|
|
||||||
// note: child obtained (as it must be) by reading from prarent's memory _now_.
|
// note: child obtained (as it must be) by reading from prarent's memory _now_.
|
||||||
// Since parent has moved, child has too
|
// Since parent has moved, child has too
|
||||||
Object * child_to = to_entry.child(); // after moveing
|
IObject * child_to = to_entry.child(); // after moveing
|
||||||
|
|
||||||
if (tospace_generation_of(parent_to) == generation_result::tenured)
|
if (tospace_generation_of(parent_to) == generation_result::tenured)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
/* @file IAlloc.cpp
|
|
||||||
*
|
|
||||||
* author: Roland Conybeare, Aug 2025
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "IAlloc.hpp"
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
namespace xo {
|
|
||||||
namespace gc {
|
|
||||||
|
|
||||||
std::uint32_t
|
|
||||||
IAlloc::alloc_padding(std::size_t z)
|
|
||||||
{
|
|
||||||
/* word size for alignment */
|
|
||||||
constexpr uint32_t c_bpw = sizeof(std::uintptr_t);
|
|
||||||
|
|
||||||
/* round up to multiple of c_bpw, but map 0 -> 0
|
|
||||||
* (table assuming c_bpw==8)
|
|
||||||
*
|
|
||||||
* z%c_bpw dz
|
|
||||||
* ------------
|
|
||||||
* 0 0
|
|
||||||
* 1 7
|
|
||||||
* 2 6
|
|
||||||
* .. ..
|
|
||||||
* 7 1
|
|
||||||
*/
|
|
||||||
std::uint32_t dz = (c_bpw - (z % c_bpw)) % c_bpw;
|
|
||||||
z += dz;
|
|
||||||
|
|
||||||
assert(z % c_bpw == 0ul);
|
|
||||||
|
|
||||||
return dz;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t
|
|
||||||
IAlloc::with_padding(std::size_t z)
|
|
||||||
{
|
|
||||||
return z + alloc_padding(z);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
IAlloc::assign_member(Object * /*parent*/, Object ** lhs, Object * rhs)
|
|
||||||
{
|
|
||||||
*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*/)
|
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_STOP
|
|
||||||
|
|
||||||
} /*namespace gc*/
|
|
||||||
} /*namespace xo*/
|
|
||||||
|
|
||||||
/* end IAlloc.cpp */
|
|
||||||
|
|
@ -23,8 +23,8 @@ namespace xo {
|
||||||
gc::IAlloc *
|
gc::IAlloc *
|
||||||
Object::mm = nullptr;
|
Object::mm = nullptr;
|
||||||
|
|
||||||
Object *
|
IObject *
|
||||||
Object::_forward(Object * src, gc::IAlloc * gc)
|
Object::_forward(IObject * src, gc::IAlloc * gc)
|
||||||
{
|
{
|
||||||
if (!src)
|
if (!src)
|
||||||
return src;
|
return src;
|
||||||
|
|
@ -43,15 +43,15 @@ namespace xo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *
|
IObject *
|
||||||
Object::_deep_move(Object * from_src, gc::GC * gc, gc::ObjectStatistics * /*stats*/)
|
Object::_deep_move(IObject * from_src, gc::GC * gc, gc::ObjectStatistics * /*stats*/)
|
||||||
{
|
{
|
||||||
using gc::generation;
|
using gc::generation;
|
||||||
|
|
||||||
if (!from_src)
|
if (!from_src)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
Object * retval = from_src->_destination();
|
IObject * retval = from_src->_destination();
|
||||||
|
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -124,7 +124,7 @@ namespace xo {
|
||||||
std::array<std::byte *, gen2int(generation::N)> gray_lo_v
|
std::array<std::byte *, gen2int(generation::N)> gray_lo_v
|
||||||
= { gc->free_ptr(generation::nursery), gc->free_ptr(generation::tenured) };
|
= { gc->free_ptr(generation::nursery), gc->free_ptr(generation::tenured) };
|
||||||
|
|
||||||
Object * to_src = Object::_shallow_move(from_src, gc);
|
IObject * to_src = Object::_shallow_move(from_src, gc);
|
||||||
|
|
||||||
std::size_t fixup_work = 0;
|
std::size_t fixup_work = 0;
|
||||||
do {
|
do {
|
||||||
|
|
@ -158,15 +158,15 @@ namespace xo {
|
||||||
return to_src;
|
return to_src;
|
||||||
} /*deep_move*/
|
} /*deep_move*/
|
||||||
|
|
||||||
Object *
|
IObject *
|
||||||
Object::_shallow_move(Object * src, gc::IAlloc * gc)
|
Object::_shallow_move(IObject * 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->check_owned(src))
|
if (gc->check_owned(src))
|
||||||
{
|
{
|
||||||
Object * dest = src->_shallow_copy(gc);
|
IObject * dest = src->_shallow_copy(gc);
|
||||||
|
|
||||||
if (dest != src)
|
if (dest != src)
|
||||||
src->_forward_to(dest);
|
src->_forward_to(dest);
|
||||||
|
|
@ -178,7 +178,7 @@ namespace xo {
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Object::_forward_to(Object * dest)
|
Object::_forward_to(IObject * dest)
|
||||||
{
|
{
|
||||||
char * mem = reinterpret_cast<char *>(this);
|
char * mem = reinterpret_cast<char *>(this);
|
||||||
|
|
||||||
|
|
|
||||||
43
xo-allocutil/CMakeLists.txt
Normal file
43
xo-allocutil/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
# xo-allocutil/CMakeLists.txt
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
project(xo_allocutil VERSION 0.1)
|
||||||
|
enable_language(CXX)
|
||||||
|
|
||||||
|
# common XO macros (see github:Rconybea/xo-cmake)
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
include(cmake/xo-bootstrap-macros.cmake)
|
||||||
|
|
||||||
|
xo_cxx_toplevel_options3()
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# c++ settings
|
||||||
|
|
||||||
|
set(PROJECT_CXX_FLAGS "")
|
||||||
|
add_definitions(${PROJECT_CXX_FLAGS})
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# output targets
|
||||||
|
|
||||||
|
#add_subdirectory(utest)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# header-only library
|
||||||
|
|
||||||
|
set(SELF_LIB xo_allocutil)
|
||||||
|
xo_add_headeronly_library(${SELF_LIB})
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
#
|
||||||
|
xo_install_library4(${SELF_LIB} ${PROJECT_NAME}Targets)
|
||||||
|
# (note: ..Targets from xo_install_library2())
|
||||||
|
xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# input dependencies
|
||||||
|
|
||||||
|
# NOTE: dependency set here must be kept consistent with allocutil/cmake/xo_allocutilConfig.cmake.in
|
||||||
|
|
||||||
|
# xo-allocutil is also header-only
|
||||||
|
#xo_headeronly_dependency(${SELF_LIB} randomgen)
|
||||||
14
xo-allocutil/cmake/xo-bootstrap-macros.cmake
Normal file
14
xo-allocutil/cmake/xo-bootstrap-macros.cmake
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL "prefix"))
|
||||||
|
# default to typical install location for xo-project-macros
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_INSTALL_PREFIX}/share/cmake)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT XO_SUBMODULE_BUILD)
|
||||||
|
message("-- CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
|
||||||
|
message("-- CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# needs to have been installed somewhere on CMAKE_MODULE_PATH,
|
||||||
|
# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX)
|
||||||
|
#
|
||||||
|
include(xo_macros/xo_cxx)
|
||||||
6
xo-allocutil/cmake/xo_allocutilConfig.cmake.in
Normal file
6
xo-allocutil/cmake/xo_allocutilConfig.cmake.in
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
include(CMakeFindDependencyMacro)
|
||||||
|
#find_dependency(randomgen)
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||||
|
check_required_components("@PROJECT_NAME@")
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/* file IAlloc.hpp
|
/** @file IAlloc.hpp
|
||||||
*
|
*
|
||||||
* author: Roland Conybeare, Jul 2025
|
* @author: Roland Conybeare, Jul 2025
|
||||||
*/
|
**/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
@ -12,11 +12,11 @@ namespace xo {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using up = std::unique_ptr<T>;
|
using up = std::unique_ptr<T>;
|
||||||
|
|
||||||
class Object;
|
class IObject;
|
||||||
|
|
||||||
namespace gc {
|
namespace gc {
|
||||||
/** @class IAllocator
|
/** @class IAllocator
|
||||||
* @brief arena allocation interface with limited garbage collector support
|
* @brief Abstract API for allocation interface
|
||||||
*
|
*
|
||||||
* Garbage collector support methods:
|
* Garbage collector support methods:
|
||||||
* - checkpoint()
|
* - checkpoint()
|
||||||
|
|
@ -30,12 +30,30 @@ namespace xo {
|
||||||
public:
|
public:
|
||||||
virtual ~IAlloc() {}
|
virtual ~IAlloc() {}
|
||||||
|
|
||||||
/** compute padding to add to an allocation of size z to bring it up to
|
static inline std::uint32_t alloc_padding(std::size_t z) {
|
||||||
* a multiple of word size (8 bytes on x86_64)
|
/* word size for alignment */
|
||||||
**/
|
constexpr uint32_t c_bpw = sizeof(std::uintptr_t);
|
||||||
static std::uint32_t alloc_padding(std::size_t z);
|
|
||||||
/** z + alloc_padding(z) **/
|
/* round up to multiple of c_bpw, but map 0 -> 0
|
||||||
static std::size_t with_padding(std::size_t z);
|
* (table assuming c_bpw==8)
|
||||||
|
*
|
||||||
|
* z%c_bpw dz
|
||||||
|
* ------------
|
||||||
|
* 0 0
|
||||||
|
* 1 7
|
||||||
|
* 2 6
|
||||||
|
* .. ..
|
||||||
|
* 7 1
|
||||||
|
*/
|
||||||
|
std::uint32_t dz = (c_bpw - (z % c_bpw)) % c_bpw;
|
||||||
|
z += dz;
|
||||||
|
|
||||||
|
return dz;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline std::size_t with_padding(std::size_t z) {
|
||||||
|
return z + alloc_padding(z);
|
||||||
|
}
|
||||||
|
|
||||||
/** optional name for this allocator; labelling for diagnostics **/
|
/** optional name for this allocator; labelling for diagnostics **/
|
||||||
virtual const std::string & name() const = 0;
|
virtual const std::string & name() const = 0;
|
||||||
|
|
@ -81,23 +99,30 @@ namespace xo {
|
||||||
/** true iff this allocator owns object at address @p src.
|
/** true iff this allocator owns object at address @p src.
|
||||||
* Use to assist Object::_shallow_move
|
* Use to assist Object::_shallow_move
|
||||||
**/
|
**/
|
||||||
virtual bool check_owned(Object * src) const;
|
virtual bool check_owned(IObject * /*src*/) const { return false; }
|
||||||
/** true iff object at address @p src must move as part of
|
/** true iff object at address @p src must move as part of
|
||||||
* in-progress collection phase
|
* in-progress collection phase
|
||||||
**/
|
**/
|
||||||
virtual bool check_move(Object * src) const;
|
virtual bool check_move(IObject * /*src*/) const { return false; }
|
||||||
/** perform assignment
|
/** write barrier for collector. perform assignment
|
||||||
* @code
|
* @code
|
||||||
* *lhs = rhs
|
* *lhs = rhs
|
||||||
* @endcode
|
* @endcode
|
||||||
* plus additional book keeping if needed (e.g. in @ref GC)
|
* plus additional book keeping if needed (e.g. in @ref GC)
|
||||||
* 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(IObject * /*parent*/,
|
||||||
|
IObject ** lhs,
|
||||||
|
IObject * rhs) { *lhs = rhs; }
|
||||||
/** 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
|
||||||
**/
|
**/
|
||||||
virtual std::byte * alloc_gc_copy(std::size_t z, const void * src);
|
virtual std::byte * alloc_gc_copy(std::size_t /*z*/, const void * /*src*/) {
|
||||||
|
// LCOV_EXCL_START
|
||||||
|
//assert(false);
|
||||||
|
return nullptr;
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} /*namespace gc*/
|
} /*namespace gc*/
|
||||||
|
|
||||||
97
xo-allocutil/include/xo/allocutil/IObject.hpp
Normal file
97
xo-allocutil/include/xo/allocutil/IObject.hpp
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
/** @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:
|
||||||
|
/** 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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end IObject.hpp */
|
||||||
75
xo-allocutil/include/xo/allocutil/gc_allocator_traits.hpp
Normal file
75
xo-allocutil/include/xo/allocutil/gc_allocator_traits.hpp
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
/** @file gc_allocator_traits.hpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, Nov 2025
|
||||||
|
**/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace gc {
|
||||||
|
/** Extended version of
|
||||||
|
* std::allocator_traits<Allocator>
|
||||||
|
* Introduces additional i/face methods
|
||||||
|
* for garbage-collector-enabled allocators
|
||||||
|
*
|
||||||
|
* allocator A can identify itself as a copying collector:
|
||||||
|
* 1. provide A::object_interface
|
||||||
|
* A::object_interface = xo::Object
|
||||||
|
* 2. provide A::is_incremental_collector
|
||||||
|
* A::is_incremental_collector = std::true_type
|
||||||
|
* Collectible objects must:
|
||||||
|
* 2a. inherit A::object_interface
|
||||||
|
* 2b. implement A::object_interface::_shallow_size()
|
||||||
|
* 2c. implement A::object_interface::_shallow_copy(alloc)
|
||||||
|
* 2d. implement A::object_interface::_forward_children(alloc)
|
||||||
|
**/
|
||||||
|
template <typename Allocator>
|
||||||
|
struct gc_allocator_traits : std::allocator_traits<Allocator> {
|
||||||
|
using super = std::allocator_traits<Allocator>;
|
||||||
|
using pointer = typename super::pointer;
|
||||||
|
using value_type = typename super::value_type;
|
||||||
|
|
||||||
|
// default: allocator A fallback to standard non-gc allocator behavior
|
||||||
|
template <typename A, typename = void>
|
||||||
|
struct is_incremental_collector : std::false_type {};
|
||||||
|
|
||||||
|
// opt-in: A provides nested type 'is_incremental_collector':
|
||||||
|
// struct A {
|
||||||
|
// using is_incremental_collector = std::true_type;
|
||||||
|
// };
|
||||||
|
template <typename A>
|
||||||
|
struct is_incremental_collector<A, std::void_t<typename A::is_incremental_collector>> :
|
||||||
|
A::is_incremental_collector {};
|
||||||
|
|
||||||
|
// default: empty object interface.
|
||||||
|
// classes that want to conditionally support GC
|
||||||
|
// (e.g. see xo::tree::RedBlackTree, xo::tree::Node
|
||||||
|
// in xo-ordinal-tree)
|
||||||
|
// can inherit
|
||||||
|
// gc_allocator_traits<Allocator>::template object_interface<Allocator>
|
||||||
|
//
|
||||||
|
template <typename A, typename = void>
|
||||||
|
struct object_interface {};
|
||||||
|
|
||||||
|
// specialization when A provides gc_object_interface
|
||||||
|
template <typename A>
|
||||||
|
struct object_interface<A, std::void_t<typename A::gc_object_interface>>
|
||||||
|
: A::gc_object_interface {};
|
||||||
|
|
||||||
|
/** true iff this allocator advertises itself as an incremental collector
|
||||||
|
* allocator will include:
|
||||||
|
*
|
||||||
|
* struct GC {
|
||||||
|
* using is_incremental_collector = std::true_type;
|
||||||
|
* };
|
||||||
|
**/
|
||||||
|
static inline constexpr bool is_incremental_collector_v = is_incremental_collector<Allocator>::value;
|
||||||
|
|
||||||
|
};
|
||||||
|
} /*namespace gc*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end gc_allocator_traits.hpp */
|
||||||
77
xo-allocutil/include/xo/allocutil/gc_ptr.hpp
Normal file
77
xo-allocutil/include/xo/allocutil/gc_ptr.hpp
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
/** @file gc_ptr.hpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, Nov 2025
|
||||||
|
**/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
template <typename T>
|
||||||
|
class gc_ptr;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using gp = gc_ptr<T>;
|
||||||
|
|
||||||
|
/** wrapper for a pointer to garbage-collector-eligible T.
|
||||||
|
* Application code will usually use the alias template gp<T>
|
||||||
|
**/
|
||||||
|
template <typename T>
|
||||||
|
class gc_ptr {
|
||||||
|
public:
|
||||||
|
using element_type = T;
|
||||||
|
|
||||||
|
public:
|
||||||
|
gc_ptr() = default;
|
||||||
|
gc_ptr(T * p) : ptr_{p} {}
|
||||||
|
gc_ptr(const gc_ptr & x) : ptr_{x.ptr_} {}
|
||||||
|
|
||||||
|
/** create from gc_ptr to some related type @tparam S **/
|
||||||
|
template <typename S>
|
||||||
|
gc_ptr(const gc_ptr<S> & x) : ptr_{x.ptr()} {}
|
||||||
|
|
||||||
|
/** runtime downcast. shorthand for dynamic_cast<T*> **/
|
||||||
|
template <typename S>
|
||||||
|
static gc_ptr<T> from(const gc_ptr<S> & x) { return gc_ptr<T>{dynamic_cast<T*>(x.ptr())}; }
|
||||||
|
|
||||||
|
/** convenience for static asserts **/
|
||||||
|
static constexpr bool is_gc_ptr = true;
|
||||||
|
/** see also: xo/refcnt/Refcounted.hpp **/
|
||||||
|
static constexpr bool is_rc_ptr = false;
|
||||||
|
|
||||||
|
static bool is_eq(gc_ptr x1, gc_ptr x2) {
|
||||||
|
std::uintptr_t u1 = reinterpret_cast<std::uintptr_t>(x1.ptr());
|
||||||
|
std::uintptr_t u2 = reinterpret_cast<std::uintptr_t>(x2.ptr());
|
||||||
|
|
||||||
|
// multiple inheritance shenanigans.
|
||||||
|
// (allow interface pointers separated by one pointer)
|
||||||
|
|
||||||
|
if (u1 >= u2)
|
||||||
|
return (u1 <= u2 + sizeof(std::uintptr_t));
|
||||||
|
else
|
||||||
|
return (u2 <= u1 + sizeof(std::uintptr_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** (for consistency's sake) **/
|
||||||
|
T * get() const { return ptr_; }
|
||||||
|
|
||||||
|
T * ptr() const { return ptr_; }
|
||||||
|
T ** ptr_address() { return &ptr_; }
|
||||||
|
|
||||||
|
bool is_null() const { return ptr_ == nullptr; }
|
||||||
|
void make_null() { ptr_ = nullptr; }
|
||||||
|
|
||||||
|
void assign_ptr(T * x) { ptr_ = x; }
|
||||||
|
|
||||||
|
gc_ptr & operator=(const gc_ptr & x) { ptr_ = x.ptr(); return *this; }
|
||||||
|
|
||||||
|
T * operator->() const { return ptr_; }
|
||||||
|
T & operator*() const { return *ptr_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T * ptr_ = nullptr;
|
||||||
|
};
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end gc_ptr.hpp */
|
||||||
|
|
@ -263,6 +263,7 @@ GcStateDescription::GcStateDescription(const GcGenerationDescription & nursery,
|
||||||
|
|
||||||
using xo::gp;
|
using xo::gp;
|
||||||
using xo::up;
|
using xo::up;
|
||||||
|
using xo::IObject;
|
||||||
using xo::Object;
|
using xo::Object;
|
||||||
using xo::obj::List;
|
using xo::obj::List;
|
||||||
using xo::obj::Integer;
|
using xo::obj::Integer;
|
||||||
|
|
@ -342,7 +343,7 @@ AppState::AppState()
|
||||||
Object::mm = gc_.get();
|
Object::mm = gc_.get();
|
||||||
|
|
||||||
for (auto & x: gc_root_v_)
|
for (auto & x: gc_root_v_)
|
||||||
gc_->add_gc_root(x.ptr_address());
|
gc_->add_gc_root(reinterpret_cast<IObject **>(x.ptr_address()));
|
||||||
|
|
||||||
gc_->disable_gc();
|
gc_->disable_gc();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include "xo/object/Integer.hpp"
|
#include "xo/object/Integer.hpp"
|
||||||
#include "xo/object/List.hpp"
|
#include "xo/object/List.hpp"
|
||||||
|
|
||||||
|
using xo::IObject;
|
||||||
using xo::obj::Integer;
|
using xo::obj::Integer;
|
||||||
using xo::obj::List;
|
using xo::obj::List;
|
||||||
using xo::gp;
|
using xo::gp;
|
||||||
|
|
@ -22,7 +23,7 @@ AppState::AppState()
|
||||||
Object::mm = gc_.get();
|
Object::mm = gc_.get();
|
||||||
|
|
||||||
for (auto & x: gc_root_v_)
|
for (auto & x: gc_root_v_)
|
||||||
gc_->add_gc_root(x.ptr_address());
|
gc_->add_gc_root(reinterpret_cast<IObject **>(x.ptr_address()));
|
||||||
|
|
||||||
gc_->disable_gc();
|
gc_->disable_gc();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#include "xo/object/ObjectConverter.hpp"
|
#include "xo/object/ObjectConverter.hpp"
|
||||||
#include "xo/alloc/IAlloc.hpp"
|
#include "xo/allocutil/IAlloc.hpp"
|
||||||
#include "Primitive.hpp"
|
#include "Primitive.hpp"
|
||||||
#include "GlobalEnv.hpp"
|
#include "GlobalEnv.hpp"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Env.hpp"
|
#include "Env.hpp"
|
||||||
#include "xo/alloc/IAlloc.hpp"
|
#include "xo/allocutil/IAlloc.hpp"
|
||||||
#include "xo/expression/GlobalSymtab.hpp"
|
#include "xo/expression/GlobalSymtab.hpp"
|
||||||
|
|
||||||
namespace xo {
|
namespace xo {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#include "Env.hpp"
|
#include "Env.hpp"
|
||||||
#include "CVector.hpp"
|
#include "CVector.hpp"
|
||||||
#include "xo/alloc/IAlloc.hpp"
|
#include "xo/allocutil/IAlloc.hpp"
|
||||||
#include "xo/expression/LocalSymtab.hpp"
|
#include "xo/expression/LocalSymtab.hpp"
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
|
||||||
|
|
@ -91,12 +91,12 @@ namespace xo {
|
||||||
std::size_t n = tc.contents_.size();
|
std::size_t n = tc.contents_.size();
|
||||||
|
|
||||||
gp<Integer> x = Integer::make(gc.get(), 42);
|
gp<Integer> x = Integer::make(gc.get(), 42);
|
||||||
gc->add_gc_root(reinterpret_cast<Object **>(&x));
|
gc->add_gc_root(reinterpret_cast<IObject **>(&x));
|
||||||
REQUIRE(gc->tospace_generation_of(x.ptr()) == generation_result::nursery);
|
REQUIRE(gc->tospace_generation_of(x.ptr()) == generation_result::nursery);
|
||||||
|
|
||||||
gp<LocalEnv> frame = LocalEnv::make(gc.get(), nullptr /*parent*/, nullptr /*symtab*/, n);
|
gp<LocalEnv> frame = LocalEnv::make(gc.get(), nullptr /*parent*/, nullptr /*symtab*/, n);
|
||||||
LocalEnv ** frame_pp = frame.ptr_address();
|
LocalEnv ** frame_pp = frame.ptr_address();
|
||||||
gc->add_gc_root(reinterpret_cast<Object **>(frame_pp));
|
gc->add_gc_root(reinterpret_cast<IObject **>(frame_pp));
|
||||||
|
|
||||||
/* verifying allocated in N1 */
|
/* verifying allocated in N1 */
|
||||||
REQUIRE(gc->tospace_generation_of(frame.ptr()) == generation_result::nursery);
|
REQUIRE(gc->tospace_generation_of(frame.ptr()) == generation_result::nursery);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "xo/alloc/IAlloc.hpp"
|
#include "xo/allocutil/IAlloc.hpp"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace xo {
|
namespace xo {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace xo {
|
||||||
/** create instance holding integer value @p x **/
|
/** create instance holding integer value @p x **/
|
||||||
static gp<Integer> make(IAlloc * mm, int_type x);
|
static gp<Integer> make(IAlloc * mm, int_type x);
|
||||||
/** downcast from @p x iff x is actually an Integer. Otherwise nullptr **/
|
/** downcast from @p x iff x is actually an Integer. Otherwise nullptr **/
|
||||||
static gp<Integer> from(gp<Object> x);
|
static gp<Integer> from(gp<IObject> x);
|
||||||
|
|
||||||
int_type value() const { return value_; }
|
int_type value() const { return value_; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace xo {
|
||||||
static gp<List> nil;
|
static gp<List> nil;
|
||||||
|
|
||||||
/** @return non-null iff @p x is actually a List cell (or nil) **/
|
/** @return non-null iff @p x is actually a List cell (or nil) **/
|
||||||
static gp<List> from(gp<Object> x);
|
static gp<List> from(gp<IObject> x);
|
||||||
|
|
||||||
/** @return list with first element @p car, and tail @p cdr **/
|
/** @return list with first element @p car, and tail @p cdr **/
|
||||||
static gp<List> cons(gp<Object> car, gp<List> cdr);
|
static gp<List> cons(gp<Object> car, gp<List> cdr);
|
||||||
|
|
@ -44,7 +44,7 @@ namespace xo {
|
||||||
/** @return first element in list; synonym for @ref head **/
|
/** @return first element in list; synonym for @ref head **/
|
||||||
gp<Object> car() const { return head_; }
|
gp<Object> car() const { return head_; }
|
||||||
/** @return remainder of list after first element; synonym for @ref rest **/
|
/** @return remainder of list after first element; synonym for @ref rest **/
|
||||||
gp<Object> cdr() const { return rest_; }
|
gp<List> cdr() const { return rest_; }
|
||||||
|
|
||||||
/** @return number of top-level elements in this list **/
|
/** @return number of top-level elements in this list **/
|
||||||
std::size_t size() const;
|
std::size_t size() const;
|
||||||
|
|
@ -58,7 +58,7 @@ namespace xo {
|
||||||
virtual TaggedPtr self_tp() const final override;
|
virtual TaggedPtr self_tp() const final override;
|
||||||
virtual void display(std::ostream & os) const final override;
|
virtual void display(std::ostream & os) const final override;
|
||||||
virtual std::size_t _shallow_size() const final override;
|
virtual std::size_t _shallow_size() const final override;
|
||||||
virtual Object * _shallow_copy(gc::IAlloc * gc) const final override;
|
virtual IObject * _shallow_copy(gc::IAlloc * gc) const final override;
|
||||||
virtual std::size_t _forward_children(gc::IAlloc * gc) final override;
|
virtual std::size_t _forward_children(gc::IAlloc * gc) final override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include "xo/alloc/Object.hpp"
|
#include "xo/alloc/Object.hpp"
|
||||||
#include "ObjectConversion.hpp"
|
#include "ObjectConversion.hpp"
|
||||||
#include "xo/alloc/IAlloc.hpp"
|
#include "xo/allocutil/IAlloc.hpp"
|
||||||
#include "xo/indentlog/print/tag.hpp"
|
#include "xo/indentlog/print/tag.hpp"
|
||||||
|
|
||||||
namespace xo {
|
namespace xo {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace xo {
|
||||||
}
|
}
|
||||||
|
|
||||||
gp<Integer>
|
gp<Integer>
|
||||||
Integer::from(gp<Object> x) {
|
Integer::from(gp<IObject> x) {
|
||||||
return gp<Integer>::from(x);
|
return gp<Integer>::from(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ namespace xo {
|
||||||
List::nil = new List(nullptr, nullptr);
|
List::nil = new List(nullptr, nullptr);
|
||||||
|
|
||||||
gp<List>
|
gp<List>
|
||||||
List::from(gp<Object> x) {
|
List::from(gp<IObject> x) {
|
||||||
return dynamic_cast<List *>(x.ptr());
|
return dynamic_cast<List *>(x.ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,7 +99,7 @@ namespace xo {
|
||||||
return sizeof(List);
|
return sizeof(List);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *
|
IObject *
|
||||||
List::_shallow_copy(gc::IAlloc * gc) const
|
List::_shallow_copy(gc::IAlloc * gc) const
|
||||||
{
|
{
|
||||||
assert(!(this->is_nil()));
|
assert(!(this->is_nil()));
|
||||||
|
|
|
||||||
|
|
@ -59,10 +59,10 @@ namespace xo {
|
||||||
Object::mm = gc.get();
|
Object::mm = gc.get();
|
||||||
|
|
||||||
gp<List> l = List::list(Integer::make(gc.get(), 1));
|
gp<List> l = List::list(Integer::make(gc.get(), 1));
|
||||||
gc->add_gc_root(reinterpret_cast<Object**>(l.ptr_address()));
|
gc->add_gc_root(reinterpret_cast<IObject**>(l.ptr_address()));
|
||||||
|
|
||||||
gp<List> l2 = List::list(Integer::make(gc.get(), 10));
|
gp<List> l2 = List::list(Integer::make(gc.get(), 10));
|
||||||
gc->add_gc_root(reinterpret_cast<Object**>(l2.ptr_address()));
|
gc->add_gc_root(reinterpret_cast<IObject**>(l2.ptr_address()));
|
||||||
|
|
||||||
{
|
{
|
||||||
REQUIRE(l->size() == 1);
|
REQUIRE(l->size() == 1);
|
||||||
|
|
@ -447,7 +447,7 @@ namespace xo {
|
||||||
REQUIRE(root_v_.size() == r_);
|
REQUIRE(root_v_.size() == r_);
|
||||||
|
|
||||||
for (auto & root : root_v_)
|
for (auto & root : root_v_)
|
||||||
gc->add_gc_root(root.ptr_address());
|
gc->add_gc_root(reinterpret_cast<IObject**>(root.ptr_address()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RandomMutationModel::generate_random_mutations(xoshiro256ss * p_rgen)
|
void RandomMutationModel::generate_random_mutations(xoshiro256ss * p_rgen)
|
||||||
|
|
@ -495,7 +495,7 @@ namespace xo {
|
||||||
|
|
||||||
if (w2_.at(j)->_is_forwarded()) {
|
if (w2_.at(j)->_is_forwarded()) {
|
||||||
/* w2[i] survived GC */
|
/* w2[i] survived GC */
|
||||||
w2_[j] = w2_[j]->_destination();
|
w2_[j] = Object::from(w2_[j]->_destination());
|
||||||
REQUIRE(w2_[j].ptr());
|
REQUIRE(w2_[j].ptr());
|
||||||
} else {
|
} else {
|
||||||
/* w2[j] is garbage, replace */
|
/* w2[j] is garbage, replace */
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ namespace xo {
|
||||||
REQUIRE(l1->size() == v.size());
|
REQUIRE(l1->size() == v.size());
|
||||||
|
|
||||||
root_v[i] = l1;
|
root_v[i] = l1;
|
||||||
gc->add_gc_root(reinterpret_cast<Object **>(root_v[i].ptr_address()));
|
gc->add_gc_root(reinterpret_cast<IObject **>(root_v[i].ptr_address()));
|
||||||
|
|
||||||
REQUIRE(gc->allocated() % sizeof(std::uintptr_t) == 0);
|
REQUIRE(gc->allocated() % sizeof(std::uintptr_t) == 0);
|
||||||
REQUIRE(gc->allocated() == expected_alloc_z);
|
REQUIRE(gc->allocated() == expected_alloc_z);
|
||||||
|
|
@ -285,7 +285,7 @@ namespace xo {
|
||||||
//REQUIRE(l1->size() == v.size()); // lwill loop forever
|
//REQUIRE(l1->size() == v.size()); // lwill loop forever
|
||||||
|
|
||||||
root_v[i] = l1;
|
root_v[i] = l1;
|
||||||
gc->add_gc_root(reinterpret_cast<Object **>(root_v[i].ptr_address()));
|
gc->add_gc_root(reinterpret_cast<IObject **>(root_v[i].ptr_address()));
|
||||||
|
|
||||||
REQUIRE(gc->allocated() % sizeof(std::uintptr_t) == 0);
|
REQUIRE(gc->allocated() % sizeof(std::uintptr_t) == 0);
|
||||||
REQUIRE(gc->allocated() == expected_alloc_z);
|
REQUIRE(gc->allocated() == expected_alloc_z);
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ namespace xo {
|
||||||
xtag("alloc_z", alloc_z));
|
xtag("alloc_z", alloc_z));
|
||||||
log && log(xtag("expected_alloc_z", expected_alloc_z));
|
log && log(xtag("expected_alloc_z", expected_alloc_z));
|
||||||
|
|
||||||
gc->add_gc_root(reinterpret_cast<Object **>(sv[i].ptr_address()));
|
gc->add_gc_root(reinterpret_cast<IObject **>(sv[i].ptr_address()));
|
||||||
|
|
||||||
REQUIRE(gc->allocated() % sizeof(std::uintptr_t) == 0);
|
REQUIRE(gc->allocated() % sizeof(std::uintptr_t) == 0);
|
||||||
REQUIRE(gc->allocated() == expected_alloc_z);
|
REQUIRE(gc->allocated() == expected_alloc_z);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue