aboutsummaryrefslogtreecommitdiff
path: root/executor/interpreter
diff options
context:
space:
mode:
Diffstat (limited to 'executor/interpreter')
-rw-r--r--executor/interpreter/executor.c197
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;
+}