Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transpiler #11

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ cd bluescript
docker compose up -d
```

3. Verify that the server has started successfully
Open [Google Chrome browser](https://www.google.com/chrome/) and access [http://localhost:3000/](http://localhost:3000/).
You can see BlueScript REPL page on the browser.
3. Verify that the server has started successfully.
- Open [Google Chrome browser](https://www.google.com/chrome/) and access [http://localhost:3000/](http://localhost:3000/).
- You can see BlueScript REPL page on the browser.

### Build and Flash the BlueScript Runtime

Expand Down
2 changes: 1 addition & 1 deletion microcontroller/core/include/c-runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ inline float* get_obj_float_property(value_t obj, int index) {
}

inline value_t set_global_variable(value_t* ptr, value_t new_value) {
// write barrier
gc_write_barrier((pointer_t)0, new_value);
return *ptr = new_value;
}

Expand Down
88 changes: 80 additions & 8 deletions microcontroller/core/src/c-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,20 @@ pointer_t gc_heap_pointer(pointer_t ptr) {
}
#endif

#ifdef TEST64

#define GC_ENTER_CRITICAL(m)
#define GC_EXIT_CRITICAL(m)

#else

#include <freertos/FreeRTOS.h>

#define GC_ENTER_CRITICAL(m) portENTER_CRITICAL(&(m))
#define GC_EXIT_CRITICAL(m) portEXIT_CRITICAL(&(m))

#endif

// runtime error handling

static jmp_buf long_jump_buffer;
Expand Down Expand Up @@ -337,6 +351,7 @@ value_t minus_any_value(value_t v) {
// heap objects

static bool gc_is_running = false;

// An interrupt handler must count up this value at the beginning, and count down at the end.
// Note that an interrupt handler may be nested.
// When this value is 0, no interrupt handler is working.
Expand Down Expand Up @@ -1140,7 +1155,7 @@ static pointer_t allocate_heap_base(uint16_t word_size) {

static pointer_t allocate_heap(uint16_t word_size) {
if (nested_interrupt_handler > 0) {
runtime_memory_allocation_error("you cannot create objects in interrupt handler.");
runtime_memory_allocation_error("you cannot create objects in an interrupt handler.");
}

pointer_t ptr = allocate_heap_base(word_size);
Expand Down Expand Up @@ -1177,12 +1192,15 @@ struct gc_root_set* gc_root_set_head = NULL;
#define CLEAR_GRAY_BIT(ptr) ((ptr)->header &= ~0b10)
#define SET_GRAY_BIT(ptr) ((ptr)->header |= 0b10)


#define STACK_SIZE (HEAP_SIZE / 65)
static pointer_t gc_stack[STACK_SIZE];
static uint32_t gc_stack_top = 0;
static bool gc_stack_overflowed = false;

#define ISTACK_SIZE (STACK_SIZE / 2)
static pointer_t gc_intr_stack[ISTACK_SIZE]; // used by interrupt handlers
static uint32_t gc_intr_stack_top = 0;

static void push_object_to_stack(pointer_t obj, uint32_t mark) {
WRITE_MARK_BIT(obj, mark);
SET_GRAY_BIT(obj);
Expand All @@ -1192,18 +1210,51 @@ static void push_object_to_stack(pointer_t obj, uint32_t mark) {
gc_stack_overflowed = true;
}

#ifndef TEST64
static portMUX_TYPE gc_mux = portMUX_INITIALIZER_UNLOCKED;
#endif

void gc_write_barrier(pointer_t obj, value_t value) {
if (nested_interrupt_handler > 0 && gc_is_running) {
if (is_ptr_value(value)) {
uint32_t mark = current_no_mark ? 0 : 1;
pointer_t ptr = value_to_ptr(value);
if (IS_BLACK(obj, mark) && IS_WHITE(ptr, mark)) {
push_object_to_stack(ptr, mark);
if (IS_WHITE(ptr, mark) && (obj == NULL || IS_BLACK(obj, mark))) {
GC_ENTER_CRITICAL(gc_mux);
if (gc_intr_stack_top < ISTACK_SIZE)
gc_intr_stack[gc_intr_stack_top++] = ptr;
else {
WRITE_MARK_BIT(ptr, mark);
SET_GRAY_BIT(ptr);
gc_stack_overflowed = true;
}
GC_EXIT_CRITICAL(gc_mux);
}
}
}
}

static void copy_from_intr_stack(uint32_t mark) {
uint32_t num = gc_intr_stack_top;
uint32_t i = 0;
int failure;
do {
while (i < num)
push_object_to_stack(gc_intr_stack[i++], mark);

GC_ENTER_CRITICAL(gc_mux);
if (num == gc_intr_stack_top) {
failure = 0;
gc_intr_stack_top = 0;
}
else {
num = gc_intr_stack_top;
failure = 1;
}
GC_EXIT_CRITICAL(gc_mux);
} while (failure);
}

static void trace_from_an_object(uint32_t mark) {
while (gc_stack_top > 0) {
pointer_t obj = gc_stack[--gc_stack_top];
Expand Down Expand Up @@ -1239,6 +1290,9 @@ static void scan_and_mark_objects(uint32_t mark) {
if (IS_GRAY(obj)) {
gc_stack[0] = obj;
gc_stack_top = 1;
if (gc_intr_stack_top > 0)
copy_from_intr_stack(mark);

trace_from_an_object(mark);
}
start += real_objsize(size);
Expand Down Expand Up @@ -1267,6 +1321,9 @@ static void mark_objects(struct gc_root_set* root_set, uint32_t mark) {
SET_GRAY_BIT(rootp);
gc_stack[0] = rootp;
gc_stack_top = 1;
if (gc_intr_stack_top > 0)
copy_from_intr_stack(mark);

trace_from_an_object(mark);
}
}
Expand All @@ -1275,10 +1332,18 @@ static void mark_objects(struct gc_root_set* root_set, uint32_t mark) {
root_set = root_set->next;
}

while (gc_stack_overflowed) {
gc_stack_overflowed = false;
scan_and_mark_objects(mark);
}
do {
while (gc_stack_overflowed) {
gc_stack_overflowed = false;
scan_and_mark_objects(mark);
}

if (gc_intr_stack_top > 0) {
gc_stack_top = 0;
copy_from_intr_stack(mark);
trace_from_an_object(mark);
}
} while (gc_stack_overflowed || gc_intr_stack_top > 0);
}

static void sweep_objects(uint32_t mark) {
Expand Down Expand Up @@ -1347,6 +1412,13 @@ void gc_run() {
gc_is_running = false;
}

#ifdef TEST64
uint32_t gc_test_run() {
gc_is_running = true;
return current_no_mark ? 0 : 1;
}
#endif

void gc_init_rootset(struct gc_root_set* set, uint32_t length) {
set->next = gc_root_set_head;
if (length > 0) {
Expand Down
49 changes: 49 additions & 0 deletions microcontroller/core/test/c-runtime-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,54 @@ void test_gc_sweep() {
gc_run();
}

extern uint32_t gc_test_run();

static void write_mark_bit(value_t obj, uint32_t mark) {
pointer_t ptr = value_to_ptr(obj);
if (mark)
ptr->header |= 1;
else
ptr->header &= ~1;
}

void test_gc_write_barrier() {
gc_initialize();
ROOT_SET(root_set, 5);
value_t obj, obj1, obj2;

obj = gc_new_string("test");
obj1 = gc_new_string("int");

uint32_t mark = gc_test_run();
interrupt_handler_start();

write_mark_bit(obj, mark);
write_mark_bit(obj1, !mark);
gc_write_barrier(value_to_ptr(obj), obj1);

interrupt_handler_end();

gc_new_string("test1");
root_set.values[0] = gc_new_string("test2");
root_set.values[1] = gc_new_string("test3");
root_set.values[2] = gc_new_string("test4");
gc_new_string("test5");
gc_new_vector2(2);
gc_new_vector2(3);
root_set.values[3] = obj = gc_new_vector2(4);
obj2 = gc_new_vector2(3);
gc_vector_setter(obj, 0, obj2);

gc_run();
Assert_true(is_live_object(obj1));
Assert_true(is_live_object(obj2));

gc_run();
Assert_true(!is_live_object(obj1));

DELETE_ROOT_SET(root_set);
}

void test_main() {
test_converters();
test_string();
Expand All @@ -461,6 +509,7 @@ void test_main() {
test_gc_liveness();
test_gc_liveness2();
test_gc_sweep();
test_gc_write_barrier();
puts("done");
}

Expand Down