Skip to content

Commit

Permalink
Merge pull request #37 from mjp41/region_object
Browse files Browse the repository at this point in the history
Refactoring
  • Loading branch information
mjp41 authored Oct 25, 2024
2 parents be9a1b0 + 6a23ff2 commit 7fc63d3
Show file tree
Hide file tree
Showing 9 changed files with 286 additions and 293 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ set(CMAKE_CXX_STANDARD 20)
add_library(
rt OBJECT
src/rt/rt.cc
src/rt/objects/region.cc
src/rt/ui/mermaid.cc
src/rt/core/builtin.cc
)
Expand Down
21 changes: 3 additions & 18 deletions src/rt/core.h
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
#include "objects/dyn_object.h"
#include "objects/prototype_object.h"
#include "rt.h"

#include <map>

namespace rt::core
{
class PrototypeObject : public objects::DynObject
{
std::string name;

public:
PrototypeObject(std::string name_, objects::DynObject* prototype = nullptr)
: objects::DynObject(prototype), name(name_)
{}

std::string get_name() override
{
std::stringstream stream;
stream << "[" << name << "]";
return stream.str();
}
};
using PrototypeObject = objects::PrototypeObject;

inline PrototypeObject* framePrototypeObject()
{
Expand All @@ -39,7 +24,7 @@ namespace rt::core
if (parent_frame)
{
auto old_value = this->set(objects::ParentField, parent_frame);
add_reference(this, parent_frame);
objects::add_reference(this, parent_frame);
assert(!old_value);
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/rt/core/builtin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace rt::core
{
auto value = stack->back();
mermaid->add_always_hide(value);
remove_reference(frame, value);
rt::remove_reference(frame, value);
stack->pop_back();
}

Expand All @@ -42,7 +42,7 @@ namespace rt::core
auto value = stack->back();
mermaid->remove_unreachable_hide(value);
mermaid->remove_always_hide(value);
remove_reference(frame, value);
rt::remove_reference(frame, value);
stack->pop_back();
}

Expand Down Expand Up @@ -74,7 +74,7 @@ namespace rt::core

auto region = pop(stack, "region for cown creation");
auto cown = make_cown(region);
move_reference(frame, cown, region);
rt::move_reference(frame, cown, region);

return cown;
});
Expand All @@ -97,7 +97,7 @@ namespace rt::core

auto value = pop(stack, "object to freeze");
freeze(value);
remove_reference(frame, value);
rt::remove_reference(frame, value);

return std::nullopt;
});
Expand All @@ -106,8 +106,8 @@ namespace rt::core
assert(args == 1);

auto value = pop(stack, "region source");
create_region(value);
remove_reference(frame, value);
rt::create_region(value);
rt::remove_reference(frame, value);

return std::nullopt;
});
Expand Down
233 changes: 14 additions & 219 deletions src/rt/objects/dyn_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ namespace rt::objects
const std::string PrototypeField{"__proto__"};
const std::string ParentField{"__parent__"};

Region* get_region(DynObject* obj);

Region* get_local_region();
void set_local_region(Region* region);

// Representation of objects
class DynObject
{
Expand All @@ -39,8 +44,8 @@ namespace rt::objects
friend void dealloc(DynObject* obj);
template<typename Pre, typename Post>
friend void visit(Edge, Pre, Post);

thread_local static RegionPointer local_region;
friend Region* get_region(DynObject* obj);
friend void add_to_region(Region* r, DynObject* target);

// TODO: Not concurrency safe
inline static size_t count{0};
Expand All @@ -53,68 +58,7 @@ namespace rt::objects

std::map<std::string, DynObject*> fields{};

static Region* get_region(DynObject* obj)
{
if ((obj == nullptr) || obj->is_immutable())
return nullptr;
return obj->region.get_ptr();
}

bool is_local_object()
{
return region.get_ptr() == get_local_region();
}

static void remove_region_reference(Region* src, Region* target)
{
if (src == target)
{
std::cout << "Same region, no need to do anything" << std::endl;
return;
}

// Handle immutable case
if (target == nullptr)
return;

if (src == get_local_region())
{
Region::dec_lrc(target);
return;
}

if (src)
{
assert(target->parent == src);
Region::dec_prc(target);
}
return;
}

static void add_region_reference(Region* src_region, DynObject* target)
{
if (target->is_immutable())
return;

auto target_region = get_region(target);
if (src_region == target_region)
return;

if (src_region == get_local_region())
{
Region::inc_lrc(target_region);
return;
}

if (target_region == get_local_region())
{
target->add_to_region(src_region);
return;
}

Region::set_parent(target_region, src_region);
}

public:
size_t change_rc(signed delta)
{
std::cout << "Change RC: " << get_name() << " " << rc << " + " << delta
Expand All @@ -134,50 +78,6 @@ namespace rt::objects
delta;
}

void add_to_region(Region* r)
{
size_t internal_references{0};
size_t rc_of_added_objects{0};
visit(this, [&](Edge e) {
auto obj = e.target;
if (obj == nullptr || obj->is_immutable())
return false;

if (obj->is_local_object())
{
std::cout << "Adding object to region: " << obj->get_name()
<< " rc = " << obj->rc << std::endl;
rc_of_added_objects += obj->rc;
internal_references++;
obj->region = {r};
get_local_region()->objects.erase(obj);
r->objects.insert(obj);
return true;
}

auto obj_region = get_region(obj);
if (obj_region == r)
{
std::cout << "Adding internal reference to object: "
<< obj->get_name() << std::endl;
internal_references++;
return false;
}

Region::set_parent(obj_region, r);
Region::dec_lrc(obj_region);
return false;
});
r->local_reference_count += rc_of_added_objects - internal_references;

std::cout << "Added " << rc_of_added_objects - internal_references
<< " to LRC of region" << std::endl;
std::cout << "Region LRC: " << r->local_reference_count << std::endl;
std::cout << "Internal references found: " << internal_references
<< std::endl;
}

public:
// prototype is borrowed, the caller does not need to provide an RC.
DynObject(DynObject* prototype_ = nullptr, bool first_frame = false)
: prototype(prototype_)
Expand All @@ -194,7 +94,7 @@ namespace rt::objects
if (prototype != nullptr)
{
// prototype->change_rc(1);
add_reference(this, prototype);
objects::add_reference(this, prototype);
}
std::cout << "Allocate: " << this << std::endl;
}
Expand Down Expand Up @@ -224,6 +124,11 @@ namespace rt::objects
std::cout << "Deallocate: " << get_name() << std::endl;
}

size_t get_rc()
{
return rc;
}

/// @brief The string representation of this value to
/// TODO remove virtual once we have primitive functions.
virtual std::string get_name()
Expand Down Expand Up @@ -333,127 +238,17 @@ namespace rt::objects
return prototype;
}

static void add_reference(DynObject* src, DynObject* target)
{
if (target == nullptr)
return;

target->change_rc(1);

auto src_region = get_region(src);
add_region_reference(src_region, target);
}

static void
remove_reference(DynObject* src_initial, DynObject* old_dst_initial)
{
visit(
{src_initial, "", old_dst_initial},
[&](Edge e) {
if (e.target == nullptr)
return false;

std::cout << "Remove reference from: " << e.src->get_name() << " to "
<< e.target->get_name() << std::endl;
bool result = e.target->change_rc(-1) == 0;

remove_region_reference(get_region(e.src), get_region(e.target));
return result;
},
[&](DynObject* obj) { delete obj; });

Region::collect();
}

static void
move_reference(DynObject* src, DynObject* dst, DynObject* target)
{
if (target == nullptr || target->is_immutable())
return;

auto src_region = get_region(src);
auto dst_region = get_region(dst);

if (src_region == dst_region)
return;

auto target_region = get_region(target);

add_region_reference(dst_region, target);
// Note that target_region and get_region(target) are not necessarily the
// same.
remove_region_reference(src_region, target_region);
}

void create_region()
{
Region* r = new Region();
add_to_region(r);
// Add root reference as external.
r->local_reference_count++;
}

static size_t get_count()
{
return count;
}

static Region* get_local_region()
{
return local_region;
}

static std::set<DynObject*> get_objects()
{
return all_objects;
}
};

inline void destruct(DynObject* obj)
{
// Called from the region destructor.
// Remove all references to other objects.
// If in the same region, then just remove the RC, but don't try to collect
// as the whole region is being torndown including any potential cycles.
auto same_region = [](DynObject* src, DynObject* target) {
return DynObject::get_region(src) == DynObject::get_region(target);
};
for (auto& [key, field] : obj->fields)
{
if (field == nullptr)
continue;
if (same_region(obj, field))
{
// Same region just remove the rc, but don't try to collect.
field->change_rc(-1);
continue;
}

auto old_value = obj->set(key, nullptr);
remove_reference(obj, old_value);
}

if (same_region(obj, obj->prototype))
{
obj->prototype->change_rc(-1);
}
else
{
auto old_value = obj->set_prototype(nullptr);
remove_reference(obj, old_value);
}
}

inline void dealloc(DynObject* obj)
{
// Called from the region destructor.
// So remove from region if in one.
// This ensures we don't try to remove it from the set that is being
// iterated.
obj->region = nullptr;
delete obj;
}

template<typename Pre, typename Post>
inline void visit(Edge e, Pre pre, Post post)
{
Expand Down
Loading

0 comments on commit 7fc63d3

Please sign in to comment.