This repository contains a toy programming language called "FrankenScript" with Python-like syntax and Python/JavaScript-inspired semantics.
The purpose of FrankenScript is to explore the design space for adding a region-based ownership system inspired by Reggio and a concurrency
model inspired by behaviour-oriented concurrency to dynamic programming languages to unlock parallelism in a way that is free from data-races
(and also deadlocks, if the full behaviour-oriented concurrency model is adopted). FrankenScript is implemented using Trieste.
To this end, FrankenScript programs generate a file called mermaid.md
with a Mermaid diagram per line in the source program showing the object and region
graph of the program at that program point.
This is a legend for the diagrams that FrankenScript generates:
This project is C++20 based and uses CMake as the build system. We also recommend installing Ninja to speed up the build process.
sudo apt-get install cmake ninja-build clang-15
Once you have the pre-requisites installed, you can build the project by running the following commands:
mkdir build
cd build
cmake -G Ninja ..
ninja
and run the tests with:
ctest
The project can be run by
./build/frankenscript build foo.frank
where foo.fs
is a FrankenScript program. This generates a file mermaid.md
that contains the Mermaid representation of the heap after each step of the program.
You can run in interactive mode by running:
./build/frankenscript build --interactive foo.frank
Which will keep overwritting the mermaid.md
file with the new heap state after each step.
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 fromsource
totarget
.add_to_region(region, target, source)
: This addstarget
and all reachable nodes toregion
if possible.remove_reference(source, old_target)
: This removes a reference fromsource
toold_target
move_reference(old_src, new_src, target)
: This is thewriteBarrier()
function, which adds a new reference fromnew_src
totarget
and removes the reference fromold_src
totarget
.
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:
frankenscript/src/lang/interpreter.cc
Lines 303 to 318 in 30e431c