From b7ee0079f7b896d7d787e4c10d7edc21e0110034 Mon Sep 17 00:00:00 2001 From: Marek Marecki Date: Fri, 26 May 2023 01:26:28 +0200 Subject: [PATCH] Save and restore memory registers The memory registers are: - frame pointer ie, the first address allocated for the frame - stack break ie, the first unallocated address on the stack These are saved during a CALL instruction, and restored during RETURN. The information is saved in the caller's frame, but the VM does it automatically - neither caller nor callee have to do anything to ensure correct operation. --- new/include/viua/vm/core.h | 7 +++++++ new/src/vm/ins.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/new/include/viua/vm/core.h b/new/include/viua/vm/core.h index b179250e1..525a3a4b2 100644 --- a/new/include/viua/vm/core.h +++ b/new/include/viua/vm/core.h @@ -283,6 +283,11 @@ struct Frame { viua::arch::Register_access result_to; + struct { + uint64_t fp { 0 }; + uint64_t sbrk { 0 }; + } saved; + inline Frame(size_t const sz, addr_type const e, addr_type const r) : registers(sz), entry_address{e}, return_address{r} {} @@ -472,6 +477,8 @@ struct Process { stack_type stack; std::vector memory; + uint64_t frame_pointer { 0 }; + uint64_t stack_break { 0 }; using Pointer = std::pair; auto memory_at(Pointer const) const -> void const*; diff --git a/new/src/vm/ins.cpp b/new/src/vm/ins.cpp index 9ea45d5ae..143fa14d8 100644 --- a/new/src/vm/ins.cpp +++ b/new/src/vm/ins.cpp @@ -1221,6 +1221,18 @@ auto execute(CALL const op, Stack& stack, ip_type const ip) -> ip_type throw abort_execution{ip, "invalid IP after call"}; } + /* + * Save: + * + * - frame pointer ie, pointer to where the frames memory area begins + * - stack break ie, pointer to where next unallocated pointer is on the + * stack memory + * + * They should be restored when the frame is popped. + */ + stack.frames.back().saved.fp = stack.proc->frame_pointer; + stack.frames.back().saved.sbrk = stack.proc->stack_break; + auto const fr_return = (stack.ip + 1); auto const fr_entry = (stack.proc->module.ip_base + (fn_addr / sizeof(viua::arch::instruction_type))); @@ -1230,6 +1242,15 @@ auto execute(CALL const op, Stack& stack, ip_type const ip) -> ip_type stack.frames.back().parameters = std::move(stack.args); stack.frames.back().result_to = op.instruction.out; + /* + * Set the frame pointer to stack break to. Usually, one of the first + * instructions in the callee is AMA which will increase the stack break + * giving the function some memory to work with. + */ + stack.proc->frame_pointer = stack.proc->stack_break; + stack.frames.back().saved.fp = stack.proc->frame_pointer; + stack.frames.back().saved.sbrk = stack.proc->stack_break; + return fr_entry; } @@ -1260,6 +1281,9 @@ auto execute(RETURN const op, Stack& stack, ip_type const ip) -> ip_type out = std::move(fr.registers.at(op.instruction.out.index)); } + stack.proc->frame_pointer = fr.saved.fp; + stack.proc->stack_break = fr.saved.sbrk; + return fr.return_address; } -- 2.45.2