Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modified finaliser to collect subregions #90

Merged
merged 3 commits into from
Jun 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions src/interpreter/object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ namespace verona::interpreter
// skip it. In that case, there are also obviously no iso fields.
rt::Descriptor::destructor =
field_count > 0 ? VMObject::destructor_fn : nullptr;
rt::Descriptor::trace_possibly_iso =
field_count > 0 ? VMObject::trace_fn : nullptr;
// In the VM object we always need a finaliser in case it has an iso field.
// The finaliser will collect the iso references that will be deallocated
// at the end of this phase.
// TODO: Can be optimised if we look at the types of all the fields
rt::Descriptor::finaliser =
finaliser_ip > 0 ? VMObject::finaliser_fn : nullptr;
finaliser_ip > 0 ? VMObject::finaliser_fn : VMObject::collect_iso_fields;
}

VMObject::VMObject(VMObject* region, const VMDescriptor* desc)
Expand All @@ -58,7 +60,7 @@ namespace verona::interpreter
}
}

void VMObject::trace_fn(const rt::Object* base_object, rt::ObjectStack* stack)
void VMObject::trace_fn(const rt::Object* base_object, rt::ObjectStack& stack)
{
const VMObject* object = static_cast<const VMObject*>(base_object);
const VMDescriptor* descriptor = object->descriptor();
Expand All @@ -69,10 +71,30 @@ namespace verona::interpreter
}
}

void VMObject::finaliser_fn(rt::Object* base_object)
void VMObject::finaliser_fn(
rt::Object* base_object, rt::Object* region, rt::ObjectStack& sub_regions)
{
VMObject* object = static_cast<VMObject*>(base_object);

VM::execute_finaliser(object);

collect_iso_fields(base_object, region, sub_regions);
}

void VMObject::collect_iso_fields(
rt::Object* base_object, rt::Object* region, rt::ObjectStack& sub_regions)
{
// The interpreter doesn't need the region, as the FieldValue type contains
// the ISO information in its fat pointers.
UNUSED(region);

VMObject* object = static_cast<VMObject*>(base_object);
const VMDescriptor* descriptor = object->descriptor();

for (size_t i = 0; i < descriptor->field_count; i++)
{
object->fields[i].add_isos(sub_regions);
}
}

void VMObject::destructor_fn(rt::Object* base_object)
Expand Down
21 changes: 11 additions & 10 deletions src/interpreter/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,15 @@ namespace verona::interpreter

VMObject* region();

static void trace_fn(const rt::Object* base_object, rt::ObjectStack* stack);
static void finaliser_fn(rt::Object* base_object);
static void trace_fn(const rt::Object* base_object, rt::ObjectStack& stack);
static void finaliser_fn(
rt::Object* base_object,
rt::Object* region,
rt::ObjectStack& sub_regions);
static void collect_iso_fields(
rt::Object* base_object,
rt::Object* region,
rt::ObjectStack& sub_regions);
static void destructor_fn(rt::Object* base_object);

private:
Expand Down Expand Up @@ -81,16 +88,10 @@ namespace verona::interpreter
rt::VCown<VMCown>::schedule();
}

void trace(rt::ObjectStack* stack)
void trace(rt::ObjectStack& stack)
{
if (contents != nullptr)
stack->push(contents);
}

void trace_possibly_iso(rt::ObjectStack* stack)
{
if (contents != nullptr)
stack->push(contents);
stack.push(contents);
}
};
}
31 changes: 28 additions & 3 deletions src/interpreter/value.cc
Original file line number Diff line number Diff line change
Expand Up @@ -297,18 +297,18 @@ namespace verona::interpreter
return result;
}

void FieldValue::trace(rt::ObjectStack* stack) const
void FieldValue::trace(rt::ObjectStack& stack) const
{
switch (tag)
{
case Value::ISO:
case Value::MUT:
case Value::IMM:
stack->push(inner.object);
stack.push(inner.object);
break;

case Value::COWN:
stack->push(inner.cown);
stack.push(inner.cown);
break;

case Value::UNINIT:
Expand All @@ -325,6 +325,31 @@ namespace verona::interpreter
}
}

void FieldValue::add_isos(rt::ObjectStack& stack) const
{
switch (tag)
{
case Value::ISO:
rengolin marked this conversation as resolved.
Show resolved Hide resolved
stack.push(inner.object);
break;

case Value::COWN:
case Value::MUT:
case Value::IMM:
case Value::UNINIT:
case Value::U64:
case Value::STRING:
case Value::DESCRIPTOR:
break;

case Value::COWN_UNOWNED:
// Cannot be part of the heap.
abort();

EXHAUSTIVE_SWITCH
}
}

FieldValue::~FieldValue()
{
switch (tag)
Expand Down
10 changes: 8 additions & 2 deletions src/interpreter/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ namespace verona::interpreter
return &inner;
}

void trace(rt::ObjectStack* stack) const;
void trace(rt::ObjectStack& stack) const;

static constexpr Tag UNINIT = Tag::UNINIT;
static constexpr Tag ISO = Tag::ISO;
Expand Down Expand Up @@ -190,7 +190,13 @@ namespace verona::interpreter
*/
Value exchange(rt::Alloc* alloc, rt::Object* region, Value&& value);

void trace(rt::ObjectStack* stack) const;
void trace(rt::ObjectStack& stack) const;

/**
* If this Value contains an ISO, then add it to the stack
* Otherwise, do nothing.
**/
void add_isos(rt::ObjectStack& stack) const;

friend fmt::formatter<Value>;

Expand Down
4 changes: 2 additions & 2 deletions src/rt/cpp/vaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace verona::rt
friend class Cown;

private:
static void gc_trace(const Action* msg, ObjectStack* st)
static void gc_trace(const Action* msg, ObjectStack& st)
{
(static_cast<const T*>(msg))->trace(st);
}
Expand All @@ -51,7 +51,7 @@ namespace verona::rt
return &desc;
}

void trace(ObjectStack*) const {}
void trace(ObjectStack&) const {}

public:
VAction() : Action(desc())
Expand Down
28 changes: 6 additions & 22 deletions src/rt/cpp/vobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,6 @@ namespace verona::rt
//
// This is better than ignoring methods with the right name but the wrong
// signature.
template<class T, class = void>
struct has_trace_possibly_iso : std::false_type
{};
template<class T>
struct has_trace_possibly_iso<
T,
std::void_t<decltype(&T::trace_possibly_iso)>> : std::true_type
{};

template<class T, class = void>
struct has_notified : std::false_type
{};
Expand Down Expand Up @@ -66,27 +57,21 @@ namespace verona::rt

using RegionClass = typename RegionType_to_class<region_type>::T;

static void gc_trace(const Object* o, ObjectStack* st)
static void gc_trace(const Object* o, ObjectStack& st)
{
((T*)o)->trace(st);
}

static void gc_trace_possibly_iso(const Object* o, ObjectStack* st)
{
if constexpr (has_trace_possibly_iso<T>::value)
((T*)o)->trace_possibly_iso(st);
}

static void gc_notified(Object* o)
{
if constexpr (has_notified<T>::value)
((T*)o)->notified(o);
}

static void gc_final(Object* o)
static void gc_final(Object* o, Object* region, ObjectStack& sub_regions)
{
if constexpr (has_finaliser<T>::value)
((T*)o)->finaliser();
((T*)o)->finaliser(region, sub_regions);
}

static void gc_destructor(Object* o)
Expand All @@ -99,15 +84,14 @@ namespace verona::rt
static constexpr Descriptor desc = {
sizeof(T),
gc_trace,
has_trace_possibly_iso<T>::value ? gc_trace_possibly_iso : nullptr,
has_finaliser<T>::value ? gc_final : nullptr,
has_notified<T>::value ? gc_notified : nullptr,
has_destructor<T>::value ? gc_destructor : nullptr};

return &desc;
}

void trace(ObjectStack*) {}
void trace(ObjectStack&) {}

static EpochMark get_alloc_epoch()
{
Expand All @@ -131,7 +115,7 @@ namespace verona::rt
if constexpr (std::is_same_v<Base, Object>)
return RegionClass::template create<sizeof(T)>(alloc, desc());
else
return ThreadAlloc::get()->alloc<sizeof(T)>();
return alloc->alloc<sizeof(T)>();
}

void* operator new(size_t, Object* region)
Expand All @@ -148,7 +132,7 @@ namespace verona::rt
if constexpr (std::is_same_v<Base, Object>)
return RegionClass::template alloc<sizeof(T)>(alloc, region, desc());
else
return ThreadAlloc::get()->alloc<sizeof(T)>();
return alloc->alloc<sizeof(T)>();
}

void operator delete(void*)
Expand Down
59 changes: 25 additions & 34 deletions src/rt/object/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ namespace verona::rt
{
// for field in o do
// st.push(o.field)
using TraceFunction = void (*)(const Object* o, ObjectStack* st);
using TraceIsoFunction = void (*)(const Object* o, ObjectStack* st);
using TraceFunction = void (*)(const Object* o, ObjectStack& st);

using NotifiedFunction = void (*)(Object* o);

Expand All @@ -102,14 +101,15 @@ namespace verona::rt
// invalid state ie. close file descriptors or deallocate some auxiliary
// storage.
//
// The finaliser can extract sub-regions and eg. send them in a
// multi-message. The destructor on the other hand may not do this.
using FinalFunction = void (*)(Object* o);
// The finaliser can must add all the subregions reachable from this object
// to the ObjectStack it is passed, so that they can be deallocated once
// this region has been deallocated.
using FinalFunction = void (*)(Object* o, Object* region, ObjectStack& st);
mjp41 marked this conversation as resolved.
Show resolved Hide resolved

using DestructorFunction = void (*)(Object* o);

size_t size;
TraceFunction trace;
TraceIsoFunction trace_possibly_iso;
FinalFunction finaliser;
NotifiedFunction notified = nullptr;
DestructorFunction destructor = nullptr;
Expand Down Expand Up @@ -702,15 +702,9 @@ namespace verona::rt
return get_descriptor()->destructor != nullptr;
}

inline bool has_possibly_iso_fields()
{
return get_descriptor()->trace_possibly_iso != nullptr;
}

static inline bool is_trivial(const Descriptor* desc)
{
return desc->destructor == nullptr && desc->finaliser == nullptr &&
desc->trace_possibly_iso == nullptr;
return desc->destructor == nullptr && desc->finaliser == nullptr;
}

inline bool is_trivial()
Expand All @@ -729,18 +723,13 @@ namespace verona::rt
private:
inline void trace(ObjectStack& f) const
{
get_descriptor()->trace(this, &f);
}

inline void trace_possibly_iso(ObjectStack& f) const
{
get_descriptor()->trace_possibly_iso(this, &f);
get_descriptor()->trace(this, f);
}

inline void finalise()
inline void finalise(Object* region, ObjectStack& isos)
{
if (has_finaliser())
get_descriptor()->finaliser(this);
get_descriptor()->finaliser(this, region, isos);
}

inline void notified()
Expand All @@ -760,21 +749,23 @@ namespace verona::rt
alloc->dealloc(this, size());
}

inline void
find_iso_fields(Object* region_entry, ObjectStack& f, ObjectStack& iso_st)
protected:
static void
add_sub_region(Object* obj, Object* region, ObjectStack& sub_regions)
{
// Find all isolated fields in p other than some predecessor o.
if (!has_possibly_iso_fields())
return;

trace_possibly_iso(f);

while (!f.empty())
// Should be the entry-point of the region.
assert(
(region == nullptr) || (region->get_class() == Object::RegionMD::ISO));
// Have to be careful about internal references to the entry point for the
// `region` i.e. when obj == region we are refering to the entry point
// from inside the region and should not treat this as a subregion
// pointer.
if ((obj != nullptr) && (obj != region))
mjp41 marked this conversation as resolved.
Show resolved Hide resolved
{
Object* o = f.pop();

if ((o != region_entry) && (o->get_class() == Object::ISO))
iso_st.push(o);
if (obj->get_class() == Object::RegionMD::ISO)
{
sub_regions.push(obj);
}
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/rt/region/externalreference.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace verona::rt
// The object externally referred to
Object* o;

static void gc_trace(const Object*, ObjectStack*) {}
static void gc_trace(const Object*, ObjectStack&) {}

static const Descriptor* desc()
{
Expand Down
Loading