~maelkum/viuavm

b7ee0079f7b896d7d787e4c10d7edc21e0110034 — Marek Marecki 4 months ago 113f107
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.
2 files changed, 31 insertions(+), 0 deletions(-)

M new/include/viua/vm/core.h
M new/src/vm/ins.cpp
M new/include/viua/vm/core.h => new/include/viua/vm/core.h +7 -0
@@ 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<Page> memory;
    uint64_t frame_pointer { 0 };
    uint64_t stack_break { 0 };

    using Pointer = std::pair<bool, uintptr_t>;
    auto memory_at(Pointer const) const -> void const*;

M new/src/vm/ins.cpp => new/src/vm/ins.cpp +24 -0
@@ 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;
}