aboutsummaryrefslogtreecommitdiff
path: root/src/program.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/program.c')
-rw-r--r--src/program.c257
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) {