Extract call() and ret() into the StackFrame from VM
This commit is contained in:
parent
51de7e3547
commit
e9b9ef6d61
5 changed files with 100 additions and 72 deletions
|
@ -302,8 +302,7 @@ Result<short> Module::cmp(const Module& rhs) const {
|
|||
return res;
|
||||
}
|
||||
|
||||
Result<StackFrame> StackFrame::create(const Value& parent,
|
||||
const Function& fun) {
|
||||
Result<StackFrame> StackFrame::create(const Value& parent, const Value& fun) {
|
||||
auto pod = TRY(arena_alloc<PodStackFrame>());
|
||||
pod->header.tag = Tag::StackFrame;
|
||||
|
||||
|
@ -319,6 +318,10 @@ Result<Value> StackFrame::copy_value() const {
|
|||
return Value(StackFrame(TRY(_value.copy())));
|
||||
}
|
||||
|
||||
Result<StackFrame> StackFrame::copy() const {
|
||||
return StackFrame(TRY(_value.copy()));
|
||||
}
|
||||
|
||||
Result<Value> StackFrame::get(uint64_t idx) const {
|
||||
if (idx >= _value->size) return ERROR(KeyError);
|
||||
|
||||
|
@ -349,7 +352,7 @@ Result<StackFrame> StackFrame::set(uint64_t idx, const Value& val) {
|
|||
return StackFrame(TRY(MkGcRoot(pod)));
|
||||
}
|
||||
|
||||
Result<StackFrame> StackFrame::settop(uint64_t idx) {
|
||||
Result<StackFrame> StackFrame::settop(uint64_t idx) const {
|
||||
auto pod = TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * idx));
|
||||
pod->header.tag = Tag::StackFrame;
|
||||
|
||||
|
@ -376,8 +379,8 @@ Result<StackFrame> StackFrame::settop(uint64_t idx) {
|
|||
Result<Value> StackFrame::parent() const {
|
||||
return Value::create(_value->parent.get());
|
||||
}
|
||||
Result<Function> StackFrame::fun() const {
|
||||
return Function::create((PodFunction*)_value->fun.get());
|
||||
Result<Value> StackFrame::fun() const {
|
||||
return Value::create(_value->fun.get());
|
||||
}
|
||||
uint64_t StackFrame::pc() const { return _value->pc; }
|
||||
|
||||
|
@ -400,6 +403,39 @@ Result<StackFrame> StackFrame::setpc(uint64_t pc) {
|
|||
|
||||
Result<StackFrame> StackFrame::incpc() { return setpc(pc() + 1); }
|
||||
|
||||
Result<StackFrame> StackFrame::call(const Value& fun, uint64_t start,
|
||||
uint64_t end) const {
|
||||
auto trunc_stack = TRY(settop(start));
|
||||
auto new_stack = TRY(StackFrame::create(TRY(trunc_stack.copy_value()), fun));
|
||||
|
||||
if (fun.is<Function>()) {
|
||||
uint64_t arity = fun.to<Function>()->arity();
|
||||
if (arity != (end - start - 1)) {
|
||||
return ERROR(ArgumentCountMismatch);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint64_t i = 0; i < end - start - 1; i++) {
|
||||
new_stack = TRY(new_stack.set(i, TRY(get(start + i + 1))));
|
||||
}
|
||||
|
||||
return new_stack;
|
||||
}
|
||||
|
||||
Result<StackFrame> StackFrame::ret(uint64_t regnum) const {
|
||||
auto parent_frame = TRY(parent());
|
||||
if (parent_frame.is<Nil>()) {
|
||||
return ERROR(EndOfProgram);
|
||||
}
|
||||
|
||||
auto res = TRY(get(regnum));
|
||||
StackFrame& parent_stack = *parent_frame.to<StackFrame>();
|
||||
uint64_t parent_size = TRY(parent_stack.size());
|
||||
parent_stack = TRY(parent_stack.set(parent_size, res));
|
||||
|
||||
return std::move(parent_stack);
|
||||
}
|
||||
|
||||
Result<Value> Error::copy_value() const {
|
||||
return Value(Error(TRY(_value.copy())));
|
||||
}
|
||||
|
|
|
@ -1115,17 +1115,17 @@ class StackFrame : public Object {
|
|||
using Object::get;
|
||||
Result<Value> get(uint64_t idx) const;
|
||||
Result<StackFrame> set(uint64_t idx, const Value& val);
|
||||
Result<StackFrame> settop(uint64_t idx);
|
||||
Result<StackFrame> settop(uint64_t idx) const;
|
||||
Result<Value> parent() const;
|
||||
Result<Function> fun() const;
|
||||
Result<Value> fun() const;
|
||||
uint64_t pc() const;
|
||||
Result<StackFrame> setpc(uint64_t pc);
|
||||
Result<StackFrame> incpc();
|
||||
Result<uint64_t> size() const { return _value->size; }
|
||||
|
||||
static Result<StackFrame> create(const Value& parent, const Function& fun);
|
||||
static Result<StackFrame> create(const Value& parent, const Value& fun);
|
||||
|
||||
Result<Array> slice(uint64_t start, uint64_t end) {
|
||||
Result<Array> slice(uint64_t start, uint64_t end) const {
|
||||
if (start > end || end > _value->size) return ERROR(IndexOutOfRange);
|
||||
uint64_t res_size = end - start;
|
||||
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(PodObject*)));
|
||||
|
@ -1138,6 +1138,9 @@ class StackFrame : public Object {
|
|||
return Array(TRY(MkGcRoot(pod)));
|
||||
}
|
||||
|
||||
Result<StackFrame> call(const Value& fun, uint64_t start, uint64_t end) const;
|
||||
Result<StackFrame> ret(uint64_t regno) const;
|
||||
|
||||
virtual Result<Value> copy_value() const final;
|
||||
Result<StackFrame> copy() const;
|
||||
|
||||
|
|
|
@ -644,7 +644,6 @@ Result<Expression> Compiler::compile_syntax(Context& context, Symbol& op,
|
|||
Result<Expression> Compiler::compile_fn(Context& context, Symbol& op,
|
||||
const Value& expr) {
|
||||
Context ctx = TRY(Context::create(context));
|
||||
ctx.maxreg = 1; // Reserve the slot for function itself
|
||||
|
||||
auto rest = TRY(expr.rest());
|
||||
|
||||
|
|
69
src/vm.cpp
69
src/vm.cpp
|
@ -9,7 +9,7 @@ Result<StackFrame> VM::setreg(uint64_t idx, const Value& value) {
|
|||
return _stack.set(idx, value);
|
||||
}
|
||||
|
||||
Result<Value> VM::getconst(uint64_t idx) { return _constants.get(idx); }
|
||||
Result<Value> VM::getconst(uint64_t idx) { return TRY(constants()).get(idx); }
|
||||
|
||||
Result<Value> VM::get(bool is_const, uint64_t idx) {
|
||||
if (is_const) return getconst(idx);
|
||||
|
@ -104,23 +104,7 @@ Result<void> VM::vm_call_lisp(Opcode& oc, Function& fun) {
|
|||
uint64_t reg_start = (uint64_t)oc.arg1().arg;
|
||||
uint64_t reg_end = (uint64_t)oc.arg2().arg;
|
||||
|
||||
if (fun.arity() != (reg_end - reg_start - 1)) {
|
||||
return ERROR(ArgumentCountMismatch);
|
||||
}
|
||||
|
||||
auto trunc_stack = TRY(_stack.settop(reg_start));
|
||||
auto new_stack = TRY(StackFrame::create(TRY(trunc_stack.copy_value()), fun));
|
||||
|
||||
for (uint64_t i = 0; i < reg_end - reg_start; i++) {
|
||||
new_stack = TRY(new_stack.set(i, TRY(_stack.get(reg_start + i))));
|
||||
}
|
||||
|
||||
_stack = std::move(new_stack);
|
||||
|
||||
_code = TRY(fun.code());
|
||||
_constants = TRY(fun.constants());
|
||||
_closure = TRY(fun.closure());
|
||||
_fun = std::move(fun);
|
||||
_stack = TRY(_stack.call(TRY(fun.copy_value()), reg_start, reg_end));
|
||||
|
||||
return Result<void>();
|
||||
}
|
||||
|
@ -154,21 +138,14 @@ Result<void> VM::vm_call(Opcode& oc) {
|
|||
}
|
||||
|
||||
Result<void> VM::vm_selfcall(Opcode& oc) {
|
||||
auto fun = TRY(_stack.fun());
|
||||
if (!fun.is<Function>()) return ERROR(TypeMismatch);
|
||||
Function& lisp_fun = *fun.to<Function>();
|
||||
|
||||
uint64_t reg_start = (uint64_t)oc.arg1().arg;
|
||||
uint64_t reg_end = (uint64_t)oc.arg2().arg;
|
||||
|
||||
if (_fun.arity() != (reg_end - reg_start - 1)) {
|
||||
return ERROR(ArgumentCountMismatch);
|
||||
}
|
||||
|
||||
auto trunc_stack = TRY(_stack.settop(reg_start));
|
||||
auto new_stack = TRY(StackFrame::create(TRY(trunc_stack.copy_value()), _fun));
|
||||
|
||||
for (uint64_t i = 0; i < reg_end - reg_start; i++) {
|
||||
new_stack = TRY(new_stack.set(i, TRY(_stack.get(reg_start + i))));
|
||||
}
|
||||
|
||||
_stack = std::move(new_stack);
|
||||
_stack = TRY(_stack.call(fun, reg_start, reg_end));
|
||||
|
||||
return Result<void>();
|
||||
}
|
||||
|
@ -180,18 +157,9 @@ Result<void> VM::vm_ret(Opcode& oc) {
|
|||
return ERROR(EndOfProgram);
|
||||
}
|
||||
|
||||
auto res = TRY(getreg((uint64_t)oc.arg1().arg));
|
||||
StackFrame& parent_stack = *parent.to<StackFrame>();
|
||||
uint64_t parent_size = TRY(parent_stack.size());
|
||||
parent_stack = TRY(parent_stack.set(parent_size, res));
|
||||
auto regnum = (uint64_t)oc.arg1().arg;
|
||||
|
||||
auto fun = TRY(parent_stack.fun());
|
||||
|
||||
_stack = std::move(parent_stack);
|
||||
_code = TRY(fun.code());
|
||||
_constants = TRY(fun.constants());
|
||||
_closure = TRY(fun.closure());
|
||||
_fun = std::move(fun);
|
||||
_stack = TRY(_stack.ret(regnum));
|
||||
_stack = TRY(_stack.incpc());
|
||||
|
||||
return Result<void>();
|
||||
|
@ -223,7 +191,7 @@ Result<void> VM::vm_make_closure(Opcode& oc) {
|
|||
|
||||
Result<void> VM::vm_closure_load(Opcode& oc) {
|
||||
uint64_t acc = (uint64_t)oc.arg1().arg;
|
||||
Value val = TRY(_closure.get((uint64_t)oc.arg2().arg));
|
||||
Value val = TRY(TRY(closure()).get((uint64_t)oc.arg2().arg));
|
||||
_stack = TRY(setreg(acc, val));
|
||||
_stack = TRY(_stack.incpc());
|
||||
return Result<void>();
|
||||
|
@ -247,8 +215,8 @@ Result<void> VM::vm_global_store(Opcode& oc) {
|
|||
return Result<void>();
|
||||
}
|
||||
|
||||
Result<void> VM::step() {
|
||||
auto opcode = TRY(_code.get(_stack.pc()));
|
||||
Result<void> VM::step_bytecode() {
|
||||
auto opcode = TRY(TRY(code()).get(_stack.pc()));
|
||||
if (!opcode.is<Opcode>()) return ERROR(TypeMismatch);
|
||||
Opcode& oc = *opcode.to<Opcode>();
|
||||
|
||||
|
@ -310,6 +278,19 @@ Result<void> VM::step() {
|
|||
return Result<void>();
|
||||
}
|
||||
|
||||
Result<void> VM::step_native() { return ERROR(NotImplemented); }
|
||||
|
||||
Result<void> VM::step() {
|
||||
auto fun = TRY(_stack.fun());
|
||||
if (fun.is<Function>()) {
|
||||
return step_bytecode();
|
||||
} else if (fun.is<StdlibFunction>()) {
|
||||
return step_native();
|
||||
} else {
|
||||
return ERROR(NotImplemented);
|
||||
}
|
||||
}
|
||||
|
||||
Result<Value> VM::run() {
|
||||
while (true) {
|
||||
auto rc = step();
|
||||
|
|
45
src/vm.hpp
45
src/vm.hpp
|
@ -5,44 +5,41 @@
|
|||
class VM {
|
||||
public:
|
||||
VM() {}
|
||||
VM(StackFrame&& stack, Function&& fun, Array&& code, Array&& constants,
|
||||
Array&& closure, Dict&& globals, Value&& res)
|
||||
VM(StackFrame&& stack, Dict&& globals, Value&& res)
|
||||
: _stack(std::move(stack)),
|
||||
_fun(std::move(fun)),
|
||||
_code(std::move(code)),
|
||||
_constants(std::move(constants)),
|
||||
_closure(std::move(closure)),
|
||||
_globals(std::move(globals)),
|
||||
_res(std::move(res)) {}
|
||||
|
||||
VM(VM&& vm)
|
||||
: _stack(std::move(vm._stack)),
|
||||
_fun(std::move(vm._fun)),
|
||||
_code(std::move(vm._code)),
|
||||
_constants(std::move(vm._constants)),
|
||||
_closure(std::move(vm._closure)),
|
||||
_globals(std::move(vm._globals)),
|
||||
_res(std::move(vm._res)) {}
|
||||
|
||||
VM(const VM&) = delete;
|
||||
|
||||
static Result<VM> create(const Module& mod, const Dict& globals) {
|
||||
auto fun = TRY(mod.fun());
|
||||
auto fun = Value(TRY(mod.fun()));
|
||||
auto nil = Value(TRY(Nil::create()));
|
||||
auto stack = TRY(StackFrame::create(nil, fun));
|
||||
|
||||
auto globals_copy = TRY(globals.copy());
|
||||
|
||||
/*
|
||||
auto code = TRY(fun.code());
|
||||
auto constants = TRY(fun.constants());
|
||||
auto closure = TRY(fun.closure());
|
||||
auto globals_copy = TRY(globals.copy());
|
||||
*/
|
||||
|
||||
return VM(std::move(stack), std::move(fun), std::move(code),
|
||||
std::move(constants), std::move(closure), std::move(globals_copy),
|
||||
std::move(nil));
|
||||
return VM(std::move(stack), std::move(globals_copy), std::move(nil));
|
||||
}
|
||||
|
||||
Result<Value> run();
|
||||
|
||||
Result<void> step();
|
||||
Result<void> step_bytecode();
|
||||
Result<void> step_native();
|
||||
|
||||
Result<void> vm_mov(Opcode& oc);
|
||||
Result<void> vm_add(Opcode& oc);
|
||||
Result<void> vm_mul(Opcode& oc);
|
||||
|
@ -72,12 +69,24 @@ class VM {
|
|||
|
||||
Result<Dict> globals() { return _globals.copy(); }
|
||||
|
||||
Result<Array> code() {
|
||||
auto fun = TRY(_stack.fun());
|
||||
if (!fun.is<Function>()) return ERROR(TypeMismatch);
|
||||
return fun.to<Function>()->code();
|
||||
}
|
||||
Result<Array> constants() {
|
||||
auto fun = TRY(_stack.fun());
|
||||
if (!fun.is<Function>()) return ERROR(TypeMismatch);
|
||||
return fun.to<Function>()->constants();
|
||||
}
|
||||
Result<Array> closure() {
|
||||
auto fun = TRY(_stack.fun());
|
||||
if (!fun.is<Function>()) return ERROR(TypeMismatch);
|
||||
return fun.to<Function>()->closure();
|
||||
}
|
||||
|
||||
private:
|
||||
StackFrame _stack;
|
||||
Function _fun;
|
||||
Array _code;
|
||||
Array _constants;
|
||||
Array _closure;
|
||||
Dict _globals;
|
||||
Value _res;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue