aboutsummaryrefslogtreecommitdiff
path: root/src/program.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/program.c')
-rw-r--r--src/program.c135
1 files changed, 84 insertions, 51 deletions
diff --git a/src/program.c b/src/program.c
index 082f9fd..8a17ac9 100644
--- a/src/program.c
+++ b/src/program.c
@@ -26,52 +26,26 @@ typedef struct {
NumberUnion value;
} Number;
-/*doc(Bytecode)
-The layout of the full bytecode is: Header (Intermediates Strings Functions External_Functions Instructions)*
-*/
-
-static CHECK_RESULT int amal_program_append_header(amal_program *self) {
- /*doc(Bytecode header)
- # Header layout
- |Type|Field |Description |
- |----|-------------|----------------------------------------------------------------------------|
- |u32 |Magic number |The magic number used to identify an amalgam bytecode file. |
- |u8 |Major version|The major version of the bytecode. Updates in this is a breaking change. |
- |u8 |Minor version|The minor version of the bytecode. Updates in this are backwards compatible.|
- |u8 |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;
-}
-
int amal_program_init(amal_program *self) {
ignore_result_int(buffer_init(&self->data, NULL));
- self->string_indices = NULL;
- self->extern_func_indices = NULL;
- self->intermediates_start = NULL;
- self->strings_start = NULL;
- self->extern_funcs_start = NULL;
- self->read_index = 0;
- self->num_intermediates = 0;
- self->num_strings = 0;
- self->num_functions = 0;
- self->num_extern_functions = 0;
+ self->string_indices = NULL;
+ self->extern_func_indices = NULL;
+ self->intermediates_start = NULL;
+ self->strings_start = NULL;
+ self->extern_funcs_start = NULL;
+ self->exported_funcs = NULL;
+ self->exported_funcs_end = NULL;
+ self->read_index = 0;
+ self->main_func_instruction_offset = ~0U;
+ self->num_intermediates = 0;
+ self->num_strings = 0;
+ self->num_functions = 0;
+ self->num_extern_functions = 0;
+ self->num_exported_functions = 0;
cleanup_if_error(arena_allocator_init(&self->allocator));
cleanup_if_error(hash_map_init(&self->extern_funcs_map, &self->allocator, sizeof(ProgramExternFunc), hash_map_compare_string, amal_hash_string));
- cleanup_if_error(amal_program_append_header(self));
+ cleanup_if_error(buffer_append_header(&self->data));
return 0;
cleanup:
@@ -131,6 +105,36 @@ static CHECK_RESULT int amal_program_get_extern_func_by_index(amal_program *self
return 0;
}
+static CHECK_RESULT int amal_program_set_exported_function_instruction_offset_advance(amal_program *self, u32 instruction_offset) {
+ if(self->exported_funcs >= self->exported_funcs_end) {
+ amal_log_error("The number of exported functions in the instructions is more than the number of exported instructions in the header");
+ return AMAL_PROGRAM_INSTRUCTION_INVALID_EXPORTED_FUNC_INDEX;
+ }
+
+ {
+ u8 num_args;
+ u8 func_name_size;
+
+ if((usize)(self->exported_funcs_end - self->exported_funcs) < sizeof(instruction_offset) + sizeof(num_args) + sizeof(func_name_size))
+ return AMAL_PROGRAM_INSTRUCTION_INVALID_EXPORTED_FUNC_INDEX;
+
+ am_memcpy(self->exported_funcs, &instruction_offset, sizeof(instruction_offset));
+ num_args = self->exported_funcs[sizeof(instruction_offset)];
+ func_name_size = self->exported_funcs[sizeof(instruction_offset) + sizeof(num_args)];
+ self->exported_funcs += sizeof(instruction_offset) + sizeof(num_args) + sizeof(func_name_size);
+ if(self->main_func_instruction_offset == ~0U && am_memeql(self->exported_funcs, "main", 4))
+ self->main_func_instruction_offset = instruction_offset;
+
+ /* +1 to skip null-termination character */
+ if((usize)(self->exported_funcs_end - self->exported_funcs) < func_name_size + 1U)
+ return AMAL_PROGRAM_INSTRUCTION_INVALID_EXPORTED_FUNC_INDEX;
+
+ self->exported_funcs += func_name_size + 1; /* +1 to skip null-termination character */
+ }
+
+ return 0;
+}
+
int amal_program_append_bytecode(amal_program *self, Bytecode *bytecode) {
return buffer_append(&self->data, bytecode->data.data, bytecode->data.size);
}
@@ -158,14 +162,14 @@ static CHECK_RESULT int amal_program_read_header(amal_program *self) {
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)
+ if(magic_number != AMAL_BYTECODE_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)
+ if(major_version > AMAL_BYTECODE_MAJOR_VERSION)
return AMAL_PROGRAM_INCOMPATIBLE;
return AMAL_PROGRAM_OK;
@@ -237,7 +241,7 @@ static CHECK_RESULT int amal_program_read_strings(amal_program *self) {
am_memcpy(&string_size, &self->data.data[self->read_index], sizeof(string_size));
self->read_index += sizeof(string_size);
- /* +1 to skip null-termination character */
+ /* +1 to skip null-termination character */
if(bytes_left_to_read(self) < string_size + 1U)
return AMAL_PROGRAM_INVALID_STRINGS;
@@ -291,9 +295,9 @@ static CHECK_RESULT int amal_program_read_external_functions(amal_program *self)
func_name_size = self->data.data[self->read_index + sizeof(num_args)];
self->read_index += sizeof(num_args) + sizeof(func_name_size);
- /* +1 to skip null-termination character */
+ /* +1 to skip null-termination character */
if(bytes_left_to_read(self) < func_name_size + 1U)
- return AMAL_PROGRAM_INVALID_STRINGS;
+ return AMAL_PROGRAM_INVALID_EXTERNAL_FUNCTIONS;
self->read_index += func_name_size + 1; /* +1 to skip null-termination character */
}
@@ -303,6 +307,28 @@ static CHECK_RESULT int amal_program_read_external_functions(amal_program *self)
return AMAL_PROGRAM_OK;
}
+static CHECK_RESULT int amal_program_read_exported_functions(amal_program *self) {
+ u32 export_funcs_size;
+
+ if(!amal_program_read_advance(self, &self->num_exported_functions, sizeof(u16)))
+ return AMAL_PROGRAM_INVALID_EXPORTED_FUNCTIONS;
+
+ if(!amal_program_read_advance(self, &export_funcs_size, sizeof(export_funcs_size)))
+ return AMAL_PROGRAM_INVALID_EXPORTED_FUNCTIONS;
+
+ if(bytes_left_to_read(self) < export_funcs_size)
+ return AMAL_PROGRAM_INVALID_EXPORTED_FUNCTIONS_SIZE;
+
+ /*
+ Exported functions doesn't need list of indices to the data, since exported functions
+ are always sorted in the instructions in the same order as list of exported functions
+ */
+ self->exported_funcs = (u8*)(self->data.data + self->read_index);
+ self->exported_funcs_end = self->exported_funcs + export_funcs_size;
+ self->read_index += export_funcs_size;
+ return AMAL_PROGRAM_OK;
+}
+
static CHECK_RESULT int amal_program_get_intermediate_by_index(amal_program *self, u16 index, Number *result) {
if(index >= self->num_intermediates)
return AMAL_PROGRAM_INSTRUCTION_INVALID_INTERMEDIATE_INDEX;
@@ -507,7 +533,7 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
break;
}
case AMAL_OP_FUNC_START: {
- u8 func_num_param_regs;
+ u8 func_flags;
u16 func_num_local_var_regs;
assert(!inside_func);
@@ -515,9 +541,10 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
assert(func_counter < self->num_functions);
++func_counter;
- func_num_param_regs = self->data.data[self->read_index];
- (void)func_num_param_regs;
- am_memcpy(&func_num_local_var_regs, self->data.data + self->read_index + sizeof(func_num_param_regs), sizeof(func_num_local_var_regs));
+ func_flags = self->data.data[self->read_index];
+ am_memcpy(&func_num_local_var_regs, self->data.data + self->read_index + sizeof(func_flags), sizeof(func_num_local_var_regs));
+ if(func_flags & FUNC_FLAG_EXPORTED)
+ return_if_error(amal_program_set_exported_function_instruction_offset_advance(self, amal_exec_get_code_offset(executor)));
return_if_error(amal_exec_func_start(executor, func_num_local_var_regs));
self->read_index += 3;
break;
@@ -549,9 +576,15 @@ int amal_program_run(amal_program *self) {
cleanup_if_error(amal_program_read_strings(self));
cleanup_if_error(amal_program_read_functions(self));
cleanup_if_error(amal_program_read_external_functions(self));
+ cleanup_if_error(amal_program_read_exported_functions(self));
cleanup_if_error(amal_program_read_instructions(self, executor));
}
- result = amal_executor_run(executor);
+ if(self->main_func_instruction_offset == ~0U) {
+ amal_log_error("The program is missing a main function");
+ result = AMAL_PROGRAM_NO_MAIN_FUNC;
+ goto cleanup;
+ }
+ result = amal_executor_run(executor, self->main_func_instruction_offset);
cleanup:
amal_executor_deinit(executor);