aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-08-14 01:30:08 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-25 14:36:46 +0200
commit664fbc5f5c947aaa04bbbf132d9c935959e34a9c (patch)
treefb25c4d6b8ccc5c6c7d02ad1170947096ff684e9 /src
parentea97370f973374f863e4296c2bb872be8b5235a3 (diff)
Move program code generation and execution out of program (make it generic)
Diffstat (limited to 'src')
-rw-r--r--src/program.c251
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(&reg1, RBP, -(i32)get_register_at_offset(1));
- asm_ptr_init_disp(&reg2, RBP, -(i32)get_register_at_offset(2));
-
- return_if_error(asm_mov_rm(&self->asm, RAX, &reg1));
- return_if_error(asm_mov_rm(&self->asm, RCX, &reg2));
- 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(&reg1, RBP, -(i32)get_register_at_offset(1));
- asm_ptr_init_disp(&reg2, RBP, -(i32)get_register_at_offset(2));
-
- return_if_error(asm_mov_rm(&self->asm, RAX, &reg1));
- return_if_error(asm_mov_rm(&self->asm, RCX, &reg2));
- 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(&reg1, RBP, -(i32)get_register_at_offset(1));
- asm_ptr_init_disp(&reg2, RBP, -(i32)get_register_at_offset(2));
-
- return_if_error(asm_mov_rm(&self->asm, RAX, &reg1));
- return_if_error(asm_mov_rm(&self->asm, RCX, &reg2));
- 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(&reg1, RBP, -(i32)get_register_at_offset(1));
- asm_ptr_init_disp(&reg2, RBP, -(i32)get_register_at_offset(2));
-
- return_if_error(asm_mov_rm(&self->asm, RAX, &reg1));
- return_if_error(asm_mov_rm(&self->asm, RCX, &reg2));
- 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(&reg, 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, &reg));
- #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) {