// SPDX-License-Identifier: MIT // Copyright (c) 2023 John Watts and the LuminaSensum contributors #include "vm.h" #include "error.h" #include "object.h" #include <stddef.h> #include <stdlib.h> struct vm_state { Object *stack; int stack_base; int stack_next; int stack_size; Object *tail_obj; const char *tail_name; }; VmState vm_create(void) { struct vm_state *state = malloc(sizeof(struct vm_state)); abort_if(state, state == NULL, "vm_create: unable to allocate state"); state->stack_size = 16; state->stack_base = 0; state->stack_next = 0; state->tail_obj = object_none(); state->tail_name = NULL; state->stack = malloc(sizeof(Object) * state->stack_size); abort_if(state, state->stack == NULL, "vm_create: unable to allocate stack"); return (VmState)state; } void vm_destroy(VmState *state) { struct vm_state **priv = (struct vm_state **)state; free((*priv)->stack); free(*priv); } void vm_stack_set(VmState state, int index, Object obj) { struct vm_state *priv = (struct vm_state *)state; int offset = priv->stack_base + index; abort_if(state, index < 0, "vm_stack_set: negative value"); abort_if(state, offset >= priv->stack_next, "vm_stack_set: stack overflow"); Object *stack_pos = &priv->stack[offset]; object_drop(state, stack_pos); *stack_pos = obj; } Object vm_stack_get(VmState state, int index) { struct vm_state *priv = (struct vm_state *)state; int offset = priv->stack_base + index; abort_if(state, index < 0, "vm_stack_get: negative value"); abort_if(state, offset >= priv->stack_next, "vm_stack_get: stack overflow"); Object obj = priv->stack[offset]; object_hold(state, obj); return obj; } void vm_stack_push(VmState state, Object obj) { struct vm_state *priv = (struct vm_state *)state; // stack_next starts at 0, stack_size starts at 1 // Convert stack_size to a max stack offset to compensate int max_stack = priv->stack_size - 1; // Check if stack_next is outside the stack before // writing to it abort_if(state, priv->stack_next > max_stack, "vm_stack_push: stack overflow"); priv->stack[priv->stack_next++] = obj; } Object vm_stack_pop(VmState state) { struct vm_state *priv = (struct vm_state *)state; abort_if(state, priv->stack_next <= priv->stack_base, "vm_stack_pop: stack base underflow"); Object obj = priv->stack[--priv->stack_next]; priv->stack[priv->stack_next] = object_none(); return obj; } void vm_stack_drop(VmState state, int count) { abort_if(state, count < 1, "vm_stack_drop: invalid drop count"); while (count--) { Object obj = vm_stack_pop(state); object_drop(state, &obj); } } int vm_stack_depth(VmState state) { struct vm_state *priv = (struct vm_state *)state; return priv->stack_next - priv->stack_base; } void vm_call(VmState state, Object obj, const char *name, int arg_count) { struct vm_state *priv = (struct vm_state *)state; int old_base = priv->stack_base; priv->stack_base = priv->stack_next - arg_count; object_hold(state, obj); do { dispatch_call(priv, obj, name); object_drop(state, &obj); obj = priv->tail_obj; name = priv->tail_name; priv->tail_obj = object_none(); priv->tail_name = NULL; } while (obj != object_none()); priv->stack_base = old_base; } void vm_tailcall(VmState state, Object obj, const char *name) { struct vm_state *priv = (struct vm_state *)state; object_hold(state, obj); priv->tail_obj = obj; priv->tail_name = name; }