Implement reraise correctly: don't destroy the parent frame
This commit is contained in:
parent
b9fa84ba0e
commit
5f2636c62f
5 changed files with 73 additions and 49 deletions
|
@ -63,6 +63,8 @@ const char* errname(ErrorCode errcode) {
|
|||
return "runtime-error";
|
||||
case ErrorCode::Raise:
|
||||
return "raise";
|
||||
case ErrorCode::Reraise:
|
||||
return "reraise";
|
||||
case ErrorCode::TaskFailed:
|
||||
return "task-failed";
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ enum class ErrorCode {
|
|||
SyntaxError,
|
||||
RuntimeError,
|
||||
Raise,
|
||||
Reraise,
|
||||
TaskFailed,
|
||||
};
|
||||
|
||||
|
|
|
@ -417,48 +417,9 @@ Result<StackFrame> stdlib_reraise(const StackFrame& stack) {
|
|||
|
||||
if (!cont_val.is<Continuation>()) return ERROR(TypeMismatch);
|
||||
|
||||
Continuation& cont = *cont_val.to<Continuation>();
|
||||
StackFrame cont_stack = TRY(cont.frame());
|
||||
auto new_cont = Value(TRY(Continuation::create(cont_val, stack)));
|
||||
|
||||
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);
|
||||
return ERROR_OBJ(Reraise, new_cont);
|
||||
}
|
||||
|
||||
Result<StackFrame> stdlib_task(const StackFrame& stack) {
|
||||
|
|
70
src/vm.cpp
70
src/vm.cpp
|
@ -302,17 +302,16 @@ Result<void> VM::step_bytecode() {
|
|||
return Result<void>();
|
||||
}
|
||||
|
||||
Result<Value> VM::unwind(const Continuation& cont) {
|
||||
Result<Value> VM::unwind(const Continuation& cont, uint64_t start_from) {
|
||||
auto val = TRY(cont.value());
|
||||
auto cont_stack = TRY(cont.frame());
|
||||
|
||||
return cont_stack.unwind(val);
|
||||
return cont_stack.unwind(val, start_from);
|
||||
}
|
||||
|
||||
Result<StackFrame> VM::handle_raise(const Continuation& cont) {
|
||||
// TODO: this should do proper stack unwinding
|
||||
|
||||
auto unwind_res = TRY(unwind(cont));
|
||||
Result<StackFrame> VM::handle_raise(const Continuation& cont,
|
||||
uint64_t start_from) {
|
||||
auto unwind_res = TRY(unwind(cont, start_from));
|
||||
|
||||
if (!unwind_res.is<Nil>()) {
|
||||
auto new_stack = TRY(unwind_res.to<StackFrame>()->copy());
|
||||
|
@ -358,6 +357,59 @@ Result<StackFrame> VM::handle_raise(const Continuation& cont) {
|
|||
return ERROR(TypeMismatch);
|
||||
}
|
||||
|
||||
Result<StackFrame> VM::handle_reraise(const Continuation& parent_cont) {
|
||||
auto stack = TRY(parent_cont.frame());
|
||||
auto cont_val = TRY(parent_cont.value());
|
||||
|
||||
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));
|
||||
|
||||
auto params = TRY(cur.get(0));
|
||||
Value fun = TRY(params.get(0));
|
||||
cur = TRY(cur.set(1, Value(TRY(Int64::create((int64_t)0)))));
|
||||
cur = TRY(cur.settop(2));
|
||||
|
||||
cur = TRY(cont_stack.attach(cur));
|
||||
|
||||
uint64_t start_from = TRY(cont_stack.depth()) + 1;
|
||||
|
||||
auto res = TRY(cur.unwind(val, start_from));
|
||||
if (res.is<StackFrame>()) {
|
||||
return res.to<StackFrame>()->copy();
|
||||
} else {
|
||||
auto new_cont = TRY(Continuation::create(val, cur));
|
||||
return handle_raise(new_cont, start_from);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto parent = TRY(cur.parent());
|
||||
if (parent.is<Nil>()) break;
|
||||
|
||||
cur = TRY(parent.to<StackFrame>()->copy());
|
||||
++depth;
|
||||
}
|
||||
|
||||
auto new_cont = TRY(Continuation::create(TRY(cont.value()), stack));
|
||||
return handle_raise(new_cont, 0);
|
||||
}
|
||||
|
||||
Result<void> VM::step_native() {
|
||||
auto fun = TRY(_stack.fun());
|
||||
if (!fun.is<StdlibFunction>()) return ERROR(TypeMismatch);
|
||||
|
@ -392,6 +444,12 @@ Result<void> VM::step() {
|
|||
return Result<void>();
|
||||
}
|
||||
}
|
||||
if (res.error() == ErrorCode::Reraise) {
|
||||
if (obj.is<Continuation>()) {
|
||||
_stack = TRY(handle_reraise(*obj.to<Continuation>()));
|
||||
return Result<void>();
|
||||
}
|
||||
}
|
||||
|
||||
auto cont = TRY(Continuation::create(obj, _stack));
|
||||
_stack = TRY(handle_raise(cont));
|
||||
|
|
|
@ -63,8 +63,10 @@ class VM {
|
|||
Result<void> vm_global_load(Opcode& oc);
|
||||
Result<void> vm_global_store(Opcode& oc);
|
||||
|
||||
Result<Value> unwind(const Continuation& cont);
|
||||
Result<StackFrame> handle_raise(const Continuation& cont);
|
||||
Result<Value> unwind(const Continuation& cont, uint64_t start_from = 0);
|
||||
Result<StackFrame> handle_raise(const Continuation& cont,
|
||||
uint64_t start_from = 0);
|
||||
Result<StackFrame> handle_reraise(const Continuation& cont);
|
||||
|
||||
Result<Value> get(bool is_const, uint64_t idx);
|
||||
Result<Value> getconst(uint64_t idx);
|
||||
|
|
Loading…
Reference in a new issue