Implement exception reraising from the guard handler
This commit is contained in:
parent
999cd062f0
commit
b9fa84ba0e
5 changed files with 107 additions and 28 deletions
|
@ -702,6 +702,50 @@ Result<StackFrame> StackFrame::attach(const StackFrame& frame) const {
|
||||||
return StackFrame(TRY(MkGcRoot(pod)));
|
return StackFrame(TRY(MkGcRoot(pod)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<Value> 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<Int64>()) return ERROR(TypeMismatch);
|
||||||
|
auto state_int = state.to<Int64>()->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<Nil>()) break;
|
||||||
|
|
||||||
|
cur = TRY(parent.to<StackFrame>()->copy());
|
||||||
|
++depth;
|
||||||
|
}
|
||||||
|
return Value(TRY(Nil::create()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<uint64_t> StackFrame::depth() const {
|
||||||
|
StackFrame cur = TRY(copy());
|
||||||
|
|
||||||
|
uint64_t depth = 1;
|
||||||
|
while (true) {
|
||||||
|
auto parent = TRY(cur.parent());
|
||||||
|
if (parent.is<Nil>()) break;
|
||||||
|
|
||||||
|
cur = TRY(parent.to<StackFrame>()->copy());
|
||||||
|
++depth;
|
||||||
|
}
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
Result<StackFrame> StackFrame::set_guard(bool guard) const {
|
Result<StackFrame> StackFrame::set_guard(bool guard) const {
|
||||||
uint64_t size = _value->size;
|
uint64_t size = _value->size;
|
||||||
auto pod = TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * size));
|
auto pod = TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * size));
|
||||||
|
|
|
@ -1168,6 +1168,9 @@ class StackFrame : public Object {
|
||||||
Result<StackFrame> detach(uint64_t depth) const;
|
Result<StackFrame> detach(uint64_t depth) const;
|
||||||
Result<StackFrame> attach(const StackFrame& frame) const;
|
Result<StackFrame> attach(const StackFrame& frame) const;
|
||||||
|
|
||||||
|
Result<Value> unwind(const Value& val, uint64_t start_from = 0) const;
|
||||||
|
Result<uint64_t> depth() const;
|
||||||
|
|
||||||
Result<StackFrame> set_guard(bool guard = true) const;
|
Result<StackFrame> set_guard(bool guard = true) const;
|
||||||
|
|
||||||
virtual Result<Value> copy_value() const final;
|
virtual Result<Value> copy_value() const final;
|
||||||
|
|
|
@ -406,6 +406,61 @@ Result<StackFrame> stdlib_raise(const StackFrame& stack) {
|
||||||
return ERROR_OBJ(Raise, cont);
|
return ERROR_OBJ(Raise, cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<StackFrame> 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<Continuation>()) return ERROR(TypeMismatch);
|
||||||
|
|
||||||
|
Continuation& cont = *cont_val.to<Continuation>();
|
||||||
|
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<Int64>()) return ERROR(TypeMismatch);
|
||||||
|
auto state_int = state.to<Int64>()->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<StackFrame>())
|
||||||
|
return res.to<StackFrame>()->copy();
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto parent = TRY(cur.parent());
|
||||||
|
if (parent.is<Nil>()) break;
|
||||||
|
|
||||||
|
cur = TRY(parent.to<StackFrame>()->copy());
|
||||||
|
++depth;
|
||||||
|
}
|
||||||
|
return ERROR_OBJ(Raise, cont_val);
|
||||||
|
}
|
||||||
|
|
||||||
Result<StackFrame> stdlib_task(const StackFrame& stack) {
|
Result<StackFrame> stdlib_task(const StackFrame& stack) {
|
||||||
auto params = TRY(stack.get(0));
|
auto params = TRY(stack.get(0));
|
||||||
Array& params_array = *params.to<Array>();
|
Array& params_array = *params.to<Array>();
|
||||||
|
@ -588,6 +643,7 @@ static StdlibFunctionEntry function_entries[] = {
|
||||||
STDLIB_FUNCTION(map, Map),
|
STDLIB_FUNCTION(map, Map),
|
||||||
STDLIB_FUNCTION(error, Error),
|
STDLIB_FUNCTION(error, Error),
|
||||||
STDLIB_FUNCTION(raise, Raise),
|
STDLIB_FUNCTION(raise, Raise),
|
||||||
|
STDLIB_FUNCTION(reraise, Reraise),
|
||||||
STDLIB_FUNCTION(task, Task),
|
STDLIB_FUNCTION(task, Task),
|
||||||
STDLIB_FUNCTION(guard, Guard),
|
STDLIB_FUNCTION(guard, Guard),
|
||||||
STDLIB_FUNCTION(serialize, Serialize),
|
STDLIB_FUNCTION(serialize, Serialize),
|
||||||
|
|
|
@ -22,6 +22,7 @@ enum class StdlibFunctionId : uint64_t {
|
||||||
Map,
|
Map,
|
||||||
Error,
|
Error,
|
||||||
Raise,
|
Raise,
|
||||||
|
Reraise,
|
||||||
Task,
|
Task,
|
||||||
Guard,
|
Guard,
|
||||||
Serialize,
|
Serialize,
|
||||||
|
|
31
src/vm.cpp
31
src/vm.cpp
|
@ -303,35 +303,10 @@ Result<void> VM::step_bytecode() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Value> VM::unwind(const Continuation& cont) {
|
Result<Value> 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;
|
return cont_stack.unwind(val);
|
||||||
while (true) {
|
|
||||||
if (cur.guard()) {
|
|
||||||
auto state = TRY(cur.get(1));
|
|
||||||
if (!state.is<Int64>()) return ERROR(TypeMismatch);
|
|
||||||
auto state_int = state.to<Int64>()->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<Nil>()) break;
|
|
||||||
|
|
||||||
cur = TRY(parent.to<StackFrame>()->copy());
|
|
||||||
++depth;
|
|
||||||
}
|
|
||||||
return Value(TRY(Nil::create()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<StackFrame> VM::handle_raise(const Continuation& cont) {
|
Result<StackFrame> VM::handle_raise(const Continuation& cont) {
|
||||||
|
|
Loading…
Reference in a new issue