From d9f92cd8949825516b5cae4343bdc9cf26a5d97e Mon Sep 17 00:00:00 2001 From: Luis Michaelis Date: Sat, 10 Aug 2024 07:28:21 +0200 Subject: [PATCH] test --- include/zenkit/DaedalusVm.hh | 1 + src/DaedalusVm.cc | 60 +++++++++++++++++++++++++++--------- 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/include/zenkit/DaedalusVm.hh b/include/zenkit/DaedalusVm.hh index d71f8cd3..c80dc980 100644 --- a/include/zenkit/DaedalusVm.hh +++ b/include/zenkit/DaedalusVm.hh @@ -82,6 +82,7 @@ namespace zenkit { struct DaedalusCallStackFrame { DaedalusSymbol const* function; std::uint32_t program_counter; + std::uint32_t stack_ptr; std::shared_ptr context; }; diff --git a/src/DaedalusVm.cc b/src/DaedalusVm.cc index d00f1bd0..d2732bb8 100644 --- a/src/DaedalusVm.cc +++ b/src/DaedalusVm.cc @@ -36,19 +36,31 @@ namespace zenkit { ~StackGuard() { if (_m_inhibited) return; - switch (_m_type) { + StackGuard::fix(_m_machine, _m_type); + } + + /// \brief Inhibits this guard. + /// + /// Calling this function will cause the guard to disengage and thus not push a + /// value onto the stack. + void inhibit() { + _m_inhibited = true; + } + + static void fix(DaedalusVm* vm, DaedalusDataType type) { + switch (type) { case DaedalusDataType::FLOAT: - _m_machine->push_float(0); + vm->push_float(0); break; case DaedalusDataType::INT: case DaedalusDataType::FUNCTION: - _m_machine->push_int(0); + vm->push_int(0); break; case DaedalusDataType::STRING: - _m_machine->push_string(""); + vm->push_string(""); break; case DaedalusDataType::INSTANCE: - _m_machine->push_instance(nullptr); + vm->push_instance(nullptr); break; case DaedalusDataType::VOID: case DaedalusDataType::CLASS: @@ -57,14 +69,6 @@ namespace zenkit { } } - /// \brief Inhibits this guard. - /// - /// Calling this function will cause the guard to disengage and thus not push a - /// value onto the stack. - void inhibit() { - _m_inhibited = true; - } - private: DaedalusDataType _m_type; DaedalusVm* _m_machine; @@ -453,11 +457,39 @@ namespace zenkit { } void DaedalusVm::push_call(DaedalusSymbol const* sym) { - _m_call_stack.push({sym, _m_pc, _m_instance}); + auto var_count = this->find_parameters_for_function(sym).size(); + _m_call_stack.push({sym, _m_pc, _m_stack_ptr - static_cast(var_count), _m_instance}); } void DaedalusVm::pop_call() { auto const& call = _m_call_stack.top(); + + // First, try to fix up the stack. + if (!call.function->has_return()) { + // No special logic needed, there are supposed to be no more stack frames for + // this function, so just reset the stack for the caller. + _m_stack_ptr = call.stack_ptr; + } else { + auto remaining_locals = _m_stack_ptr - call.stack_ptr; + if (remaining_locals == 0) { + // The function is supposed to have a return value, but it does not seem to have one. + // To fix this, we just insert a default value (either 0, "" or NULL). + StackGuard::fix(this, call.function->rtype()); + } else if (remaining_locals > 1) { + // Now we have too many items left on the stack. Remove all of them, except the topmost one, + // since that one is supposed to be the return value of the function. + DaedalusStackFrame frame = _m_stack[--_m_stack_ptr]; + _m_stack_ptr = call.stack_ptr; + _m_stack[_m_stack_ptr++] = std::move(frame); + } + // else { + // We have exactly one value to be returned (as indicated by the symbol's return type). + // That means, that the compiler did not mess up the stack management, so we can just + // return that value. + // } + } + + // Second, reset PC and context, then remove the call stack frame _m_pc = call.program_counter; _m_instance = call.context; _m_call_stack.pop();