diff options
Diffstat (limited to 'src/program.c')
-rw-r--r-- | src/program.c | 257 |
1 files changed, 253 insertions, 4 deletions
diff --git a/src/program.c b/src/program.c index aa39a4c..167f4c4 100644 --- a/src/program.c +++ b/src/program.c @@ -1,23 +1,272 @@ #include "../include/program.h" +#include "../include/std/mem.h" +#include "../include/std/alloc.h" +#include "../include/std/log.h" #include <stdio.h> #include <errno.h> +#include <assert.h> -void amal_program_init(amal_program *self) { +/* TODO: If system is big-endian, then do endian conversion for all reads */ + +/* This matches SsaNumberType */ +typedef enum { + NUMBER_TYPE_INTEGER, + NUMBER_TYPE_FLOAT +} NumberType; + +typedef union { + i64 integer; + f64 floating; +} NumberUnion; + +int amal_program_init(amal_program *self) { ignore_result_int(buffer_init(&self->data, NULL)); + ignore_result_int(buffer_init(&self->string_indices, NULL)); + self->intermediates_start = NULL; + self->strings_start = NULL; + self->read_index = 0; + + /*doc(Bytecode header) + # Header layout + |Size|Name |Description | + |----|-------------|----------------------------------------------------------------------------| + |4 |Magic number |The magic number used to identify an amalgam bytecode file. | + |1 |Major version|The major version of the bytecode. Updates in this is a breaking change. | + |1 |Minor version|The minor version of the bytecode. Updates in this are backwards compatible.| + |1 |Patch version|The patch version of the bytecode. Updates in this are only minor bug fixes.| + The versions in the header only changes for every release, not every change. + */ + + const u32 magic_number = AMAL_PROGRAM_MAGIC_NUMBER; + const u8 major_version = AMAL_PROGRAM_MAJOR_VERSION; + const u8 minor_version = AMAL_PROGRAM_MINOR_VERSION; + const u8 patch_version = AMAL_PROGRAM_PATCH_VERSION; + + return_if_error(buffer_append(&self->data, &magic_number, 4)); + return_if_error(buffer_append(&self->data, &major_version, 1)); + return_if_error(buffer_append(&self->data, &minor_version, 1)); + return_if_error(buffer_append(&self->data, &patch_version, 1)); + + return 0; } void amal_program_deinit(amal_program *self) { buffer_deinit(&self->data); + buffer_deinit(&self->string_indices); } int amal_program_append_bytecode(amal_program *self, Bytecode *bytecode) { return buffer_append(&self->data, bytecode->data.data, bytecode->data.size); } +static usize bytes_left_to_read(amal_program *self) { + assert(self->read_index <= self->data.size); + return self->data.size - self->read_index; +} + +static CHECK_RESULT int amal_program_read_header(amal_program *self) { + u32 magic_number; + u8 major_version; + u8 minor_version; + u8 patch_version; + + if(bytes_left_to_read(self) < sizeof(u32) + sizeof(u8) * 3) + return AMAL_PROGRAM_INVALID_HEADER; + + am_memcpy(&magic_number, &self->data.data[self->read_index], sizeof(magic_number)); + self->read_index += sizeof(u32); + am_memcpy(&major_version, &self->data.data[self->read_index], sizeof(major_version)); + self->read_index += sizeof(u8); + am_memcpy(&minor_version, &self->data.data[self->read_index], sizeof(minor_version)); + self->read_index += sizeof(u8); + am_memcpy(&patch_version, &self->data.data[self->read_index], sizeof(patch_version)); + self->read_index += sizeof(u8); + + if(magic_number != AMAL_PROGRAM_MAGIC_NUMBER) + return AMAL_PROGRAM_INVALID_MAGIC_NUMBER; + + /* + A program is only incompatible if the major version is newer than the version that is used to run it. + TODO: Implement backwards compatible reads, starting from when the program bytecode breaks backwards compatibility + */ + if(major_version > AMAL_PROGRAM_MAJOR_VERSION) + return AMAL_PROGRAM_INCOMPATIBLE; + + return AMAL_PROGRAM_OK; +} + +static CHECK_RESULT int amal_program_read_intermediates(amal_program *self) { + u32 intermediates_size; + /*u32 read_end;*/ + + if(bytes_left_to_read(self) < sizeof(intermediates_size)) { + amal_log_error("Not enough space in program to intermediates size"); + return AMAL_PROGRAM_INVALID_INTERMEDIATES; + } + + am_memcpy(&intermediates_size, &self->data.data[self->read_index], sizeof(intermediates_size)); + self->read_index += sizeof(intermediates_size); + + if(bytes_left_to_read(self) < intermediates_size) { + amal_log_error("Not enough space in program to read all intermediates"); + return AMAL_PROGRAM_INVALID_INTERMEDIATES_SIZE; + } + + self->intermediates_start = &self->data.data[self->read_index]; + /* + read_end = self->read_index + intermediates_size; + while(self->read_index < read_end) { + NumberType type; + NumberUnion value; + am_memcpy(&type, &self->data.data[self->read_index], sizeof(u8)); + am_memcpy(&value, &self->data.data[self->read_index + sizeof(u8)], sizeof(u64)); + self->read_index += sizeof(u8) + sizeof(u64); + } + */ + self->read_index += intermediates_size; + + return AMAL_PROGRAM_OK; +} + +static CHECK_RESULT int amal_program_read_strings(amal_program *self) { + u16 num_strings; + u32 strings_size; + u32 read_start; + u32 read_end; + u32 *string_index_ptr; + + if(bytes_left_to_read(self) < sizeof(num_strings)) + return AMAL_PROGRAM_INVALID_STRINGS; + + am_memcpy(&num_strings, &self->data.data[self->read_index], sizeof(num_strings)); + self->read_index += sizeof(num_strings); + + if(buffer_append_empty(&self->string_indices, num_strings) != 0) + return AMAL_PROGRAM_STRING_ALLOC_FAILURE; + string_index_ptr = (u32*)self->string_indices.data; + + if(bytes_left_to_read(self) < sizeof(strings_size)) + return AMAL_PROGRAM_INVALID_STRINGS; + + am_memcpy(&strings_size, &self->data.data[self->read_index], sizeof(strings_size)); + self->read_index += sizeof(strings_size); + + if(bytes_left_to_read(self) < strings_size) + return AMAL_PROGRAM_INVALID_STRINGS_SIZE; + + read_start = self->read_index; + read_end = read_start + strings_size; + self->strings_start = &self->data.data[self->read_index]; + while(self->read_index < read_end) { + u16 string_size; + + if(bytes_left_to_read(self) < sizeof(string_size)) + return AMAL_PROGRAM_INVALID_STRINGS; + + *string_index_ptr = self->read_index - read_start; + ++string_index_ptr; + am_memcpy(&string_size, &self->data.data[self->read_index], sizeof(string_size)); + self->read_index += sizeof(string_size); + + if(bytes_left_to_read(self) < string_size) + return AMAL_PROGRAM_INVALID_STRINGS; + + self->read_index += string_size; + } + + assert(self->read_index == read_end); + return AMAL_PROGRAM_OK; +} + +static CHECK_RESULT int amal_program_read_instructions(amal_program *self) { + u32 instructions_size; + u32 read_end; + + if(bytes_left_to_read(self) < sizeof(instructions_size)) + return AMAL_PROGRAM_INVALID_INSTRUCTIONS_SIZE; + + am_memcpy(&instructions_size, &self->data.data[self->read_index], sizeof(instructions_size)); + self->read_index += sizeof(instructions_size); + + if(bytes_left_to_read(self) < instructions_size) + return AMAL_PROGRAM_INVALID_INSTRUCTIONS_SIZE; + + read_end = self->read_index + instructions_size; + while(self->read_index < read_end) { + AmalOpcode opcode; + opcode = self->data.data[self->read_index]; + self->read_index += sizeof(AmalOpcodeType); + switch(opcode) { + case AMAL_OP_NOP: + break; + case AMAL_OP_SETZ: + self->read_index += 1; + break; + case AMAL_OP_MOV: + self->read_index += 2; + break; + case AMAL_OP_MOVI: + self->read_index += 3; + break; + case AMAL_OP_MOVD: + self->read_index += 3; + break; + case AMAL_OP_ADD: + self->read_index += 3; + break; + case AMAL_OP_SUB: + self->read_index += 3; + break; + case AMAL_OP_MUL: + self->read_index += 3; + break; + case AMAL_OP_DIV: + self->read_index += 3; + break; + case AMAL_OP_PUSH: + self->read_index += 1; + break; + case AMAL_OP_PUSHI: + self->read_index += 2; + break; + case AMAL_OP_PUSHD: + self->read_index += 2; + break; + case AMAL_OP_CALL: + self->read_index += 2; + break; + case AMAL_OP_CALLR: + self->read_index += 1; + break; + case AMAL_OP_CMP: + self->read_index += 3; + break; + case AMAL_OP_JZ: + self->read_index += 3; + break; + case AMAL_OP_JMP: + self->read_index += 2; + break; + case AMAL_OP_RET: + break; + case AMAL_OP_FUNC_START: + break; + case AMAL_OP_FUNC_END: + break; + } + } + + return AMAL_PROGRAM_OK; +} + int amal_program_run(amal_program *self) { - /* TODO: Implement */ - (void)self; - return 0; + return_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)); + } + return AMAL_PROGRAM_OK; } int amal_program_save(amal_program *self, const char *filepath) { |