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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<StackFrame> StackFrame::create(const Value& parent,
|
Result<StackFrame> StackFrame::create(const Value& parent, const Value& fun) {
|
||||||
const Function& fun) {
|
|
||||||
auto pod = TRY(arena_alloc<PodStackFrame>());
|
auto pod = TRY(arena_alloc<PodStackFrame>());
|
||||||
pod->header.tag = Tag::StackFrame;
|
pod->header.tag = Tag::StackFrame;
|
||||||
|
|
||||||
|
@ -319,6 +318,10 @@ Result<Value> StackFrame::copy_value() const {
|
||||||
return Value(StackFrame(TRY(_value.copy())));
|
return Value(StackFrame(TRY(_value.copy())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<StackFrame> StackFrame::copy() const {
|
||||||
|
return StackFrame(TRY(_value.copy()));
|
||||||
|
}
|
||||||
|
|
||||||
Result<Value> StackFrame::get(uint64_t idx) const {
|
Result<Value> StackFrame::get(uint64_t idx) const {
|
||||||
if (idx >= _value->size) return ERROR(KeyError);
|
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)));
|
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));
|
auto pod = TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * idx));
|
||||||
pod->header.tag = Tag::StackFrame;
|
pod->header.tag = Tag::StackFrame;
|
||||||
|
|
||||||
|
@ -376,8 +379,8 @@ Result<StackFrame> StackFrame::settop(uint64_t idx) {
|
||||||
Result<Value> StackFrame::parent() const {
|
Result<Value> StackFrame::parent() const {
|
||||||
return Value::create(_value->parent.get());
|
return Value::create(_value->parent.get());
|
||||||
}
|
}
|
||||||
Result<Function> StackFrame::fun() const {
|
Result<Value> StackFrame::fun() const {
|
||||||
return Function::create((PodFunction*)_value->fun.get());
|
return Value::create(_value->fun.get());
|
||||||
}
|
}
|
||||||
uint64_t StackFrame::pc() const { return _value->pc; }
|
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::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 {
|
Result<Value> Error::copy_value() const {
|
||||||
return Value(Error(TRY(_value.copy())));
|
return Value(Error(TRY(_value.copy())));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1115,17 +1115,17 @@ class StackFrame : public Object {
|
||||||
using Object::get;
|
using Object::get;
|
||||||
Result<Value> get(uint64_t idx) const;
|
Result<Value> get(uint64_t idx) const;
|
||||||
Result<StackFrame> set(uint64_t idx, const Value& val);
|
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<Value> parent() const;
|
||||||
Result<Function> fun() const;
|
Result<Value> fun() const;
|
||||||
uint64_t pc() const;
|
uint64_t pc() const;
|
||||||
Result<StackFrame> setpc(uint64_t pc);
|
Result<StackFrame> setpc(uint64_t pc);
|
||||||
Result<StackFrame> incpc();
|
Result<StackFrame> incpc();
|
||||||
Result<uint64_t> size() const { return _value->size; }
|
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);
|
if (start > end || end > _value->size) return ERROR(IndexOutOfRange);
|
||||||
uint64_t res_size = end - start;
|
uint64_t res_size = end - start;
|
||||||
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(PodObject*)));
|
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(PodObject*)));
|
||||||
|
@ -1138,6 +1138,9 @@ class StackFrame : public Object {
|
||||||
return Array(TRY(MkGcRoot(pod)));
|
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;
|
virtual Result<Value> copy_value() const final;
|
||||||
Result<StackFrame> copy() const;
|
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,
|
Result<Expression> Compiler::compile_fn(Context& context, Symbol& op,
|
||||||
const Value& expr) {
|
const Value& expr) {
|
||||||
Context ctx = TRY(Context::create(context));
|
Context ctx = TRY(Context::create(context));
|
||||||
ctx.maxreg = 1; // Reserve the slot for function itself
|
|
||||||
|
|
||||||
auto rest = TRY(expr.rest());
|
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);
|
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) {
|
Result<Value> VM::get(bool is_const, uint64_t idx) {
|
||||||
if (is_const) return getconst(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_start = (uint64_t)oc.arg1().arg;
|
||||||
uint64_t reg_end = (uint64_t)oc.arg2().arg;
|
uint64_t reg_end = (uint64_t)oc.arg2().arg;
|
||||||
|
|
||||||
if (fun.arity() != (reg_end - reg_start - 1)) {
|
_stack = TRY(_stack.call(TRY(fun.copy_value()), reg_start, reg_end));
|
||||||
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);
|
|
||||||
|
|
||||||
return Result<void>();
|
return Result<void>();
|
||||||
}
|
}
|
||||||
|
@ -154,21 +138,14 @@ Result<void> VM::vm_call(Opcode& oc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> VM::vm_selfcall(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_start = (uint64_t)oc.arg1().arg;
|
||||||
uint64_t reg_end = (uint64_t)oc.arg2().arg;
|
uint64_t reg_end = (uint64_t)oc.arg2().arg;
|
||||||
|
|
||||||
if (_fun.arity() != (reg_end - reg_start - 1)) {
|
_stack = TRY(_stack.call(fun, reg_start, reg_end));
|
||||||
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);
|
|
||||||
|
|
||||||
return Result<void>();
|
return Result<void>();
|
||||||
}
|
}
|
||||||
|
@ -180,18 +157,9 @@ Result<void> VM::vm_ret(Opcode& oc) {
|
||||||
return ERROR(EndOfProgram);
|
return ERROR(EndOfProgram);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res = TRY(getreg((uint64_t)oc.arg1().arg));
|
auto regnum = (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 fun = TRY(parent_stack.fun());
|
_stack = TRY(_stack.ret(regnum));
|
||||||
|
|
||||||
_stack = std::move(parent_stack);
|
|
||||||
_code = TRY(fun.code());
|
|
||||||
_constants = TRY(fun.constants());
|
|
||||||
_closure = TRY(fun.closure());
|
|
||||||
_fun = std::move(fun);
|
|
||||||
_stack = TRY(_stack.incpc());
|
_stack = TRY(_stack.incpc());
|
||||||
|
|
||||||
return Result<void>();
|
return Result<void>();
|
||||||
|
@ -223,7 +191,7 @@ Result<void> VM::vm_make_closure(Opcode& oc) {
|
||||||
|
|
||||||
Result<void> VM::vm_closure_load(Opcode& oc) {
|
Result<void> VM::vm_closure_load(Opcode& oc) {
|
||||||
uint64_t acc = (uint64_t)oc.arg1().arg;
|
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(setreg(acc, val));
|
||||||
_stack = TRY(_stack.incpc());
|
_stack = TRY(_stack.incpc());
|
||||||
return Result<void>();
|
return Result<void>();
|
||||||
|
@ -247,8 +215,8 @@ Result<void> VM::vm_global_store(Opcode& oc) {
|
||||||
return Result<void>();
|
return Result<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> VM::step() {
|
Result<void> VM::step_bytecode() {
|
||||||
auto opcode = TRY(_code.get(_stack.pc()));
|
auto opcode = TRY(TRY(code()).get(_stack.pc()));
|
||||||
if (!opcode.is<Opcode>()) return ERROR(TypeMismatch);
|
if (!opcode.is<Opcode>()) return ERROR(TypeMismatch);
|
||||||
Opcode& oc = *opcode.to<Opcode>();
|
Opcode& oc = *opcode.to<Opcode>();
|
||||||
|
|
||||||
|
@ -310,6 +278,19 @@ Result<void> VM::step() {
|
||||||
return Result<void>();
|
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() {
|
Result<Value> VM::run() {
|
||||||
while (true) {
|
while (true) {
|
||||||
auto rc = step();
|
auto rc = step();
|
||||||
|
|
45
src/vm.hpp
45
src/vm.hpp
|
@ -5,44 +5,41 @@
|
||||||
class VM {
|
class VM {
|
||||||
public:
|
public:
|
||||||
VM() {}
|
VM() {}
|
||||||
VM(StackFrame&& stack, Function&& fun, Array&& code, Array&& constants,
|
VM(StackFrame&& stack, Dict&& globals, Value&& res)
|
||||||
Array&& closure, Dict&& globals, Value&& res)
|
|
||||||
: _stack(std::move(stack)),
|
: _stack(std::move(stack)),
|
||||||
_fun(std::move(fun)),
|
|
||||||
_code(std::move(code)),
|
|
||||||
_constants(std::move(constants)),
|
|
||||||
_closure(std::move(closure)),
|
|
||||||
_globals(std::move(globals)),
|
_globals(std::move(globals)),
|
||||||
_res(std::move(res)) {}
|
_res(std::move(res)) {}
|
||||||
|
|
||||||
VM(VM&& vm)
|
VM(VM&& vm)
|
||||||
: _stack(std::move(vm._stack)),
|
: _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)),
|
_globals(std::move(vm._globals)),
|
||||||
_res(std::move(vm._res)) {}
|
_res(std::move(vm._res)) {}
|
||||||
|
|
||||||
VM(const VM&) = delete;
|
VM(const VM&) = delete;
|
||||||
|
|
||||||
static Result<VM> create(const Module& mod, const Dict& globals) {
|
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 nil = Value(TRY(Nil::create()));
|
||||||
auto stack = TRY(StackFrame::create(nil, fun));
|
auto stack = TRY(StackFrame::create(nil, fun));
|
||||||
|
|
||||||
|
auto globals_copy = TRY(globals.copy());
|
||||||
|
|
||||||
|
/*
|
||||||
auto code = TRY(fun.code());
|
auto code = TRY(fun.code());
|
||||||
auto constants = TRY(fun.constants());
|
auto constants = TRY(fun.constants());
|
||||||
auto closure = TRY(fun.closure());
|
auto closure = TRY(fun.closure());
|
||||||
auto globals_copy = TRY(globals.copy());
|
auto globals_copy = TRY(globals.copy());
|
||||||
|
*/
|
||||||
|
|
||||||
return VM(std::move(stack), std::move(fun), std::move(code),
|
return VM(std::move(stack), std::move(globals_copy), std::move(nil));
|
||||||
std::move(constants), std::move(closure), std::move(globals_copy),
|
|
||||||
std::move(nil));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Value> run();
|
Result<Value> run();
|
||||||
|
|
||||||
Result<void> step();
|
Result<void> step();
|
||||||
|
Result<void> step_bytecode();
|
||||||
|
Result<void> step_native();
|
||||||
|
|
||||||
Result<void> vm_mov(Opcode& oc);
|
Result<void> vm_mov(Opcode& oc);
|
||||||
Result<void> vm_add(Opcode& oc);
|
Result<void> vm_add(Opcode& oc);
|
||||||
Result<void> vm_mul(Opcode& oc);
|
Result<void> vm_mul(Opcode& oc);
|
||||||
|
@ -72,12 +69,24 @@ class VM {
|
||||||
|
|
||||||
Result<Dict> globals() { return _globals.copy(); }
|
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:
|
private:
|
||||||
StackFrame _stack;
|
StackFrame _stack;
|
||||||
Function _fun;
|
|
||||||
Array _code;
|
|
||||||
Array _constants;
|
|
||||||
Array _closure;
|
|
||||||
Dict _globals;
|
Dict _globals;
|
||||||
Value _res;
|
Value _res;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue