From f16850d26c11e51d9f5c079c6c987ffda83d1781 Mon Sep 17 00:00:00 2001 From: Konstantin Nazarov Date: Fri, 13 Sep 2024 00:54:32 +0100 Subject: [PATCH] Switch to immutable stack frames from array-based stack --- src/arena.cpp | 8 ++-- src/common.cpp | 80 ++++++++++++++++++++++++++++------------ src/common.hpp | 19 +++++++--- src/pod.hpp | 3 +- src/valeri.cpp | 9 +++-- src/vm.cpp | 99 ++++++++++++++++++++------------------------------ src/vm.hpp | 47 ++++++++++++++++++------ 7 files changed, 154 insertions(+), 111 deletions(-) diff --git a/src/arena.cpp b/src/arena.cpp index d7e0889..e8569dd 100644 --- a/src/arena.cpp +++ b/src/arena.cpp @@ -257,15 +257,13 @@ Result Arena::gc_stack(PodStackFrame* obj) { auto nobj = TRY(alloc(sizeof(OffPtr) * obj->size)); nobj->header.tag = Tag::StackFrame; nobj->parent = TRY(gc_pod(obj->parent.get())); + nobj->fun = TRY(gc_pod(obj->fun.get())); + nobj->parent_pc = obj->parent_pc; nobj->size = obj->size; - nobj->top = obj->top; - for (uint64_t i = 0; i < obj->top; i++) { + for (uint64_t i = 0; i < obj->size; i++) { PodObject* val = obj->data[i].get(); nobj->data[i] = TRY(gc_pod(val)); } - for (uint64_t i = obj->top; i < obj->size; i++) { - nobj->data[i] = 0; - } return nobj; } diff --git a/src/common.cpp b/src/common.cpp index 0cc9ba3..8a3276f 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -302,18 +302,15 @@ Result Module::cmp(const Module& rhs) const { return res; } -Result StackFrame::create(uint64_t size) { - auto nil = Value(TRY(Nil::create())); - auto pod = TRY(arena_alloc(sizeof(OffPtr) * size)); +Result StackFrame::create(const Value& parent, const Function& fun, + uint64_t parent_pc) { + auto pod = TRY(arena_alloc()); pod->header.tag = Tag::StackFrame; - pod->parent = nil.pod(); - pod->size = size; - pod->top = 0; - - for (uint64_t i = 0; i < size; i++) { - pod->data[i] = 0; - } + pod->parent = parent.pod(); + pod->fun = fun.pod(); + pod->parent_pc = parent_pc; + pod->size = 0; return StackFrame(TRY(MkGcRoot(pod))); } @@ -323,32 +320,67 @@ Result StackFrame::copy_value() const { } Result StackFrame::get(uint64_t idx) const { - if (idx >= _value->top) return ERROR(KeyError); + if (idx >= _value->size) return ERROR(KeyError); return Value::create(_value->data[idx].get()); } -Result StackFrame::set(uint64_t idx, const Value& val) { - if (idx >= _value->size) return ERROR(KeyError); +Result StackFrame::set(uint64_t idx, const Value& val) { + uint64_t size = std::max(_value->size, idx + 1); + auto pod = TRY(arena_alloc(sizeof(OffPtr) * size)); + pod->header.tag = Tag::StackFrame; - if (idx >= _value->top) { - _value->top = idx + 1; + pod->parent = _value->parent; + pod->fun = _value->fun; + pod->parent_pc = _value->parent_pc; + pod->size = size; + + for (uint64_t i = 0; i < _value->size; i++) { + pod->data[i] = _value->data[i]; } + if (size > _value->size) { + auto nil = Value(TRY(Nil::create())); + for (uint64_t i = _value->size; i < size; i++) { + pod->data[i] = nil.pod(); + } + } + pod->data[idx] = val.pod(); - _value->data[idx] = val.pod(); - return Result(); + return StackFrame(TRY(MkGcRoot(pod))); } -Result StackFrame::settop(uint64_t idx) { - uint64_t top = _value->top; - for (uint64_t i = std::min(top, idx); i < std::max(top, idx); i++) { - _value->data[i] = 0; - } - _value->top = idx; +Result StackFrame::settop(uint64_t idx) { + auto pod = TRY(arena_alloc(sizeof(OffPtr) * idx)); + pod->header.tag = Tag::StackFrame; - return Result(); + pod->parent = _value->parent; + pod->fun = _value->fun; + pod->parent_pc = _value->parent_pc; + pod->size = idx; + + auto min_idx = std::min(_value->size, idx); + for (uint64_t i = 0; i < min_idx; i++) { + pod->data[i] = _value->data[i]; + } + + if (min_idx < idx) { + auto nil = Value(TRY(Nil::create())); + for (uint64_t i = min_idx; i < idx; i++) { + pod->data[i] = nil.pod(); + } + } + + return StackFrame(TRY(MkGcRoot(pod))); } +Result StackFrame::parent() const { + return Value::create(_value->parent.get()); +} +Result StackFrame::fun() const { + return Function::create((PodFunction*)_value->fun.get()); +} +uint64_t StackFrame::parent_pc() const { return _value->parent_pc; } + Result Error::copy_value() const { return Value(Error(TRY(_value.copy()))); } diff --git a/src/common.hpp b/src/common.hpp index 40c8059..1ca263d 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -1092,6 +1092,11 @@ class StackFrame : public Object { StackFrame(StackFrame&& rhs) : _value(std::move(rhs._value)) {} StackFrame(GcRoot&& val) : _value(std::move(val)) {} + StackFrame& operator=(StackFrame&& rhs) { + _value = std::move(rhs._value); + return *this; + } + virtual Tag tag() const final { return Tag::StackFrame; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { @@ -1109,14 +1114,18 @@ class StackFrame : public Object { using Object::get; Result get(uint64_t idx) const; - Result set(uint64_t idx, const Value& val); - Result settop(uint64_t idx); - uint64_t gettop() { return _value->top; } + Result set(uint64_t idx, const Value& val); + Result settop(uint64_t idx); + Result parent() const; + Result fun() const; + uint64_t parent_pc() const; + Result size() const { return _value->size; } - static Result create(uint64_t size); + static Result create(const Value& parent, const Function& fun, + uint64_t parent_pc); Result slice(uint64_t start, uint64_t end) { - if (start > end || end > gettop()) return ERROR(IndexOutOfRange); + if (start > end || end > _value->size) return ERROR(IndexOutOfRange); uint64_t res_size = end - start; auto pod = TRY(arena_alloc(res_size * sizeof(PodObject*))); pod->header.tag = Tag::Array; diff --git a/src/pod.hpp b/src/pod.hpp index 94f4fdf..4c11009 100644 --- a/src/pod.hpp +++ b/src/pod.hpp @@ -197,8 +197,9 @@ class PodStackFrame final : public PodObject { PodStackFrame() : PodObject(Tag::StackFrame) {}; OffPtr parent; + OffPtr fun; + uint64_t parent_pc; uint64_t size; - uint64_t top; OffPtr data[]; }; diff --git a/src/valeri.cpp b/src/valeri.cpp index df54453..463bbed 100644 --- a/src/valeri.cpp +++ b/src/valeri.cpp @@ -21,9 +21,10 @@ Result run_string(const String& fname, const String& src) { auto compiled = TRY(compile(fname, parsed)); Module& mod = *compiled.to(); - auto vm = TRY(VM::create()); + Dict globals = TRY(Dict::create()); + auto vm = TRY(VM::create(mod, globals)); - auto res = TRY(vm.run(mod)); + auto res = TRY(vm.run()); return res; } @@ -64,8 +65,8 @@ Result run_repl() { auto compiled = maybe_compiled.release_value(); Module& mod = *compiled.to(); - auto vm = TRY(VM::create()); - auto maybe_res = vm.run(mod, globals); + auto vm = TRY(VM::create(mod, globals)); + auto maybe_res = vm.run(); if (maybe_res.has_value()) { auto res = maybe_res.release_value(); diff --git a/src/vm.cpp b/src/vm.cpp index a718173..e167d2e 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -3,11 +3,10 @@ #include "common.hpp" #include "stdlib.hpp" -Result VM::getreg(uint64_t idx) { return _stack.get(_base + idx); } +Result VM::getreg(uint64_t idx) { return _stack.get(idx); } -Result VM::setreg(uint64_t idx, const Value& value) { - TRY(_stack.set(_base + idx, value)); - return Result(); +Result VM::setreg(uint64_t idx, const Value& value) { + return _stack.set(idx, value); } Result VM::getconst(uint64_t idx) { return _constants.get(idx); } @@ -20,7 +19,7 @@ Result VM::get(bool is_const, uint64_t idx) { Result VM::vm_mov(Opcode& oc) { uint64_t acc = (uint64_t)oc.arg1().arg; Value val = TRY(get(oc.arg2().is_const, (uint64_t)oc.arg2().arg)); - setreg(acc, val); + _stack = TRY(setreg(acc, val)); _pc++; return Result(); } @@ -30,7 +29,7 @@ Result VM::vm_add(Opcode& oc) { Value val1 = TRY(get(oc.arg2().is_const, (uint64_t)oc.arg2().arg)); Value val2 = TRY(get(oc.arg3().is_const, (uint64_t)oc.arg3().arg)); Value res = TRY(val1.add(val2)); - setreg(acc, res); + _stack = TRY(setreg(acc, res)); _pc++; return Result(); } @@ -40,7 +39,7 @@ Result VM::vm_mul(Opcode& oc) { Value val1 = TRY(get(oc.arg2().is_const, (uint64_t)oc.arg2().arg)); Value val2 = TRY(get(oc.arg3().is_const, (uint64_t)oc.arg3().arg)); Value res = TRY(val1.mul(val2)); - setreg(acc, res); + _stack = TRY(setreg(acc, res)); _pc++; return Result(); } @@ -50,7 +49,7 @@ Result VM::vm_sub(Opcode& oc) { Value val1 = TRY(get(oc.arg2().is_const, (uint64_t)oc.arg2().arg)); Value val2 = TRY(get(oc.arg3().is_const, (uint64_t)oc.arg3().arg)); Value res = TRY(val1.sub(val2)); - setreg(acc, res); + _stack = TRY(setreg(acc, res)); _pc++; return Result(); } @@ -60,7 +59,7 @@ Result VM::vm_div(Opcode& oc) { Value val1 = TRY(get(oc.arg2().is_const, (uint64_t)oc.arg2().arg)); Value val2 = TRY(get(oc.arg3().is_const, (uint64_t)oc.arg3().arg)); Value res = TRY(val1.div(val2)); - setreg(acc, res); + _stack = TRY(setreg(acc, res)); _pc++; return Result(); } @@ -109,21 +108,21 @@ Result VM::vm_call_lisp(Opcode& oc, Function& fun) { return ERROR(ArgumentCountMismatch); } - uint64_t old_base = _base; + auto trunc_stack = TRY(_stack.settop(reg_start)); + auto new_stack = + TRY(StackFrame::create(TRY(trunc_stack.copy_value()), fun, _pc)); - Value fun_val = TRY(_fun.copy()); - Value oldbase_val = TRY(Int64::create(old_base)); - Value pc_val = TRY(Int64::create(_pc)); - _callstack.set(_callstack.gettop(), fun_val); - _callstack.set(_callstack.gettop(), oldbase_val); - _callstack.set(_callstack.gettop(), pc_val); + 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); _pc = 0; - _base = _base + reg_start; return Result(); } @@ -135,7 +134,7 @@ Result VM::vm_call_stdlib(Opcode& oc, StdlibFunction& fun) { auto params = TRY(_stack.slice(reg_start + 1, reg_end)); auto res = TRY(call_stdlib_function(fun.fun_id(), params)); - setreg(oc.arg1().arg, res); + _stack = TRY(setreg(oc.arg1().arg, res)); _pc++; return Result(); @@ -164,47 +163,41 @@ Result VM::vm_selfcall(Opcode& oc) { return ERROR(ArgumentCountMismatch); } - uint64_t old_base = _base; + auto trunc_stack = TRY(_stack.settop(reg_start)); + auto new_stack = + TRY(StackFrame::create(TRY(trunc_stack.copy_value()), _fun, _pc)); - Value fun_val = TRY(_fun.copy()); - Value oldbase_val = TRY(Int64::create(old_base)); - Value pc_val = TRY(Int64::create(_pc)); - _callstack.set(_callstack.gettop(), fun_val); - _callstack.set(_callstack.gettop(), oldbase_val); - _callstack.set(_callstack.gettop(), pc_val); + 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); _pc = 0; - _base = _base + reg_start; return Result(); } Result VM::vm_ret(Opcode& oc) { - if (_callstack.gettop() == 0) { + auto parent = TRY(_stack.parent()); + if (parent.is()) { _res = TRY(getreg((uint64_t)oc.arg1().arg)); return ERROR(EndOfProgram); } - Value fun_val = TRY(_callstack.get(_callstack.gettop() - 3)); - Value oldbase_val = TRY(_callstack.get(_callstack.gettop() - 2)); - Value pc_val = TRY(_callstack.get(_callstack.gettop() - 1)); + auto res = TRY(getreg((uint64_t)oc.arg1().arg)); + StackFrame& parent_stack = *parent.to(); + uint64_t parent_size = TRY(parent_stack.size()); + parent_stack = TRY(parent_stack.set(parent_size, res)); - if (!oldbase_val.is() || !pc_val.is() || - !fun_val.is()) - return ERROR(TypeMismatch); - - Function& fun = *fun_val.to(); - uint64_t oldbase = oldbase_val.to()->value(); - uint64_t pc = pc_val.to()->value(); + auto fun = TRY(parent_stack.fun()); + uint64_t pc = _stack.parent_pc(); + _stack = std::move(parent_stack); _code = TRY(fun.code()); _constants = TRY(fun.constants()); _closure = TRY(fun.closure()); _fun = std::move(fun); _pc = pc + 1; - _base = oldbase; - - TRY(_callstack.settop(_callstack.gettop() - 3)); return Result(); } @@ -215,8 +208,8 @@ Result VM::vm_jump(Opcode& oc) { } Result VM::vm_make_closure(Opcode& oc) { - uint64_t begin = (uint64_t)_base + oc.arg1().arg + 1; - uint64_t end = (uint64_t)_base + oc.arg2().arg; + uint64_t begin = oc.arg1().arg + 1; + uint64_t end = oc.arg2().arg; Value fun_proto = TRY(get(oc.arg1().is_const, (uint64_t)oc.arg1().arg)); if (!fun_proto.is()) return ERROR(TypeMismatch); @@ -225,7 +218,7 @@ Result VM::vm_make_closure(Opcode& oc) { Value fun = TRY(Function::create(*fun_proto.to(), closure)); - setreg(oc.arg1().arg, fun); + _stack = TRY(setreg(oc.arg1().arg, fun)); _pc++; @@ -235,7 +228,7 @@ Result VM::vm_make_closure(Opcode& oc) { Result VM::vm_closure_load(Opcode& oc) { uint64_t acc = (uint64_t)oc.arg1().arg; Value val = TRY(_closure.get((uint64_t)oc.arg2().arg)); - setreg(acc, val); + _stack = TRY(setreg(acc, val)); _pc++; return Result(); } @@ -244,7 +237,7 @@ Result VM::vm_global_load(Opcode& oc) { uint64_t acc = (uint64_t)oc.arg1().arg; Value sym = TRY(get(oc.arg2().is_const, (uint64_t)oc.arg2().arg)); Value val = TRY(_globals.get(sym)); - setreg(acc, val); + _stack = TRY(setreg(acc, val)); _pc++; return Result(); } @@ -321,17 +314,7 @@ Result VM::step() { return Result(); } -// Result Int64::copy() const { return Value(Int64(TRY(_value.copy()))); -// } -Result VM::run(const Module& mod, const Dict& globals) { - _fun = TRY(mod.fun()); - _pc = 0; - _base = 0; - _code = TRY(_fun.code()); - _constants = TRY(_fun.constants()); - _closure = TRY(_fun.closure()); - _globals = TRY(globals.copy()); - +Result VM::run() { while (true) { auto rc = step(); if (!rc.has_error()) continue; @@ -343,7 +326,3 @@ Result VM::run(const Module& mod, const Dict& globals) { } return ERROR(NotImplemented); } - -Result VM::run(const Module& mod) { - return run(mod, TRY(Dict::create())); -} diff --git a/src/vm.hpp b/src/vm.hpp index 17ecf1c..daa7ae8 100644 --- a/src/vm.hpp +++ b/src/vm.hpp @@ -5,20 +5,45 @@ class VM { public: VM() {} - VM(StackFrame&& stack, StackFrame&& callstack) - : _stack(std::move(stack)), _callstack(std::move(callstack)) {} + VM(StackFrame&& stack, Function&& fun, Array&& code, Array&& constants, + Array&& closure, Dict&& globals, uint64_t pc, 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)), + _pc(pc), + _res(std::move(res)) {} VM(VM&& vm) - : _stack(std::move(vm._stack)), _callstack(std::move(vm._callstack)) {} + : _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)), + _pc(vm._pc), + _res(std::move(vm._res)) {} + VM(const VM&) = delete; - static Result create() { - auto stack = TRY(StackFrame::create(16 * 1024)); - auto callstack = TRY(StackFrame::create(16 * 1024)); - return VM(std::move(stack), std::move(callstack)); + static Result create(const Module& mod, const Dict& globals) { + auto fun = TRY(mod.fun()); + auto nil = Value(TRY(Nil::create())); + auto stack = TRY(StackFrame::create(nil, fun, 0)); + + uint64_t pc = 0; + 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), + pc, std::move(nil)); } - Result run(const Module& mod); - Result run(const Module& mod, const Dict& globals); + Result run(); Result step(); Result vm_mov(Opcode& oc); @@ -46,19 +71,17 @@ class VM { Result get(bool is_const, uint64_t idx); Result getconst(uint64_t idx); Result getreg(uint64_t idx); - Result setreg(uint64_t idx, const Value& value); + Result setreg(uint64_t idx, const Value& value); Result globals() { return _globals.copy(); } private: StackFrame _stack; - StackFrame _callstack; Function _fun; Array _code; Array _constants; Array _closure; Dict _globals; uint64_t _pc; - uint64_t _base; Value _res; };