#include "../executor.h" #include "../../include/program.h" #include "../../include/std/alloc.h" #include 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; }