From b9fa84ba0e95e7d11539c5ee635d1babeb15ee87 Mon Sep 17 00:00:00 2001 From: Konstantin Nazarov Date: Sun, 13 Oct 2024 19:13:33 +0100 Subject: [PATCH] Implement exception reraising from the guard handler --- src/common.cpp | 44 +++++++++++++++++++++++++++++++++++++++ src/common.hpp | 3 +++ src/stdlib.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/stdlib.hpp | 1 + src/vm.cpp | 31 +++------------------------- 5 files changed, 107 insertions(+), 28 deletions(-) diff --git a/src/common.cpp b/src/common.cpp index a2d3445..a7b1826 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -702,6 +702,50 @@ Result StackFrame::attach(const StackFrame& frame) const { return StackFrame(TRY(MkGcRoot(pod))); } +Result StackFrame::unwind(const Value& val, uint64_t start_from) const { + StackFrame cur = TRY(copy()); + + uint64_t depth = 0; + while (true) { + if (cur.guard() && depth >= start_from) { + auto state = TRY(cur.get(1)); + if (!state.is()) return ERROR(TypeMismatch); + auto state_int = state.to()->value(); + + if (state_int <= 1) { + auto detached_stack = TRY(detach(depth - 1)); + + auto new_cont = TRY(Continuation::create(val, detached_stack)); + + cur = TRY(cur.set(1, Value(TRY(Int64::create((int64_t)1))))); + cur = TRY(cur.set(2, Value(std::move(new_cont)))); + return Value(std::move(cur)); + } + } + + auto parent = TRY(cur.parent()); + if (parent.is()) break; + + cur = TRY(parent.to()->copy()); + ++depth; + } + return Value(TRY(Nil::create())); +} + +Result StackFrame::depth() const { + StackFrame cur = TRY(copy()); + + uint64_t depth = 1; + while (true) { + auto parent = TRY(cur.parent()); + if (parent.is()) break; + + cur = TRY(parent.to()->copy()); + ++depth; + } + return depth; +} + Result StackFrame::set_guard(bool guard) const { uint64_t size = _value->size; auto pod = TRY(arena_alloc(sizeof(OffPtr) * size)); diff --git a/src/common.hpp b/src/common.hpp index 48a2c0c..fca7a8d 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -1168,6 +1168,9 @@ class StackFrame : public Object { Result detach(uint64_t depth) const; Result attach(const StackFrame& frame) const; + Result unwind(const Value& val, uint64_t start_from = 0) const; + Result depth() const; + Result set_guard(bool guard = true) const; virtual Result copy_value() const final; diff --git a/src/stdlib.cpp b/src/stdlib.cpp index ebe1c86..7616f61 100644 --- a/src/stdlib.cpp +++ b/src/stdlib.cpp @@ -406,6 +406,61 @@ Result stdlib_raise(const StackFrame& stack) { return ERROR_OBJ(Raise, cont); } +Result stdlib_reraise(const StackFrame& stack) { + auto stack_size = TRY(stack.size()); + + auto params = TRY(stack.get(0)); + auto size = TRY(params.size()); + if (size != 1) return ERROR(ArgumentCountMismatch); + + auto cont_val = TRY(params.get(0)); + + if (!cont_val.is()) return ERROR(TypeMismatch); + + Continuation& cont = *cont_val.to(); + StackFrame cont_stack = TRY(cont.frame()); + + StackFrame cur = TRY(stack.copy()); + + uint64_t depth = 0; + + while (true) { + if (cur.guard()) { + auto state = TRY(cur.get(1)); + if (!state.is()) return ERROR(TypeMismatch); + auto state_int = state.to()->value(); + + if (state_int > 1) { + auto val = TRY(cont.value()); + auto remaining_stack = TRY(stack.detach(depth - 1)); + + Value fun = TRY(params.get(0)); + cur = TRY(cur.set(1, Value(TRY(Int64::create((int64_t)0))))); + cur = TRY(cur.set(2, Value(std::move(fun)))); + cur = TRY(cur.settop(3)); + + cur = TRY(remaining_stack.attach(cur)); + cur = TRY(cont_stack.attach(cur)); + + uint64_t start_from = depth + TRY(cont_stack.depth()) + 1; + + auto res = TRY(cur.unwind(val, start_from)); + if (res.is()) + return res.to()->copy(); + else + break; + } + } + + auto parent = TRY(cur.parent()); + if (parent.is()) break; + + cur = TRY(parent.to()->copy()); + ++depth; + } + return ERROR_OBJ(Raise, cont_val); +} + Result stdlib_task(const StackFrame& stack) { auto params = TRY(stack.get(0)); Array& params_array = *params.to(); @@ -588,6 +643,7 @@ static StdlibFunctionEntry function_entries[] = { STDLIB_FUNCTION(map, Map), STDLIB_FUNCTION(error, Error), STDLIB_FUNCTION(raise, Raise), + STDLIB_FUNCTION(reraise, Reraise), STDLIB_FUNCTION(task, Task), STDLIB_FUNCTION(guard, Guard), STDLIB_FUNCTION(serialize, Serialize), diff --git a/src/stdlib.hpp b/src/stdlib.hpp index a7192a4..f346b68 100644 --- a/src/stdlib.hpp +++ b/src/stdlib.hpp @@ -22,6 +22,7 @@ enum class StdlibFunctionId : uint64_t { Map, Error, Raise, + Reraise, Task, Guard, Serialize, diff --git a/src/vm.cpp b/src/vm.cpp index 0fb83da..3d3518c 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -303,35 +303,10 @@ Result VM::step_bytecode() { } Result VM::unwind(const Continuation& cont) { - StackFrame cur = TRY(cont.frame()); + auto val = TRY(cont.value()); + auto cont_stack = TRY(cont.frame()); - uint64_t depth = 0; - while (true) { - if (cur.guard()) { - auto state = TRY(cur.get(1)); - if (!state.is()) return ERROR(TypeMismatch); - auto state_int = state.to()->value(); - - if (state_int <= 1) { - auto val = TRY(cont.value()); - auto cont_stack = TRY(cont.frame()); - cont_stack = TRY(cont_stack.detach(depth - 1)); - - auto new_cont = TRY(Continuation::create(val, cont_stack)); - - cur = TRY(cur.set(1, Value(TRY(Int64::create((int64_t)1))))); - cur = TRY(cur.set(2, Value(std::move(new_cont)))); - return Value(std::move(cur)); - } - } - - auto parent = TRY(cur.parent()); - if (parent.is()) break; - - cur = TRY(parent.to()->copy()); - ++depth; - } - return Value(TRY(Nil::create())); + return cont_stack.unwind(val); } Result VM::handle_raise(const Continuation& cont) {