diff options
Diffstat (limited to 'executor/interpreter')
-rw-r--r-- | executor/interpreter/executor.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/executor/interpreter/executor.c b/executor/interpreter/executor.c new file mode 100644 index 0000000..0180b08 --- /dev/null +++ b/executor/interpreter/executor.c @@ -0,0 +1,197 @@ +#include "../executor.h" +#include "../../include/program.h" +#include "../../include/std/alloc.h" +#include <assert.h> + +typedef struct { + usize *stack; + usize stack_size; + usize stack_index; + isize reg[AMAL_PROGRAM_NUM_REGISTERS]; +} amal_executor_impl; + +#define IMPL \ + amal_executor_impl *impl; \ + impl = (amal_executor_impl*)self; + +#define FOUR_MEGABYTES 1024*1024*4 + +static int executor_ensure_stack_capacity(amal_executor_impl *self, usize bytes_to_add) { + const isize overflow = self->stack_size - self->stack_index * sizeof(isize) + bytes_to_add; + if(overflow > 0) { + void *new_data; + const usize new_stack_size = self->stack_size * 1.5; + if(new_stack_size > FOUR_MEGABYTES) + return AMAL_PROGRAM_INSTRUCTION_STACK_OVERFLOW; + return_if_error(am_realloc(self->stack, new_stack_size, &new_data)); + self->stack = new_data; + self->stack_size = new_stack_size; + } + return 0; +} + +int amal_executor_init(amal_executor **self) { + amal_executor_impl **impl; + impl = (amal_executor_impl**)self; + *impl = NULL; + return_if_error(am_malloc(sizeof(amal_executor_impl), (void**)impl)); + (*impl)->stack_size = 4096; + return_if_error(am_malloc((*impl)->stack_size, (void**)&(*impl)->stack)); + (*impl)->stack_index = 0; + return 0; +} + +void amal_executor_deinit(amal_executor *self) { + IMPL + am_free(impl->stack); + am_free(impl); +} + +int amal_executor_run(amal_executor *self) { + (void)self; + assert(bool_false && "TODO: Implement!"); + return 0; +} + +int amal_exec_nop(amal_executor *self) { + (void)self; + return 0; +} + +int amal_exec_setz(amal_executor *self, u8 dst_reg) { + IMPL + impl->reg[dst_reg] = 0; + return 0; +} + +int amal_exec_mov(amal_executor *self, u8 dst_reg, u8 src_reg) { + IMPL + impl->reg[dst_reg] = impl->reg[src_reg]; + return 0; +} + +int amal_exec_movi(amal_executor *self, u8 dst_reg, i64 imm) { + IMPL + impl->reg[dst_reg] = imm; + return 0; +} + +int amal_exec_movd(amal_executor *self, u8 dst_reg, BufferView data) { + IMPL + impl->reg[dst_reg] = (uintptr_t)data.data; + return 0; +} + +int amal_exec_add(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) { + IMPL + impl->reg[dst_reg] = impl->reg[src_reg1] + impl->reg[src_reg2]; + return 0; +} + +int amal_exec_sub(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) { + IMPL + impl->reg[dst_reg] = impl->reg[src_reg1] - impl->reg[src_reg2]; + return 0; +} + +int amal_exec_imul(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) { + IMPL + impl->reg[dst_reg] = impl->reg[src_reg1] * impl->reg[src_reg2]; + return 0; +} + +int amal_exec_mul(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) { + IMPL + impl->reg[dst_reg] = impl->reg[src_reg1] * impl->reg[src_reg2]; + return 0; +} + +int amal_exec_idiv(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) { + IMPL + impl->reg[dst_reg] = impl->reg[src_reg1] / impl->reg[src_reg2]; + return 0; +} + +int amal_exec_div(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) { + IMPL + impl->reg[dst_reg] = impl->reg[src_reg1] / impl->reg[src_reg2]; + return 0; +} + +int amal_exec_push(amal_executor *self, u8 reg) { + IMPL + return_if_error(executor_ensure_stack_capacity(impl, sizeof(isize))); + impl->stack[impl->stack_index++] = impl->reg[reg]; + return 0; +} + +int amal_exec_pushi(amal_executor *self, i64 imm) { + IMPL + return_if_error(executor_ensure_stack_capacity(impl, sizeof(isize))); + impl->stack[impl->stack_index++] = imm; + return 0; +} + +int amal_exec_pushd(amal_executor *self, BufferView data) { + IMPL + return_if_error(executor_ensure_stack_capacity(impl, sizeof(isize))); + impl->stack[impl->stack_index++] = (uintptr_t)data.data; + return 0; +} + +/*int amal_exec_call(u8 dst_reg, BufferView data); +int amal_exec_callr(u8 dst_reg, BufferView data);*/ +int amal_exec_cmp(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) { + IMPL + impl->reg[dst_reg] = (impl->reg[src_reg1] == impl->reg[src_reg2]); + return 0; +} + +int amal_exec_jz(amal_executor *self, u8 dst_reg, i16 offset) { + (void)self; + (void)dst_reg; + (void)offset; + /* TODO: Implement! */ + assert(bool_false && "TODO: Implement!"); + return 0; +} + +int amal_exec_jmp(amal_executor *self, i16 offset) { + (void)self; + (void)offset; + /* TODO: Implement! */ + assert(bool_false && "TODO: Implement!"); + return 0; +} + +int amal_exec_ret(amal_executor *self) { + (void)self; + /* TODO: Implement! */ + assert(bool_false && "TODO: Implement RET. RET needs to restore the stack before returning"); + return 0; +} + +int amal_exec_func_start(amal_executor *self, u16 num_regs) { + /* + TODO: Validate stack size, or maybe remove all validation? do we really need validation? + If we need security, we could fork the process instead. + */ + + /* + Some registers need to be preserved before entering a function scope and these registers are different on different platforms. + 32-bit: EBX, ESI, EDI, EBP + 64-bit Windows: RBX, RSI, RDI, RBP, R12-R15, XMM6-XMM15 + 64-bit Linux,BSD,Mac: RBX, RBP, R12-R15 + */ + /* TODO: Preserve registers and stack frame */ + /*return executor_ensure_stack_capacity(impl, num_regs * sizeof(isize));*/ + (void)self; + (void)num_regs; + return 0; +} + +int amal_exec_func_end(amal_executor *self) { + (void)self; + /* TODO: Restore registers and stack frame and ret */ + return 0; +} |