diff --git a/README.md b/README.md index 9e15927..86e8f66 100644 --- a/README.md +++ b/README.md @@ -54,3 +54,24 @@ You can run in interactive mode by running: Which will keep overwritting the `mermaid.md` file with the new heap state after each step. +## Lungfish + +FrankenScript has been submitted as an PLDI25 artifact to explain the *Lungfish* +Ownership Model implemented here. + +A critical part of Lungfish is the write-barrier shown in Figure 6 of the Paper. FrankenScript implements +these functions in `src/rt/objects/region.cc`. The important functions are: + +* `add_reference(source, target)`: This adds a new reference from `source` to `target`. +* `add_to_region(region, target, source)`: This adds `target` and all reachable nodes to `region` if possible. +* `remove_reference(source, old_target)`: This removes a reference from `source` to `old_target` +* `move_reference(old_src, new_src, target)`: This is the `writeBarrier()` function, which adds a new reference + from `new_src` to `target` and removes the reference from `old_src` to `target`. + +The interpreter, implemented in `src/lang/interpreter.cc`, calls these functions via the public API of the +runtime (`rt::add_reference`, `rt::remove_reference`, `rt::move_reference`). The `add_to_region()` method is +never called directly by the interpreter. + +A good example for the write-barrier is the `StoreField` bytecode implementation: + +https://github.com/fxpl/frankenscript/blob/30e431c7ba8022f29fb4927913976bbf18356789/src/lang/interpreter.cc#L303-L318 diff --git a/src/rt/objects/region.cc b/src/rt/objects/region.cc index 8b13475..f63ae26 100644 --- a/src/rt/objects/region.cc +++ b/src/rt/objects/region.cc @@ -218,10 +218,10 @@ namespace rt::objects add_region_reference(src_region, target, src); } - void remove_reference(DynObject* src_initial, DynObject* old_dst_initial) + void remove_reference(DynObject* source, DynObject* old_target) { visit( - {src_initial, "", old_dst_initial}, + {source, "", old_target}, [&](Edge e) { if (e.target == nullptr) return false; @@ -238,18 +238,18 @@ namespace rt::objects Region::collect(); } - void move_reference(DynObject* src, DynObject* dst, DynObject* target) + void move_reference(DynObject* old_src, DynObject* new_src, DynObject* target) { - assert(src != nullptr); - assert(dst != nullptr); + assert(old_src != nullptr); + assert(new_src != nullptr); if (target == nullptr || target->is_immutable() || target->is_cown()) { return; } - auto src_region = get_region(src); - auto dst_region = get_region(dst); - if (src_region == dst_region) + auto old_src_region = get_region(old_src); + auto new_src_region = get_region(new_src); + if (old_src_region == new_src_region) { return; } @@ -257,7 +257,7 @@ namespace rt::objects auto old_target_region = get_region(target); auto old_target_bridge = old_target_region->bridge; - add_region_reference(dst_region, target, src); + add_region_reference(new_src_region, target, old_src); // If the bridge was implicitly frozen we don't need to remove // the region reference. In fact, we shouldn't since the region @@ -269,7 +269,7 @@ namespace rt::objects // Note that the region of the target might have changed after the // `add_region_refernce` call - remove_region_reference(src_region, old_target_region); + remove_region_reference(old_src_region, old_target_region); } void Region::clean_lrcs_and_close(Region* to_close_reg)