From 9ce92a38359eb70c03756f7523fcc0278e80d014 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 1 Nov 2024 10:34:33 +0100 Subject: [PATCH 01/10] Mermaid: Increase font size --- src/rt/ui/mermaid.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/rt/ui/mermaid.cc b/src/rt/ui/mermaid.cc index 9614c22..7a0a5c4 100644 --- a/src/rt/ui/mermaid.cc +++ b/src/rt/ui/mermaid.cc @@ -24,6 +24,8 @@ namespace rt::ui const char* IMM_REGION_ID = "ImmReg"; const char* COWN_REGION_ID = "CownReg"; + const char* FONT_SIZE = "16px"; + void replace(std::string& text, std::string from, std::string replace) { size_t pos = 0; @@ -90,6 +92,8 @@ namespace rt::ui { // Header out << "```mermaid" << std::endl; + out << "%%{init: {'themeVariables': { 'fontSize': '" << FONT_SIZE + << "' }}}%%"; out << "graph TD" << std::endl; draw_nodes(roots); From 96f4835866d8a34f4fdf7b39cc89d72a6d4df21b Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 1 Nov 2024 11:29:19 +0100 Subject: [PATCH 02/10] Mermaid: Display LRC/SBRC in regions's bridge object --- src/rt/core.h | 2 +- src/rt/objects/region.cc | 4 ++-- src/rt/objects/region_object.h | 20 +++++++++++++++----- src/rt/ui/mermaid.cc | 28 +++++++++++++++++++++------- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/rt/core.h b/src/rt/core.h index 5828145..b6a7ada 100644 --- a/src/rt/core.h +++ b/src/rt/core.h @@ -233,7 +233,7 @@ namespace rt::core { static std::set* globals = new std::set{ - objects::regionObjectPrototypeObject(), + objects::regionPrototypeObject(), framePrototypeObject(), funcPrototypeObject(), bytecodeFuncPrototypeObject(), diff --git a/src/rt/objects/region.cc b/src/rt/objects/region.cc index 4958010..6860e74 100644 --- a/src/rt/objects/region.cc +++ b/src/rt/objects/region.cc @@ -52,7 +52,7 @@ namespace rt::objects return false; } - if (obj->get_prototype() != objects::regionObjectPrototypeObject()) + if (obj->get_prototype() != objects::regionPrototypeObject()) { ui::error("Cannot add interior region object to another region"); } @@ -133,7 +133,7 @@ namespace rt::objects return; } - if (target->get_prototype() != objects::regionObjectPrototypeObject()) + if (target->get_prototype() != objects::regionPrototypeObject()) { ui::error("Cannot add interior region object to another region"); } diff --git a/src/rt/objects/region_object.h b/src/rt/objects/region_object.h index 4847f6a..595a81a 100644 --- a/src/rt/objects/region_object.h +++ b/src/rt/objects/region_object.h @@ -1,11 +1,12 @@ #pragma once #include "prototype_object.h" +#include "region.h" namespace rt::objects { // The prototype object for region entry point objects - inline PrototypeObject* regionObjectPrototypeObject() + inline PrototypeObject* regionPrototypeObject() { static PrototypeObject* proto = new PrototypeObject("RegionObject"); return proto; @@ -14,8 +15,17 @@ namespace rt::objects class RegionObject : public DynObject { public: - RegionObject(Region* region) - : DynObject(regionObjectPrototypeObject(), region) - {} + RegionObject(Region* region) : DynObject(regionPrototypeObject(), region) {} + + std::string get_name() override + { + auto region = get_region(this); + + std::stringstream stream; + stream << this << std::endl; + stream << "lrc=" << region->local_reference_count << std::endl; + stream << "sbrc=" << region->sub_region_reference_count; + return stream.str(); + } }; -} \ No newline at end of file +} diff --git a/src/rt/ui/mermaid.cc b/src/rt/ui/mermaid.cc index 7a0a5c4..8f70900 100644 --- a/src/rt/ui/mermaid.cc +++ b/src/rt/ui/mermaid.cc @@ -46,6 +46,7 @@ namespace rt::ui replace(text, "<", "#60;"); replace(text, ">", "#62;"); replace(text, "\"", "#34;"); + replace(text, "\n", "
"); return text; } @@ -114,6 +115,22 @@ namespace rt::ui } private: + std::pair + get_node_markers(objects::DynObject* obj) + { + if (obj->get_prototype() == core::cownPrototypeObject()) + { + return {"[[", "]]"}; + } + + if (obj->get_prototype() == objects::regionPrototypeObject()) + { + return {"[\\", "/]"}; + } + + return {"[", "]"}; + } + /// @brief Draws the target node and the edge from the source to the target. NodeInfo* draw_edge(objects::Edge e, bool reachable) { @@ -144,10 +161,11 @@ namespace rt::ui // Draw a new node nodes[dst] = {id_counter++, dst->is_opaque()}; auto node = &nodes[dst]; + auto markers = get_node_markers(dst); // Header out << *node; - out << (dst->is_cown() ? "[[" : "["); + out << markers.first; // Content out << escape(dst->get_name()); @@ -155,7 +173,7 @@ namespace rt::ui out << (rt::core::globals()->contains(dst) ? " #40;global#41;" : ""); // Footer - out << (dst->is_cown() ? "]]" : "]"); + out << markers.second; out << (reachable ? "" : ":::unreachable"); out << std::endl; @@ -267,11 +285,7 @@ namespace rt::ui } else { - out << " " << std::endl; - out << " region" << region << "[\\" << region - << "
lrc=" << region->local_reference_count - << "
sbrc=" << region->sub_region_reference_count << "/]" - << std::endl; + out << "region" << region << "[\" \"]" << std::endl; } for (auto obj : objects) { From e9ef82ca4c6b42fc73f219f4f1c7fea9a17988dc Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 1 Nov 2024 11:51:16 +0100 Subject: [PATCH 03/10] Mermaid: Use dotted arrows for borrows --- src/rt/ui/mermaid.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/rt/ui/mermaid.cc b/src/rt/ui/mermaid.cc index 8f70900..459b1f0 100644 --- a/src/rt/ui/mermaid.cc +++ b/src/rt/ui/mermaid.cc @@ -115,8 +115,7 @@ namespace rt::ui } private: - std::pair - get_node_markers(objects::DynObject* obj) + std::pair get_node_style(objects::DynObject* obj) { if (obj->get_prototype() == core::cownPrototypeObject()) { @@ -131,6 +130,13 @@ namespace rt::ui return {"[", "]"}; } + bool is_borrow_edge(objects::Edge e) + { + return e.src != nullptr && e.target != nullptr && + objects::get_region(e.src) != objects::get_region(e.target) && + objects::get_region(e.src) == objects::get_local_region(); + } + /// @brief Draws the target node and the edge from the source to the target. NodeInfo* draw_edge(objects::Edge e, bool reachable) { @@ -144,7 +150,7 @@ namespace rt::ui { auto src_node = &nodes[src]; out << " " << *src_node; - out << ((src_node->is_opaque) ? "-.->" : "-->"); + out << (is_borrow_edge(e) ? "-.->" : "-->"); out << " |" << escape(e.key) << "| "; edge_id = edge_counter; edge_counter += 1; @@ -161,7 +167,7 @@ namespace rt::ui // Draw a new node nodes[dst] = {id_counter++, dst->is_opaque()}; auto node = &nodes[dst]; - auto markers = get_node_markers(dst); + auto markers = get_node_style(dst); // Header out << *node; From c8daa5b89e3472d6583d9fe2d4390db798aa3352 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 1 Nov 2024 13:21:14 +0100 Subject: [PATCH 04/10] Fix CI --- CMakeLists.txt | 2 +- src/rt/objects/region.cc | 16 ++++++++++++++++ src/rt/objects/region.h | 13 +------------ tests/cowns/valid_01.vpy | 1 - .../fail_cross_region_ref.vpy} | 0 5 files changed, 18 insertions(+), 14 deletions(-) rename tests/{region/fail_cross_region_reg.vpy => regions/fail_cross_region_ref.vpy} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 01f2380..1836e2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,6 @@ set_property(TEST leak_with_global.vpy PROPERTY WILL_FAIL true) set_property(TEST invalid_read.vpy PROPERTY WILL_FAIL true) set_property(TEST invalid_shared_region.vpy PROPERTY WILL_FAIL true) set_property(TEST invalid_write.vpy PROPERTY WILL_FAIL true) -set_property(TEST fail_cross_region_reg.vpy PROPERTY WILL_FAIL true) set_property(TEST region_bad_1.vpy PROPERTY WILL_FAIL true) set_property(TEST region_bad_2.vpy PROPERTY WILL_FAIL true) +set_property(TEST fail_cross_region_ref.vpy PROPERTY WILL_FAIL true) diff --git a/src/rt/objects/region.cc b/src/rt/objects/region.cc index 6860e74..459f0ca 100644 --- a/src/rt/objects/region.cc +++ b/src/rt/objects/region.cc @@ -251,4 +251,20 @@ namespace rt::objects return obj; } + void Region::action(Region* r) + { + if ((r->local_reference_count == 0) && (r->parent == nullptr)) + { + // TODO, this can be hooked to perform delayed operations like send. + // Needs to check for sub_region_reference_count for send, but not + // deallocate. + + if (r != get_local_region() && r != cown_region) + { + to_collect.push_back(r); + std::cout << "Collecting region: " << r << std::endl; + } + } + } + } diff --git a/src/rt/objects/region.h b/src/rt/objects/region.h index 9344127..060459a 100644 --- a/src/rt/objects/region.h +++ b/src/rt/objects/region.h @@ -55,18 +55,7 @@ namespace rt::objects return local_reference_count + sub_region_reference_count; } - static void action(Region* r) - { - if ((r->local_reference_count == 0) && (r->parent == nullptr)) - { - // TODO, this can be hooked to perform delayed operations like send. - // Needs to check for sub_region_reference_count for send, but not - // deallocate. - - to_collect.push_back(r); - std::cout << "Collecting region: " << r << std::endl; - } - } + static void action(Region*); static void dec_lrc(Region* r) { diff --git a/tests/cowns/valid_01.vpy b/tests/cowns/valid_01.vpy index da22a09..121ea1b 100644 --- a/tests/cowns/valid_01.vpy +++ b/tests/cowns/valid_01.vpy @@ -4,7 +4,6 @@ global = {} a = Region() a.b = {} - c01 = cown(move a) # Store the cown in a global diff --git a/tests/region/fail_cross_region_reg.vpy b/tests/regions/fail_cross_region_ref.vpy similarity index 100% rename from tests/region/fail_cross_region_reg.vpy rename to tests/regions/fail_cross_region_ref.vpy From 1d3069762b4908606be7f15107e8835c1464bf35 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 1 Nov 2024 14:07:42 +0100 Subject: [PATCH 05/10] Mermaid: Mark immutable nodes by color and hide the immutable region --- docs/builtin.md | 14 +++++++++++--- src/rt/core/builtin.cc | 13 +++++++++++++ src/rt/objects/region.cc | 1 - src/rt/ui.h | 1 + src/rt/ui/mermaid.cc | 27 ++++++++++++++++++++++----- 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/docs/builtin.md b/docs/builtin.md index 2dfdce6..03395c5 100644 --- a/docs/builtin.md +++ b/docs/builtin.md @@ -12,7 +12,7 @@ Aborts the interpreter process. It's intended to indicate that an execution bran ## Constructors -#### `region()` +#### `Region()` Creates a new region object. @@ -74,7 +74,15 @@ This explicitly shows the "Cown region" in the generated diagrams. #### `mermaid_hide_cown_region()` -This hides the "Cown region" and cown prototype in diagram. (This is the default) +This hides the "Cown region" and cown prototype in diagram. (Default) + +#### `mermaid_show_immutable_region()` + +This explicitly shows the "Immutable region" in the generated diagrams + +#### `mermaid_hide_immutable_region()` + +This hides the "Immutable region" in diagram. (Default) #### `mermaid_show_functions()` @@ -82,4 +90,4 @@ Shows user defined functions in the diagram. #### `mermaid_hide_functions()` -Hides user defined functions in the diagram. (This is the default) +Hides user defined functions in the diagram. (Default) diff --git a/src/rt/core/builtin.cc b/src/rt/core/builtin.cc index 3656029..af0e478 100644 --- a/src/rt/core/builtin.cc +++ b/src/rt/core/builtin.cc @@ -124,6 +124,19 @@ namespace rt::core return std::nullopt; }); + add_builtin( + "mermaid_show_immutable_region", [mermaid](auto, auto, auto args) { + assert(args == 0); + mermaid->draw_immutable_region = true; + return std::nullopt; + }); + add_builtin( + "mermaid_hide_immutable_region", [mermaid](auto, auto, auto args) { + assert(args == 0); + mermaid->draw_immutable_region = false; + return std::nullopt; + }); + add_builtin("mermaid_show_functions", [mermaid](auto, auto, auto args) { assert(args == 0); mermaid->show_functions(); diff --git a/src/rt/objects/region.cc b/src/rt/objects/region.cc index 459f0ca..68bee31 100644 --- a/src/rt/objects/region.cc +++ b/src/rt/objects/region.cc @@ -266,5 +266,4 @@ namespace rt::objects } } } - } diff --git a/src/rt/ui.h b/src/rt/ui.h index 816e02e..7e86a91 100644 --- a/src/rt/ui.h +++ b/src/rt/ui.h @@ -57,6 +57,7 @@ namespace rt::ui std::set taint; /// Indicates if the cown region show be explicitly drawn bool draw_cown_region; + bool draw_immutable_region; /// Indicates if local functions should be visible bool draw_funcs; diff --git a/src/rt/ui/mermaid.cc b/src/rt/ui/mermaid.cc index 459b1f0..aedd914 100644 --- a/src/rt/ui/mermaid.cc +++ b/src/rt/ui/mermaid.cc @@ -17,7 +17,8 @@ namespace rt::ui const char* UNREACHABLE_NODE_COLOR = "red"; const char* ERROR_NODE_COLOR = "red"; - const char* IMMUTABLE_REGION_COLOR = "#32445d"; + const char* IMMUTABLE_NODE_COLOR = "#243042"; + const char* IMMUTABLE_REGION_COLOR = "#485464"; const char* IMMUTABLE_EDGE_COLOR = "#94f7ff"; const char* LOCAL_REGION_ID = "LocalReg"; @@ -96,6 +97,7 @@ namespace rt::ui out << "%%{init: {'themeVariables': { 'fontSize': '" << FONT_SIZE << "' }}}%%"; out << "graph TD" << std::endl; + out << " id0(None):::immutable" << std::endl; draw_nodes(roots); draw_regions(); @@ -103,13 +105,12 @@ namespace rt::ui draw_error(); draw_info(); - out << "style " << IMM_REGION_ID << " fill:" << IMMUTABLE_REGION_COLOR - << std::endl; out << "classDef unreachable stroke-width:2px,stroke:" << UNREACHABLE_NODE_COLOR << std::endl; out << "classDef error stroke-width:4px,stroke:" << ERROR_NODE_COLOR << std::endl; out << "classDef tainted fill:" << TAINT_NODE_COLOR << std::endl; + out << "classDef immutable fill:" << IMMUTABLE_NODE_COLOR << std::endl; // Footer (end of mermaid graph) out << "```" << std::endl; } @@ -127,6 +128,12 @@ namespace rt::ui return {"[\\", "/]"}; } + if (obj->is_immutable()) + { + // Make sure to also update the None node, when editing these + return {"(", ")"}; + } + return {"[", "]"}; } @@ -181,6 +188,7 @@ namespace rt::ui // Footer out << markers.second; out << (reachable ? "" : ":::unreachable"); + out << (dst->is_immutable() ? ":::immutable" : ""); out << std::endl; result = node; @@ -266,7 +274,10 @@ namespace rt::ui // Output all the region membership information for (auto [region, objects] : region_strings) { - if ((!info->draw_cown_region) && region == objects::cown_region) + if ( + ((!info->draw_cown_region) && region == objects::cown_region) || + ((!info->draw_immutable_region) && + region == objects::immutable_region)) { continue; } @@ -280,7 +291,7 @@ namespace rt::ui else if (region == objects::immutable_region) { out << IMM_REGION_ID << "[\"Immutable region\"]" << std::endl; - out << " id0[nullptr]" << std::endl; + out << " id0" << std::endl; } else if (region == objects::cown_region) { @@ -299,6 +310,12 @@ namespace rt::ui } out << "end" << std::endl; } + + if (info->draw_immutable_region) + { + out << "style " << IMM_REGION_ID << " fill:" << IMMUTABLE_REGION_COLOR + << std::endl; + } } void draw_taint() From 75b005636647f2a1ee249c7a9e2ff3eb72bc79dc Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 1 Nov 2024 14:08:49 +0100 Subject: [PATCH 06/10] Mermaid: Remove info node --- src/rt/ui/mermaid.cc | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/rt/ui/mermaid.cc b/src/rt/ui/mermaid.cc index aedd914..7805486 100644 --- a/src/rt/ui/mermaid.cc +++ b/src/rt/ui/mermaid.cc @@ -103,7 +103,6 @@ namespace rt::ui draw_regions(); draw_taint(); draw_error(); - draw_info(); out << "classDef unreachable stroke-width:2px,stroke:" << UNREACHABLE_NODE_COLOR << std::endl; @@ -359,24 +358,6 @@ namespace rt::ui out << "class " << *node_info << " error;" << std::endl; } } - - void draw_info() - { - auto globals = rt::core::globals(); - auto local_ctn = objects::DynObject::get_count() - globals->size(); - - // Header - out << "subgraph info" << std::endl; - out << " i01["; - - // Info - out << "Locals: " << local_ctn << "
"; - out << "Globals: " << globals->size() << "
"; - - // Footer - out << "]" << std::endl; - out << "end" << std::endl; - } }; MermaidUI::MermaidUI() From 3bb2eb5a44e9158a716bede1bf0492797eda11d5 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 1 Nov 2024 16:11:47 +0100 Subject: [PATCH 07/10] Mermaid: Draw nested regions as nested subgraphs --- src/rt/ui/mermaid.cc | 147 ++++++++++++++++++++++++-------------- tests/regions/region4.vpy | 30 ++++++++ 2 files changed, 124 insertions(+), 53 deletions(-) create mode 100644 tests/regions/region4.vpy diff --git a/src/rt/ui/mermaid.cc b/src/rt/ui/mermaid.cc index 7805486..79c0d4c 100644 --- a/src/rt/ui/mermaid.cc +++ b/src/rt/ui/mermaid.cc @@ -21,6 +21,9 @@ namespace rt::ui const char* IMMUTABLE_REGION_COLOR = "#485464"; const char* IMMUTABLE_EDGE_COLOR = "#94f7ff"; + const char* REGION_COLORS[] = { + "#666", "#555", "#444", "#333", "#222", "#111"}; + const char* LOCAL_REGION_ID = "LocalReg"; const char* IMM_REGION_ID = "ImmReg"; const char* COWN_REGION_ID = "CownReg"; @@ -64,6 +67,13 @@ namespace rt::ui return os; } + struct RegionInfo + { + std::vector nodes; + std::vector regions; + bool drawn; + }; + class MermaidDiagram { MermaidUI* info; @@ -75,13 +85,14 @@ namespace rt::ui // Give a nice id to each object. std::map nodes; std::map> region_strings; + std::map regions; public: MermaidDiagram(MermaidUI* info_) : info(info_), out(info->out) { // Add nullptr nodes[nullptr] = {0}; - region_strings[rt::objects::immutable_region].push_back(0); + regions[objects::immutable_region].nodes.push_back(0); } void color_edge(size_t edge_id, const char* color) @@ -186,8 +197,9 @@ namespace rt::ui // Footer out << markers.second; - out << (reachable ? "" : ":::unreachable"); - out << (dst->is_immutable() ? ":::immutable" : ""); + out + << (dst->is_immutable() ? ":::immutable" : + (reachable ? "" : ":::unreachable")); out << std::endl; result = node; @@ -232,7 +244,7 @@ namespace rt::ui auto region = objects::get_region(dst); if (region != nullptr) { - region_strings[region].push_back(node->id); + regions[region].nodes.push_back(node->id); } return true; @@ -251,70 +263,99 @@ namespace rt::ui } } - void draw_regions() + void + draw_region_body(objects::Region* r, RegionInfo* info, std::string& indent) { - // Output any region parent edges. - for (auto [region, objects] : region_strings) + indent += " "; + for (auto obj : info->nodes) { - if (region->parent == nullptr) - { - continue; - } - if ((!info->draw_cown_region) && region->parent == objects::cown_region) - { - continue; - } - - out << " region" << region->parent << " <-.-o region" << region - << std::endl; - edge_counter += 1; + out << indent << "id" << obj << std::endl; } + for (auto reg : info->regions) + { + draw_region(reg, indent); + } + indent.erase(indent.size() - 2); + } - // Output all the region membership information - for (auto [region, objects] : region_strings) + void draw_region(objects::Region* r, std::string& indent) + { + auto info = ®ions[r]; + if (info->drawn) { - if ( - ((!info->draw_cown_region) && region == objects::cown_region) || - ((!info->draw_immutable_region) && - region == objects::immutable_region)) - { - continue; - } + return; + } + info->drawn = true; + auto depth = indent.size() / 2; - out << "subgraph "; + // Header + out << indent << "subgraph "; + out << "reg" << r << "[\" \"]" << std::endl; - if (region == objects::get_local_region()) - { - out << LOCAL_REGION_ID << "[\"Local region\"]" << std::endl; - } - else if (region == objects::immutable_region) - { - out << IMM_REGION_ID << "[\"Immutable region\"]" << std::endl; - out << " id0" << std::endl; - } - else if (region == objects::cown_region) - { - out << COWN_REGION_ID << "[\"Cown region\"]" << std::endl; - out << " region" << region << "[\\" << region - << "
sbrc=" << region->sub_region_reference_count << "/]" - << std::endl; - } - else - { - out << "region" << region << "[\" \"]" << std::endl; - } - for (auto obj : objects) - { - out << " id" << obj << std::endl; - } + // Content + draw_region_body(r, info, indent); + + // Footer + out << indent << "end" << std::endl; + out << indent << "style reg" << r + << " fill:" << REGION_COLORS[depth % std::size(REGION_COLORS)] + << std::endl; + } + + void draw_regions() + { + // Build parent relations + for (auto [reg, _] : regions) + { + regions[reg->parent].regions.push_back(reg); + } + + std::string indent; + if (info->draw_cown_region) + { + auto region = objects::cown_region; + out << "subgraph " << COWN_REGION_ID << "[\"Cown region\"]" + << std::endl; + draw_region_body(region, ®ions[region], indent); out << "end" << std::endl; + out << "style " << COWN_REGION_ID << " fill:" << REGION_COLORS[0] + << std::endl; } + regions[objects::cown_region].drawn = true; if (info->draw_immutable_region) { + auto region = objects::immutable_region; + out << "subgraph " << IMM_REGION_ID << "[\"Immutable region\"]" + << std::endl; + draw_region_body(region, ®ions[region], indent); + out << "end" << std::endl; out << "style " << IMM_REGION_ID << " fill:" << IMMUTABLE_REGION_COLOR << std::endl; } + regions[objects::immutable_region].drawn = true; + + // Local region + { + auto region = objects::get_local_region(); + out << "subgraph " << LOCAL_REGION_ID << "[\"Local region\"]" + << std::endl; + draw_region_body(objects::cown_region, ®ions[region], indent); + out << "end" << std::endl; + out << "style " << LOCAL_REGION_ID << " fill:" << REGION_COLORS[0] + << std::endl; + } + regions[objects::get_local_region()].drawn = true; + + // Draw all other regions + for (auto reg : regions[nullptr].regions) + { + draw_region(reg, indent); + } + for (auto reg : regions[objects::cown_region].regions) + { + draw_region(reg, indent); + } } void draw_taint() diff --git a/tests/regions/region4.vpy b/tests/regions/region4.vpy new file mode 100644 index 0000000..92da4a2 --- /dev/null +++ b/tests/regions/region4.vpy @@ -0,0 +1,30 @@ +# Create multiple regions +r1 = Region() +r1.level = "One" + +r2 = Region() +r2.level = "Two" + +r3 = Region() +r3.level = "Three" + +r4 = Region() +r4.level = "Four" + +r5 = Region() +r5.level = "Five" + +# Stack regions +r1.n = move r2 +r1.n.n = r3 + +r4.n = move r5 +r3.n = move r4 +drop r3 + +# Move this into a cown +c = cown(move r1) + +# Check the visuals +mermaid_show_cown_region() +mermaid_show_immutable_region() From c08797d5f23f92d1f6a3ca5402df9eaba0412bd4 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 1 Nov 2024 16:44:33 +0100 Subject: [PATCH 08/10] Cown: Add more region checks --- CMakeLists.txt | 2 ++ src/rt/core.h | 23 ++++++++++++++--------- src/rt/objects/region.h | 6 +++--- src/rt/rt.cc | 2 +- tests/cowns/{valid_01.vpy => cown1.vpy} | 0 tests/cowns/{valid_02.vpy => cown2.vpy} | 2 +- tests/cowns/invalid_child_region.vpy | 8 ++++++++ tests/cowns/invalid_not_bridge.vpy | 7 +++++++ tests/cowns/invalid_shared_region.vpy | 7 ++++--- 9 files changed, 40 insertions(+), 17 deletions(-) rename tests/cowns/{valid_01.vpy => cown1.vpy} (100%) rename tests/cowns/{valid_02.vpy => cown2.vpy} (94%) create mode 100644 tests/cowns/invalid_child_region.vpy create mode 100644 tests/cowns/invalid_not_bridge.vpy diff --git a/CMakeLists.txt b/CMakeLists.txt index 1836e2a..8dac12a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,8 @@ set_property(TEST leak_with_global.vpy PROPERTY WILL_FAIL true) set_property(TEST invalid_read.vpy PROPERTY WILL_FAIL true) set_property(TEST invalid_shared_region.vpy PROPERTY WILL_FAIL true) set_property(TEST invalid_write.vpy PROPERTY WILL_FAIL true) +set_property(TEST invalid_child_region.vpy PROPERTY WILL_FAIL true) +set_property(TEST invalid_not_bridge.vpy PROPERTY WILL_FAIL true) set_property(TEST region_bad_1.vpy PROPERTY WILL_FAIL true) set_property(TEST region_bad_2.vpy PROPERTY WILL_FAIL true) set_property(TEST fail_cross_region_ref.vpy PROPERTY WILL_FAIL true) diff --git a/src/rt/core.h b/src/rt/core.h index b6a7ada..e8cb353 100644 --- a/src/rt/core.h +++ b/src/rt/core.h @@ -196,19 +196,24 @@ namespace rt::core class CownObject : public objects::DynObject { public: - CownObject(objects::DynObject* region) + CownObject(objects::DynObject* bridge) : objects::DynObject(cownPrototypeObject(), objects::cown_region) { - // 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 + auto region = objects::get_region(bridge); + if (region->bridge != bridge) + { + std::stringstream ss; + ss << bridge << " is not the bridge object of the region"; + ui::error(ss.str(), bridge); + } + + if (region->local_reference_count > 1) + { + ui::error("The given region has a LRC > 1", bridge); + } // this->set would fail, since this is a cown - this->fields["value"] = region; + this->fields["value"] = bridge; } std::string get_name() override diff --git a/src/rt/objects/region.h b/src/rt/objects/region.h index 060459a..7a228e5 100644 --- a/src/rt/objects/region.h +++ b/src/rt/objects/region.h @@ -106,9 +106,9 @@ namespace rt::objects // Check if already parented to another region. if (r->parent != nullptr) { - // FIXME: Highlight, once regions have been reified ui::error( - "Region already has a parent: Creating region DAG not supported!"); + "Region already has a parent: Creating region DAG not supported!", + r->bridge); } // Prevent creating a cycle @@ -118,7 +118,7 @@ namespace rt::objects if (ancestors == r) { // FIXME: Highlight, once regions have been reified - ui::error("Cycle created in region hierarchy"); + ui::error("Cycle created in region hierarchy", r->bridge); } ancestors = ancestors->parent; } diff --git a/src/rt/rt.cc b/src/rt/rt.cc index ac48528..b04419d 100644 --- a/src/rt/rt.cc +++ b/src/rt/rt.cc @@ -92,7 +92,7 @@ namespace rt { // TODO Add some checking. This is need to lookup the correct function in // the prototype chain. - if (key->get_prototype() != core::stringPrototypeObject()) + if (key && key->get_prototype() != core::stringPrototypeObject()) { ui::error("Key must be a string.", key); } diff --git a/tests/cowns/valid_01.vpy b/tests/cowns/cown1.vpy similarity index 100% rename from tests/cowns/valid_01.vpy rename to tests/cowns/cown1.vpy diff --git a/tests/cowns/valid_02.vpy b/tests/cowns/cown2.vpy similarity index 94% rename from tests/cowns/valid_02.vpy rename to tests/cowns/cown2.vpy index 82940ac..fc3d67e 100644 --- a/tests/cowns/valid_02.vpy +++ b/tests/cowns/cown2.vpy @@ -7,7 +7,7 @@ drop x def add_cown(obj, name): a = Region() - a.name = name + a.name = {} obj[name] = cown(move a) add_cown(global, "c1") diff --git a/tests/cowns/invalid_child_region.vpy b/tests/cowns/invalid_child_region.vpy new file mode 100644 index 0000000..3c1e276 --- /dev/null +++ b/tests/cowns/invalid_child_region.vpy @@ -0,0 +1,8 @@ +# Creating a region +r1 = Region() +r2 = Region() + +r2.child = r1 + +# Error due to invalid LRC +co = cown(move r1) diff --git a/tests/cowns/invalid_not_bridge.vpy b/tests/cowns/invalid_not_bridge.vpy new file mode 100644 index 0000000..10a7905 --- /dev/null +++ b/tests/cowns/invalid_not_bridge.vpy @@ -0,0 +1,7 @@ +# A simple region +a = Region() +a.b = {} + +# Error: Only the bridge object can be used for cown construction +b = a.b +c01 = cown(move b) diff --git a/tests/cowns/invalid_shared_region.vpy b/tests/cowns/invalid_shared_region.vpy index 7966208..e4f0dfb 100644 --- a/tests/cowns/invalid_shared_region.vpy +++ b/tests/cowns/invalid_shared_region.vpy @@ -1,8 +1,9 @@ # Creating a region a = Region() +a.v = {} # LRC = 2 -r01 = a +r01 = a.v -# Error due to invalid RC -co = cown(take a) +# Error due to invalid LRC +co = cown(move a) From 9dca2847cbd69bbddd7c063e8eae2121eb54e79d Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 1 Nov 2024 16:53:52 +0100 Subject: [PATCH 09/10] Mermaid: Make unreachable highlighting optional --- src/rt/ui.h | 1 + src/rt/ui/mermaid.cc | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/rt/ui.h b/src/rt/ui.h index 7e86a91..163336e 100644 --- a/src/rt/ui.h +++ b/src/rt/ui.h @@ -60,6 +60,7 @@ namespace rt::ui bool draw_immutable_region; /// Indicates if local functions should be visible bool draw_funcs; + bool highlight_unreachable = true; std::vector error_objects; std::vector error_edges; diff --git a/src/rt/ui/mermaid.cc b/src/rt/ui/mermaid.cc index 79c0d4c..0063d0d 100644 --- a/src/rt/ui/mermaid.cc +++ b/src/rt/ui/mermaid.cc @@ -84,7 +84,6 @@ namespace rt::ui // Give a nice id to each object. std::map nodes; - std::map> region_strings; std::map regions; public: @@ -198,8 +197,10 @@ namespace rt::ui // Footer out << markers.second; out - << (dst->is_immutable() ? ":::immutable" : - (reachable ? "" : ":::unreachable")); + << (dst->is_immutable() ? + ":::immutable" : + (reachable && info->highlight_unreachable ? "" : + ":::unreachable")); out << std::endl; result = node; @@ -503,6 +504,7 @@ namespace rt::ui { // Make sure ui doesn't pause steps += 10; + highlight_unreachable = false; // Construct message std::stringstream ss; From af5a2f6bfa21215e2b5b5fc985d542ff47255f13 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 1 Nov 2024 17:02:10 +0100 Subject: [PATCH 10/10] CI: Set reasonable timeouts --- .github/workflows/buildci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/buildci.yml b/.github/workflows/buildci.yml index ddf8cde..5a58cc6 100644 --- a/.github/workflows/buildci.yml +++ b/.github/workflows/buildci.yml @@ -11,6 +11,7 @@ on: jobs: build: runs-on: ${{ matrix.os }} + timeout-minutes: 10 strategy: # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. @@ -56,6 +57,7 @@ jobs: format: runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@v4