From 450dda40a8defbb8516ac97b6836125cba34122e Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 18 Oct 2024 14:37:24 +0200 Subject: [PATCH] Cown: Reifing cown objects --- src/rt/core.h | 49 +++++++++++++++++++++++++++++++++++++ src/rt/objects/dyn_object.h | 18 +++++++++++--- src/rt/rt.cc | 27 ++++++++++++++++++++ src/rt/rt.h | 1 + 4 files changed, 91 insertions(+), 4 deletions(-) diff --git a/src/rt/core.h b/src/rt/core.h index e4acfc0..c4f1e52 100644 --- a/src/rt/core.h +++ b/src/rt/core.h @@ -174,6 +174,54 @@ namespace rt::core } }; + // The prototype object for cown + inline PrototypeObject* cownPrototypeObject() + { + static PrototypeObject* proto = new PrototypeObject("Cown"); + return proto; + } + + class CownObject : public objects::DynObject + { + // For now always false, but might be needed later if we want to simulate + // concurrency. + bool aquired = false; + + public: + CownObject(objects::DynObject* region) + : objects::DynObject(cownPrototypeObject()), + { + // FIXME: Add once regions are reified + // assert( + // region->get_prototype() == regionPrototype() && + // "Cowns can only store regions"); + // + // FIXME: Also check that the region has a LRC == 1, with 1 + // being the reference passed into this constructor + this->set("region", region); + } + + bool is_aquired() + { + return aquired; + } + + std::string get_name() + { + return ""; + } + + objects::DynObject* is_primitive() + { + return this; + } + + bool is_cown() override + { + return false; + } + }; + inline std::set* globals() { static std::set* globals = @@ -185,6 +233,7 @@ namespace rt::core keyIterPrototypeObject(), trueObject(), falseObject(), + cownPrototypeObject(), }; return globals; } diff --git a/src/rt/objects/dyn_object.h b/src/rt/objects/dyn_object.h index b12ee5d..a5285e9 100644 --- a/src/rt/objects/dyn_object.h +++ b/src/rt/objects/dyn_object.h @@ -27,8 +27,10 @@ namespace rt::objects { friend class Reference; friend objects::DynObject* rt::make_iter(objects::DynObject* obj); - friend void - rt::ui::mermaid(std::vector& roots, std::ostream& out, std::vector* taint); + friend void rt::ui::mermaid( + std::vector& roots, + std::ostream& out, + std::vector* taint); friend void destruct(DynObject* obj); friend void dealloc(DynObject* obj); template @@ -241,7 +243,8 @@ namespace rt::objects get_region(obj)->objects.erase(obj); } obj->region.set_tag(ImmutableTag); - return true; + + return !obj->is_cown(); }); } @@ -250,6 +253,11 @@ namespace rt::objects return region.get_tag() == ImmutableTag; } + virtual bool is_cown() + { + return false; + } + [[nodiscard]] DynObject* get(std::string name) { auto result = fields.find(name); @@ -270,7 +278,7 @@ namespace rt::objects [[nodiscard]] DynObject* set(std::string name, DynObject* value) { - if (is_immutable()) + if (is_immutable() && this->is_cown()) { ui::error("Cannot mutate immutable object"); } @@ -282,6 +290,7 @@ namespace rt::objects // The caller must provide an rc for value. [[nodiscard]] DynObject* set_prototype(DynObject* value) { + // No need to check for a cown, since cowns already have a set prototype if (is_immutable()) { ui::error("Cannot mutate immutable object"); @@ -331,6 +340,7 @@ namespace rt::objects static void move_reference(DynObject* src, DynObject* dst, DynObject* target) { + // An immutable cown can't be moved to another region if (target == nullptr || target->is_immutable()) return; diff --git a/src/rt/rt.cc b/src/rt/rt.cc index 6c46386..a24ee65 100644 --- a/src/rt/rt.cc +++ b/src/rt/rt.cc @@ -34,11 +34,18 @@ namespace rt return new core::FrameObject(parent); } + objects::DynObject* make_cown(objects::DynObject* region) + { + return new core::CownObject(region); + } + thread_local objects::RegionPointer objects::DynObject::local_region = new Region(); void freeze(objects::DynObject* obj) { + // Cown specific handling of the freeze operation is handled by the + // `freeze()` implementation of the object obj->freeze(); } @@ -49,6 +56,15 @@ namespace rt objects::DynObject* get(objects::DynObject* obj, std::string key) { + if (obj->get_prototype() == core::cownPrototypeObject()) + { + core::CownObject* cown = reinterpret_cast(obj); + if (!cown->is_aquired()) + { + ui::error( + "the cown needs to be aquired, before its data can be accessed"); + } + } return obj->get(key); } @@ -72,6 +88,17 @@ namespace rt objects::DynObject* set(objects::DynObject* obj, std::string key, objects::DynObject* value) { + if (obj->get_prototype() == core::cownPrototypeObject()) + { + core::CownObject* cown = reinterpret_cast(obj); + if (!cown->is_aquired()) + { + // Overwriting data can change the RC and then call destructors of the + // type this action therefore requires the cown to be aquired + ui::error("the cown needs to be aquired, before its data can modified"); + } + } + return obj->set(key, value); } diff --git a/src/rt/rt.h b/src/rt/rt.h index 4fc2046..9eea970 100644 --- a/src/rt/rt.h +++ b/src/rt/rt.h @@ -15,6 +15,7 @@ namespace rt objects::DynObject* make_str(std::string str_value); objects::DynObject* make_object(); objects::DynObject* make_frame(objects::DynObject* parent); + objects::DynObject* make_cown(objects::DynObject* region); void freeze(objects::DynObject* obj); void create_region(objects::DynObject* objects);