diff options
author | dec05eba <dec05eba@protonmail.com> | 2019-08-14 01:30:08 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2020-07-25 14:36:46 +0200 |
commit | 664fbc5f5c947aaa04bbbf132d9c935959e34a9c (patch) | |
tree | fb25c4d6b8ccc5c6c7d02ad1170947096ff684e9 /src | |
parent | ea97370f973374f863e4296c2bb872be8b5235a3 (diff) |
Move program code generation and execution out of program (make it generic)
Diffstat (limited to 'src')
-rw-r--r-- | src/program.c | 251 |
1 files changed, 43 insertions, 208 deletions
diff --git a/src/program.c b/src/program.c index 60e9870..54709b1 100644 --- a/src/program.c +++ b/src/program.c @@ -59,13 +59,6 @@ int amal_program_init(amal_program *self) { self->read_index = 0; self->num_strings = 0; self->num_intermediates = 0; - am_memset(self->reg, 0, sizeof(self->reg)); - self->stack = NULL; - self->stack_size = 4096; - am_memset(&self->asm, 0, sizeof(self->asm)); - cleanup_if_error(am_malloc(self->stack_size, (void**)&self->stack)); - cleanup_if_error(asm_init(&self->asm)); - self->stack_index = 0; cleanup_if_error(amal_program_append_header(self)); return 0; @@ -79,9 +72,6 @@ void amal_program_deinit(amal_program *self) { buffer_deinit(&self->data); am_free(self->string_indices); self->string_indices = NULL; - am_free(self->stack); - self->stack = NULL; - asm_deinit(&self->asm); } int amal_program_append_bytecode(amal_program *self, Bytecode *bytecode) { @@ -192,7 +182,7 @@ static CHECK_RESULT int amal_program_read_strings(amal_program *self) { if(bytes_left_to_read(self) < string_size) return AMAL_PROGRAM_INVALID_STRINGS; - self->read_index += string_size +1; /* +1 to skip null-termination character */ + self->read_index += string_size + 1; /* +1 to skip null-termination character */ } assert(self->read_index == read_end); @@ -208,7 +198,7 @@ static CHECK_RESULT int amal_program_get_intermediate_by_index(amal_program *sel return 0; } -static CHECK_RESULT int amal_program_get_data_by_index(amal_program *self, u16 index, char **result) { +static CHECK_RESULT int amal_program_get_data_by_index(amal_program *self, u16 index, BufferView *result) { char *str_ptr; if(index >= self->num_strings) { @@ -217,41 +207,17 @@ static CHECK_RESULT int amal_program_get_data_by_index(amal_program *self, u16 i } str_ptr = self->strings_start + self->string_indices[index]; - am_memcpy(result, &str_ptr, sizeof(char**)); + am_memcpy(&result->size, str_ptr, sizeof(u16)); + result->data = str_ptr + sizeof(u16); return 0; } -static CHECK_RESULT int ensure_stack_capacity_for_push(amal_program *self) { - if(self->stack_index >= self->stack_size) { - self->stack_size *= 2; - /* 4MB */ - if(self->stack_size >= (1<<22)) - return AMAL_PROGRAM_INSTRUCTION_STACK_OVERFLOW; - if(am_realloc(self->stack, self->stack_size, (void**)&self->stack) != 0) - return AMAL_PROGRAM_INSTRUCTION_STACK_OOM; - } - return 0; -} - -static i64 abs_i64(i64 value) { - return value >= 0 ? value : -value; -} - -#ifdef DEBUG -static int assert_reg_outside_stack() { - assert(bool_false && "Register outside stack!"); - return 0; -} -#endif - -static CHECK_RESULT int amal_program_read_instructions(amal_program *self) { +static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_executor *executor) { u32 instructions_size; u32 read_start; u32 read_end; bool inside_func; - u16 func_num_registers; - func_num_registers = 0; inside_func = bool_false; (void)inside_func; @@ -267,20 +233,8 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self) { /* TODO: self->reg should be of type Number and each arithmetic operation should operate on the type of the register. - - TODO: Currently almost all operations are performed on memory. This should be optimized - to take advantage of registers. - - TODO: Operations with memory registers could access outside the stack. Should this be checked? */ - #ifdef DEBUG - #define get_register_at_offset(offset) \ - (self->data.data[self->read_index + (offset)] < func_num_registers ? self->data.data[self->read_index + (offset)] * (int)sizeof(usize) + (int)sizeof(usize) : assert_reg_outside_stack()) - #else - #define get_register_at_offset(offset) (self->data.data[self->read_index + (offset)] * (int)sizeof(usize) + (int)sizeof(usize)) - #endif - read_start = self->read_index; read_end = read_start + instructions_size; while(self->read_index < read_end) { @@ -289,162 +243,74 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self) { self->read_index += sizeof(AmalOpcodeType); switch(opcode) { case AMAL_OP_NOP: { - return_if_error(asm_nop(&self->asm)); + return_if_error(amal_exec_nop(executor)); break; } case AMAL_OP_SETZ: { - AsmPtr dst; - asm_ptr_init_disp(&dst, RBP, -(i32)get_register_at_offset(0)); - return_if_error(asm_mov_mi(&self->asm, &dst, 0)); - self->reg[(u8)self->data.data[self->read_index]] = 0; + return_if_error(amal_exec_setz(executor, self->data.data[self->read_index])); self->read_index += 1; break; } case AMAL_OP_MOV: { - AsmPtr ptr; - asm_ptr_init_disp(&ptr, RBP, -(i32)get_register_at_offset(1)); - return_if_error(asm_mov_rm(&self->asm, RAX, &ptr)); - - asm_ptr_init_disp(&ptr, RBP, -(i32)get_register_at_offset(0)); - return_if_error(asm_mov_mr(&self->asm, &ptr, RAX)); - - self->reg[(u8)self->data.data[self->read_index]] = self->reg[(u8)self->data.data[self->read_index + 1]]; + return_if_error(amal_exec_mov(executor, self->data.data[self->read_index], self->data.data[self->read_index + 1])); self->read_index += 2; break; } case AMAL_OP_MOVI: { - u8 dst_reg; u16 intermediate_index; Number number; - dst_reg = self->reg[(u8)self->data.data[self->read_index]]; am_memcpy(&intermediate_index, &self->data.data[self->read_index + sizeof(u8)], sizeof(intermediate_index)); - return_if_error(amal_program_get_intermediate_by_index(self, intermediate_index, &number)); - self->reg[dst_reg] = number.value.integer; - - /* TODO: if @number is a float then use float instructions */ - if(abs_i64(number.value.integer) <= INT32_MAX) { - AsmPtr dst; - asm_ptr_init_disp(&dst, RBP, -(i32)get_register_at_offset(0)); - return_if_error(asm_mov_mi(&self->asm, &dst, number.value.integer)); - } else { - AsmPtr dst; - asm_ptr_init_disp(&dst, RBP, -(i32)get_register_at_offset(0)); - return_if_error(asm_mov_ri(&self->asm, RAX, number.value.integer)); - return_if_error(asm_mov_mr(&self->asm, &dst, RAX)); - } + return_if_error(amal_exec_movi(executor, self->data.data[self->read_index], number.value.integer)); self->read_index += 3; break; } case AMAL_OP_MOVD: { - u8 dst_reg; u16 data_index; - char *data_ptr; - AsmPtr dst; + BufferView data_ptr; - dst_reg = self->reg[(u8)self->data.data[self->read_index]]; am_memcpy(&data_index, &self->data.data[self->read_index + sizeof(u8)], sizeof(data_index)); return_if_error(amal_program_get_data_by_index(self, data_index, &data_ptr)); - self->reg[dst_reg] = (uintptr_t)data_ptr; - - asm_ptr_init_disp(&dst, RBP, -(i32)get_register_at_offset(0)); - return_if_error(asm_mov_ri(&self->asm, RAX, (uintptr_t)data_ptr)); - return_if_error(asm_mov_mr(&self->asm, &dst, RAX)); + return_if_error(amal_exec_movd(executor, self->data.data[self->read_index], data_ptr)); self->read_index += 3; break; } case AMAL_OP_ADD: { - AsmPtr dst; - AsmPtr reg1; - AsmPtr reg2; - - asm_ptr_init_disp(&dst, RBP, -(i32)get_register_at_offset(0)); - asm_ptr_init_disp(®1, RBP, -(i32)get_register_at_offset(1)); - asm_ptr_init_disp(®2, RBP, -(i32)get_register_at_offset(2)); - - return_if_error(asm_mov_rm(&self->asm, RAX, ®1)); - return_if_error(asm_mov_rm(&self->asm, RCX, ®2)); - return_if_error(asm_add_rr(&self->asm, RAX, RCX)); - return_if_error(asm_mov_mr(&self->asm, &dst, RAX)); - + return_if_error(amal_exec_add(executor, self->data.data[self->read_index], self->data.data[self->read_index + 1], self->data.data[self->read_index + 2])); self->read_index += 3; break; } case AMAL_OP_SUB: { - AsmPtr dst; - AsmPtr reg1; - AsmPtr reg2; - - asm_ptr_init_disp(&dst, RBP, -(i32)get_register_at_offset(0)); - asm_ptr_init_disp(®1, RBP, -(i32)get_register_at_offset(1)); - asm_ptr_init_disp(®2, RBP, -(i32)get_register_at_offset(2)); - - return_if_error(asm_mov_rm(&self->asm, RAX, ®1)); - return_if_error(asm_mov_rm(&self->asm, RCX, ®2)); - return_if_error(asm_sub_rr(&self->asm, RAX, RCX)); - return_if_error(asm_mov_mr(&self->asm, &dst, RAX)); - + return_if_error(amal_exec_sub(executor, self->data.data[self->read_index], self->data.data[self->read_index + 1], self->data.data[self->read_index + 2])); self->read_index += 3; break; } case AMAL_OP_IMUL: { - AsmPtr dst; - AsmPtr reg1; - AsmPtr reg2; - - asm_ptr_init_disp(&dst, RBP, -(i32)get_register_at_offset(0)); - asm_ptr_init_disp(®1, RBP, -(i32)get_register_at_offset(1)); - asm_ptr_init_disp(®2, RBP, -(i32)get_register_at_offset(2)); - - return_if_error(asm_mov_rm(&self->asm, RAX, ®1)); - return_if_error(asm_mov_rm(&self->asm, RCX, ®2)); - return_if_error(asm_imul_rr(&self->asm, RAX, RCX)); - return_if_error(asm_mov_mr(&self->asm, &dst, RAX)); - + return_if_error(amal_exec_imul(executor, self->data.data[self->read_index], self->data.data[self->read_index + 1], self->data.data[self->read_index + 2])); self->read_index += 3; break; } case AMAL_OP_MUL: { - #if 0 - AsmPtr dst; - AsmPtr reg1; - AsmPtr reg2; - - asm_ptr_init_disp(&dst, RBP, -(i32)get_register_at_offset(0)); - asm_ptr_init_disp(®1, RBP, -(i32)get_register_at_offset(1)); - asm_ptr_init_disp(®2, RBP, -(i32)get_register_at_offset(2)); - - return_if_error(asm_mov_rm(&self->asm, RAX, ®1)); - return_if_error(asm_mov_rm(&self->asm, RCX, ®2)); - return_if_error(asm_mul_rr(&self->asm, RAX, RCX)); - return_if_error(asm_mov_mr(&self->asm, &dst, RAX)); - #endif - + return_if_error(amal_exec_mul(executor, self->data.data[self->read_index], self->data.data[self->read_index + 1], self->data.data[self->read_index + 2])); self->read_index += 3; break; } case AMAL_OP_IDIV: { + return_if_error(amal_exec_idiv(executor, self->data.data[self->read_index], self->data.data[self->read_index + 1], self->data.data[self->read_index + 2])); self->read_index += 3; break; } case AMAL_OP_DIV: { + return_if_error(amal_exec_div(executor, self->data.data[self->read_index], self->data.data[self->read_index + 1], self->data.data[self->read_index + 2])); self->read_index += 3; break; } case AMAL_OP_PUSH: { - #if 0 - AsmPtr reg; - asm_ptr_init_disp(®, RBP, -(i32)get_register_at_offset(0)); - - return_if_error(ensure_stack_capacity_for_push(self)); - self->stack[self->stack_index] = self->reg[(u8)self->data.data[self->read_index]]; - ++self->stack_index; - return_if_error(asm_pushm(&self->asm, ®)); - #endif + return_if_error(amal_exec_push(executor, self->data.data[self->read_index])); self->read_index += 1; break; } @@ -454,23 +320,17 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self) { am_memcpy(&intermediate_index, &self->data.data[self->read_index], sizeof(intermediate_index)); return_if_error(amal_program_get_intermediate_by_index(self, intermediate_index, &number)); - return_if_error(ensure_stack_capacity_for_push(self)); - - self->stack[self->stack_index] = number.value.integer; - ++self->stack_index; + return_if_error(amal_exec_pushi(executor, number.value.integer)); self->read_index += 2; break; } case AMAL_OP_PUSHD: { u16 data_index; - char *data_ptr; + BufferView data_ptr; am_memcpy(&data_index, &self->data.data[self->read_index], sizeof(data_index)); return_if_error(amal_program_get_data_by_index(self, data_index, &data_ptr)); - return_if_error(ensure_stack_capacity_for_push(self)); - - self->stack[self->stack_index] = (uintptr_t)data_ptr; - ++self->stack_index; + return_if_error(amal_exec_pushd(executor, data_ptr)); self->read_index += 2; break; } @@ -483,75 +343,41 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self) { self->read_index += 2; break; case AMAL_OP_CMP: { - self->reg[(u8)self->data.data[self->read_index]] = - self->reg[(u8)self->data.data[self->read_index + 1]] == self->reg[(u8)self->data.data[self->read_index + 2]]; + return_if_error(amal_exec_cmp(executor, self->data.data[self->read_index], self->data.data[self->read_index + 1], self->data.data[self->read_index + 2])); self->read_index += 3; break; } case AMAL_OP_JZ: { - #if 0 - u8 reg; i16 jump_offset; - u32 jump_target; - - reg = (u8)self->data.data[self->read_index]; - am_memcpy(&jump_offset, &self->data.data[self->read_index + 1], sizeof(jump_offset)); - jump_target = (isize)self->read_index + jump_offset; - if(jump_target < read_start || jump_target >= read_end) - return AMAL_PROGRAM_INSTRUCTION_ILLEGAL_JUMP_TARGET; - #endif + am_memcpy(&jump_offset, &self->data.data[self->read_index + sizeof(u8)], sizeof(jump_offset)); + return_if_error(amal_exec_jz(executor, self->data.data[self->read_index], jump_offset)); self->read_index += 3; break; } case AMAL_OP_JMP: { - #if 0 i16 jump_offset; - u32 jump_target; - am_memcpy(&jump_offset, &self->data.data[self->read_index], sizeof(jump_offset)); - jump_target = (isize)self->read_index + jump_offset; - if(jump_target < read_start || jump_target >= read_end) - return AMAL_PROGRAM_INSTRUCTION_ILLEGAL_JUMP_TARGET; - #endif + return_if_error(amal_exec_jmp(executor, jump_offset)); self->read_index += 2; break; } case AMAL_OP_RET: - /* return_if_error(asm_ret(&self->asm, 0)); */ - assert(bool_false && "TODO: Implement RET. RET needs to restore the stack before returning"); + return_if_error(amal_exec_ret(executor)); break; case AMAL_OP_FUNC_START: { + u16 func_num_registers; assert(!inside_func); inside_func = bool_true; am_memcpy(&func_num_registers, &self->data.data[self->read_index], sizeof(func_num_registers)); - /* - 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 - */ - return_if_error(asm_pushr(&self->asm, RBX)); - return_if_error(asm_pushr(&self->asm, RBP)); - return_if_error(asm_mov_rr(&self->asm, RBP, RSP)); - return_if_error(asm_sub_rm64_imm(&self->asm, RSP, func_num_registers * sizeof(usize))); + return_if_error(amal_exec_func_start(executor, func_num_registers)); self->read_index += 2; break; } case AMAL_OP_FUNC_END: { assert(inside_func); inside_func = bool_false; - /*assert(bool_false && "TODO: Implement FUNC_END");*/ /* TODO: Validate FUNC_END is called for every FUNC_START, otherwise stack will be corrupted */ - /* TODO: Use mov_rr(RSP, RBP) instead? why doesn't gcc do this? */ - return_if_error(asm_mov_rr(&self->asm, RSP, RBP)); - return_if_error(asm_popr(&self->asm, RBP)); - return_if_error(asm_popr(&self->asm, RBX)); - return_if_error(asm_ret(&self->asm, 0)); + return_if_error(amal_exec_func_end(executor)); break; } } @@ -561,13 +387,22 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self) { } int amal_program_run(amal_program *self) { - return_if_error(amal_program_read_header(self)); + int result; + amal_executor *executor; + result = 0; + return_if_error(amal_executor_init(&executor)); + + cleanup_if_error(amal_program_read_header(self)); while(bytes_left_to_read(self) > 0) { - return_if_error(amal_program_read_intermediates(self)); - return_if_error(amal_program_read_strings(self)); - return_if_error(amal_program_read_instructions(self)); + cleanup_if_error(amal_program_read_intermediates(self)); + cleanup_if_error(amal_program_read_strings(self)); + cleanup_if_error(amal_program_read_instructions(self, executor)); } - return asm_execute(&self->asm); + result = amal_executor_run(executor); + + cleanup: + amal_executor_deinit(executor); + return result; } int amal_program_save(amal_program *self, const char *filepath) { |