aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild.sh7
-rw-r--r--executor/x86_64/asm.c11
-rw-r--r--executor/x86_64/executor.c14
-rw-r--r--include/bytecode/bytecode.h20
-rw-r--r--include/program.h3
-rw-r--r--include/std/buffer_view.h1
-rw-r--r--src/ast.c5
-rw-r--r--src/bytecode/bytecode.c48
-rw-r--r--src/compiler.c11
-rw-r--r--src/parser.c2
-rw-r--r--src/program.c162
-rw-r--r--src/std/arena_allocator.c5
-rw-r--r--src/std/buffer.c8
-rw-r--r--src/std/buffer_view.c8
-rw-r--r--src/tokenizer.c11
-rw-r--r--tests/glfw.amal9
-rw-r--r--tests/main.c102
17 files changed, 278 insertions, 149 deletions
diff --git a/build.sh b/build.sh
index 568c6c4..415fac5 100755
--- a/build.sh
+++ b/build.sh
@@ -70,10 +70,9 @@ build_test() {
set +x
source_files_test=$(find "tests" -name "*.c")
- if [ -z "$NO_TEST" ]; then
- set -x
- time $CC $source_files_test $CFLAGS $LIBS -o test "./libamalgam.so"
- fi
+ set -x
+ time $CC $source_files_test $CFLAGS $LIBS -o test "./libamalgam.so" $(pkg-config --cflags --libs glfw3 glew)
+ set +x
build_compile_commands $source_files $source_files_test
}
diff --git a/executor/x86_64/asm.c b/executor/x86_64/asm.c
index e29130e..c633db8 100644
--- a/executor/x86_64/asm.c
+++ b/executor/x86_64/asm.c
@@ -210,16 +210,21 @@ static void asm_print_code_hex(Asm *self) {
}
#endif
+typedef union {
+ u8 *data;
+ int (*func)(void);
+} RawFuncCallPtr;
+
int asm_execute(Asm *self, u32 offset) {
- void (*func)();
+ RawFuncCallPtr raw_func_ptr;
if(mprotect(self->code, self->allocated_size, PROT_READ | PROT_EXEC) != 0)
return -errno;
/*asm_print_code_hex(self);*/
/* TODO: Verify if this is valid on all platforms. According to ISO C standard it isn't? */
- *(void**)(&func) = (u8*)self->code + offset;
- func();
+ raw_func_ptr.data = (u8*)self->code + offset;
+ raw_func_ptr.func();
return 0;
}
diff --git a/executor/x86_64/executor.c b/executor/x86_64/executor.c
index c442da8..f747e4a 100644
--- a/executor/x86_64/executor.c
+++ b/executor/x86_64/executor.c
@@ -284,6 +284,7 @@ int amal_exec_call(amal_executor *self, u32 code_offset, u8 num_args, i8 dst_reg
isize asm_offset = asm_get_size(&impl->asm);
ASM_ENSURE_CAPACITY
+ assert(num_args % 2 == 0 && "TODO: Align stack to 16-bytes before calling functions");
assert(code_offset < asm_offset);
asm_call_rel32(&impl->asm, (isize)code_offset - asm_offset);
@@ -318,7 +319,8 @@ int amal_exec_calle(amal_executor *self, void *func, u8 num_args, i8 dst_reg) {
AsmPtr dst;
IMPL_START
- /* TODO: Support R and XMM registers so more than 5 arguments can be used for functions */
+ assert(num_args % 2 == 0 && "TODO: Align stack to 16-bytes before calling functions");
+ /* TODO: Support R and XMM registers so more than 4 arguments can be used for functions */
assert(num_args < 5);
{
/*
@@ -427,6 +429,10 @@ int amal_exec_ret(amal_executor *self, i8 reg) {
return amal_exec_func_end(self);
}
+static u32 get_next_uneven_number(u32 value) {
+ return value + !(value & 1);
+}
+
int amal_exec_func_start(amal_executor *self, u16 num_regs) {
/*
TODO: Validate stack size, or maybe remove all validation? do we really need validation?
@@ -443,7 +449,11 @@ int amal_exec_func_start(amal_executor *self, u16 num_regs) {
asm_pushr(&impl->asm, RBX);
asm_pushr(&impl->asm, RBP);
asm_mov_rr(&impl->asm, RBP, RSP);
- asm_sub_rm64_imm(&impl->asm, RSP, num_regs * sizeof(isize));
+ /*
+ Functions are entered with a stack alignment of 8 (because of call return address is pushed to stack).
+ Make sure to align to to next 16-byte even if the extra bytes are not used.
+ */
+ asm_sub_rm64_imm(&impl->asm, RSP, get_next_uneven_number(num_regs) * sizeof(isize));
return 0;
}
diff --git a/include/bytecode/bytecode.h b/include/bytecode/bytecode.h
index c495d7a..a93fe4f 100644
--- a/include/bytecode/bytecode.h
+++ b/include/bytecode/bytecode.h
@@ -8,8 +8,8 @@
#include <setjmp.h>
-/*doc(Opcode)
- Variable length opcodes. Sizes range from 1 to 5 bytes.
+/*doc(Instructions)
+ Variable length instructions. Instruction size ranges from 1 to 5 bytes.
# Instruction formats
Instructions can be in 7 different formats:
1. 1 byte: Opcode(u8)
@@ -25,7 +25,8 @@
6.1 Opcode(u8) + register(i8) + label(i16)\
6.2 Opcode(u8) + register(i8) + intermediate(u16)\
6.3 Opcode(u8) + register(i8) + data(u16)\
- 6.4 Opcode(u8) + flags(u8) + num_local_var_reg(u16)
+ 6.4 Opcode(u8) + flags(u8) + num_local_var_reg(u16)\
+ 6.5 Opcode(u8) + stack_offset(i24)
7. 5 bytes: Opcode(u8) + index(u8) + index(u16) + num_args(u8)
# Registers
Registers have a range of 128. Local variables start from register 0 and increment while parameters start from -1
@@ -96,6 +97,19 @@ typedef struct {
/* TODO: Make sure this pragma pack works on all platforms */
#pragma pack(push, 1)
typedef struct {
+ u8 num_params;
+ u32 params_num_pointers;
+ u32 params_fixed_size;
+
+ u8 num_return_types;
+ u32 return_types_num_pointers;
+ u32 return_types_fixed_size;
+} BytecodeHeaderExternFunction;
+#pragma pack(pop)
+
+/* TODO: Make sure this pragma pack works on all platforms */
+#pragma pack(push, 1)
+typedef struct {
u32 function_index;
#define parser_index function_index
u32 extern_function_index;
diff --git a/include/program.h b/include/program.h
index b398a3a..aa318d9 100644
--- a/include/program.h
+++ b/include/program.h
@@ -50,7 +50,6 @@ typedef struct {
typedef struct {
Buffer/*<...>*/ data;
u32 *string_indices;
- u32 *extern_func_indices;
u8 *intermediates_start; /* Reference inside @data */
u8 *strings_start; /* Reference inside @data */
u8 *funcs_start; /* Reference inside @data */
@@ -84,7 +83,7 @@ void amal_program_deinit(amal_program *self);
returns @AMAL_PROGRAM_EXTERN_FUNC_ALREADY_EXISTS if a function with the name @name already exists
in the program
*/
-CHECK_RESULT int amal_program_add_extern_func(amal_program *self, BufferView name, void *func_ptr, int args_byte_size);
+CHECK_RESULT int amal_program_register_extern_func(amal_program *self, BufferView name, void *func_ptr, int args_byte_size);
CHECK_RESULT int amal_program_append_bytecode(amal_program *self, Bytecode *bytecode);
CHECK_RESULT int amal_program_run(amal_program *self);
diff --git a/include/std/buffer_view.h b/include/std/buffer_view.h
index 9c0a722..a54f616 100644
--- a/include/std/buffer_view.h
+++ b/include/std/buffer_view.h
@@ -10,6 +10,7 @@ typedef struct {
BufferView create_buffer_view_null(void);
BufferView create_buffer_view(const char *data, usize size);
+BufferView create_buffer_view_auto(const char *data);
bool buffer_view_equals(const BufferView *self, const BufferView *other);
#endif
diff --git a/src/ast.c b/src/ast.c
index 912b9c7..8e102ee 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -560,6 +560,9 @@ static void lhsexpr_resolve_rhs(LhsExpr *self, AstCompilerContext *context, AstR
if(ast_is_decl(self->rhs_expr)) {
result->type = RESOLVED_TYPE_LHS_EXPR;
result->value.lhs_expr = self;
+ /* Structs resolved type becomes the lhs while functions resolved type becomes the function signature they own */
+ if (self->rhs_expr->type == AST_STRUCT_DECL)
+ self->rhs_expr->resolve_data.type = *result;
} else {
*result = self->rhs_expr->resolve_data.type;
}
@@ -753,6 +756,7 @@ static TypeSize variable_type_get_byte_size(VariableType *self) {
type_size.fixed_size = 0;
switch(self->type) {
case VARIABLE_TYPE_NONE:
+ assert(bool_false && "Variable type not resolved!");
break;
case VARIABLE_TYPE_VARIABLE:
type_size = resolved_type_get_byte_size(&self->value.variable->resolved_var.resolve_data->type);
@@ -943,6 +947,7 @@ TypeSize resolved_type_get_byte_size(AstResolvedType *self) {
type_size.fixed_size = 0;
switch(self->type) {
case RESOLVED_TYPE_NONE:
+ assert(bool_false && "Type not resolved!");
break;
case RESOLVED_TYPE_LHS_EXPR: {
/* Resolved type until rhs is StructDecl or FunctionSignature */
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c
index 2c43471..c968743 100644
--- a/src/bytecode/bytecode.c
+++ b/src/bytecode/bytecode.c
@@ -155,9 +155,9 @@ static TypeSize function_signature_get_return_types_size(FunctionSignature *self
return_types_total_size.num_pointers = 0;
return_types_total_size.fixed_size = 0;
for(; return_type != return_type_end; ++return_type) {
- TypeSize param_size = resolved_type_get_byte_size(&return_type->resolved_type);
- return_types_total_size.num_pointers += param_size.num_pointers;
- return_types_total_size.fixed_size += param_size.fixed_size;
+ TypeSize return_size = resolved_type_get_byte_size(&return_type->resolved_type);
+ return_types_total_size.num_pointers += return_size.num_pointers;
+ return_types_total_size.fixed_size += return_size.fixed_size;
}
return return_types_total_size;
}
@@ -187,7 +187,7 @@ static void add_functions(BytecodeCompilerContext *self) {
Buffer *instructions = &self->bytecode->data;
SsaFunc *func = buffer_begin(&ssa->funcs);
SsaFunc *func_end = buffer_end(&ssa->funcs);
- u32 funcs_size = ssa->func_counter * sizeof(BytecodeHeaderFunction);
+ u32 funcs_size = (u32)ssa->func_counter * sizeof(BytecodeHeaderFunction);
assert(sizeof(BytecodeHeaderFunction) == 22);
self->bytecode->funcs_index = instructions->size;
@@ -224,20 +224,26 @@ static void add_extern_functions(BytecodeCompilerContext *self) {
|External function[]|External functions|Multiple external functions, where the number of functions is defined by @num_extern_func|
# External function
- |Type|Field |Description |
- |----|----------|-----------------------------------------------------------------------------------------------------|
- |u8 |num_params|The number of parameters the functions has. |
- |u8 |name_len |The length of the external function name, in bytes. Excluding the null-terminate character. |
- |u8[]|name |The name of the external function, where the size is defined by @name_len. Names are null-terminated.|
+ |Type|Field |Description |
+ |----|-------------------------|-----------------------------------------------------------------------------------------------------|
+ |u8 |num_params |The number of parameters. |
+ |u32 |params_num_pointers |The number of pointers in the parameters. |
+ |u32 |params_fixed_size |The size of all non-pointer type parameters, in bytes. |
+ |u8 |num_return_types |The number of return values. |
+ |u32 |return_types_num_pointers|The number of pointers in the return types. |
+ |u32 |return_types_fixed_size |The size of all non-pointer type return types, in bytes. |
+ |u8 |name_len |The length of the external function name, in bytes. Excluding the null-terminate character. |
+ |u8[]|name |The name of the external function, where the size is defined by @name_len. Names are null-terminated.|
*/
Ssa *ssa = self->parser->ssa;
Buffer *instructions = &self->bytecode->data;
SsaExternFunc *extern_func = buffer_begin(&ssa->extern_funcs);
SsaExternFunc *extern_func_end = buffer_end(&ssa->extern_funcs);
- u32 extern_funcs_size = 0;
+ u32 extern_funcs_size = (u32)ssa->extern_func_counter * (sizeof(BytecodeHeaderExternFunction) + sizeof(u8));
+ assert(sizeof(BytecodeHeaderExternFunction) == 18);
for(; extern_func != extern_func_end; ++extern_func) {
- extern_funcs_size += sizeof(u8) + sizeof(u8) + extern_func->name.size + 1; /* +1 for null-termination of string */
+ extern_funcs_size += extern_func->name.size + 1; /* +1 for null-termination of string */
}
extern_func = buffer_begin(&ssa->extern_funcs);
@@ -247,8 +253,19 @@ static void add_extern_functions(BytecodeCompilerContext *self) {
throw_if_error(buffer_append(instructions, &extern_funcs_size, sizeof(u32)));
for(; extern_func != extern_func_end; ++extern_func) {
const char null_s = '\0';
- u8 num_params = buffer_get_size(&extern_func->func_sig->parameters, FunctionParameter);
- throw_if_error(buffer_append(instructions, &num_params, sizeof(num_params)));
+ TypeSize params_total_size = function_signature_get_params_size(extern_func->func_sig);
+ TypeSize return_types_total_size = function_signature_get_return_types_size(extern_func->func_sig);
+ BytecodeHeaderExternFunction header_func;
+
+ header_func.num_params = buffer_get_size(&extern_func->func_sig->parameters, FunctionParameter);
+ header_func.params_num_pointers = params_total_size.num_pointers;
+ header_func.params_fixed_size = params_total_size.fixed_size;
+
+ header_func.num_return_types = buffer_get_size(&extern_func->func_sig->return_types, FunctionReturnType);
+ header_func.return_types_num_pointers = return_types_total_size.num_pointers;
+ header_func.return_types_fixed_size = return_types_total_size.fixed_size;
+ throw_if_error(buffer_append(instructions, &header_func, sizeof(header_func)));
+
/* TODO: Add namespace to the function name */
/* u8 is fine, because the max length of a variable is 255 */
throw_if_error(buffer_append(instructions, &extern_func->name.size, sizeof(u8)));
@@ -280,10 +297,10 @@ static void add_export_functions(BytecodeCompilerContext *self) {
Buffer *instructions = &self->bytecode->data;
SsaExportFunc *export_func = buffer_begin(&ssa->export_funcs);
SsaExportFunc *export_func_end = buffer_end(&ssa->export_funcs);
- u32 export_funcs_size = 0;
+ u32 export_funcs_size = (u32)ssa->export_func_counter * (sizeof(u32) + sizeof(u8) + sizeof(u8));
for(; export_func != export_func_end; ++export_func) {
- export_funcs_size += sizeof(u32) + sizeof(u8) + sizeof(u8) + export_func->name.size + 1; /* +1 for null-termination of string */
+ export_funcs_size += export_func->name.size + 1; /* +1 for null-termination of string */
}
export_func = buffer_begin(&ssa->export_funcs);
@@ -452,7 +469,6 @@ static void add_instructions(BytecodeCompilerContext *self) {
u32 num_instructions_index = self->bytecode->data.size;
throw_if_error(buffer_append_empty(&self->bytecode->data, sizeof(num_instructions_index)));
- /* TODO: Keep all registers under 256 */
while(instruction != instructions_end) {
SsaInstruction ins = (SsaInstruction)*instruction++;
switch(ins) {
diff --git a/src/compiler.c b/src/compiler.c
index 8dda1c6..6e6bc4b 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -44,6 +44,7 @@ static CHECK_RESULT int create_default_type(amal_compiler *compiler, const char
expr->resolve_data.type.type = RESOLVED_TYPE_LHS_EXPR;
expr->resolve_data.type.value.lhs_expr = lhs_expr;
expr->resolve_data.status = AST_RESOLVED;
+ lhs_expr->rhs_expr->resolve_data = expr->resolve_data;
return scope_add_child(&compiler->root_scope, expr);
}
@@ -58,12 +59,12 @@ static CHECK_RESULT int create_default_type_fixed_size(amal_compiler *compiler,
static CHECK_RESULT int init_default_types(amal_compiler *compiler) {
return_if_error(create_default_type_fixed_size(compiler, "i8", 1, &compiler->default_types.i8));
return_if_error(create_default_type_fixed_size(compiler, "i16", 2, &compiler->default_types.i16));
- return_if_error(create_default_type_fixed_size(compiler, "i32", 3, &compiler->default_types.i32));
- return_if_error(create_default_type_fixed_size(compiler, "i64", 4, &compiler->default_types.i64));
+ return_if_error(create_default_type_fixed_size(compiler, "i32", 4, &compiler->default_types.i32));
+ return_if_error(create_default_type_fixed_size(compiler, "i64", 8, &compiler->default_types.i64));
return_if_error(create_default_type_fixed_size(compiler, "u8", 1, &compiler->default_types.u8));
return_if_error(create_default_type_fixed_size(compiler, "u16", 2, &compiler->default_types.u16));
- return_if_error(create_default_type_fixed_size(compiler, "u32", 3, &compiler->default_types.u32));
- return_if_error(create_default_type_fixed_size(compiler, "u64", 4, &compiler->default_types.u64));
+ return_if_error(create_default_type_fixed_size(compiler, "u32", 4, &compiler->default_types.u32));
+ return_if_error(create_default_type_fixed_size(compiler, "u64", 8, &compiler->default_types.u64));
return_if_error(create_default_type_num_pointers(compiler, "isize", 1, &compiler->default_types.isize));
return_if_error(create_default_type_num_pointers(compiler, "usize", 1, &compiler->default_types.usize));
return_if_error(create_default_type_fixed_size(compiler, "f32", 4, &compiler->default_types.f32));
@@ -185,7 +186,7 @@ static CHECK_RESULT int amal_compiler_load_in_this_thread(amal_compiler *compile
result = AMAL_COMPILER_ERR;
cleanup_if_error(amal_mutex_lock(&compiler->mutex, "amal_compiler_load_in_this_thread, create arena allocator"));
- return_if_error(arena_allocator_alloc(&compiler->allocator, sizeof(ArenaAllocator), (void**)&parser_allocator));
+ cleanup_if_error(arena_allocator_alloc(&compiler->allocator, sizeof(ArenaAllocator), (void**)&parser_allocator));
amal_mutex_tryunlock(&compiler->mutex);
return_if_error(arena_allocator_init(parser_allocator));
diff --git a/src/parser.c b/src/parser.c
index 01c1d9f..ed99eb0 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -383,7 +383,7 @@ static CHECK_RESULT FunctionDecl* parser_parse_closure(Parser *self) {
TODO: Implement function declaration inside other functions.
Such functions should be moved to the file scope in the bytecode generation
*/
- assert(parser_is_current_scope_file_scope(self));
+ assert(parser_is_current_scope_file_scope(self) && "TODO: Implement function declaration inside other functions.");
throw_if_error(arena_allocator_alloc(self->allocator, sizeof(FunctionDecl), (void**)&result));
throw_if_error(funcdecl_init(result, signature, self->current_scope, self->allocator));
diff --git a/src/program.c b/src/program.c
index a0a2407..5c07c5d 100644
--- a/src/program.c
+++ b/src/program.c
@@ -42,7 +42,6 @@ static usize hash_u64(const u8 *data, usize size) {
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;
@@ -72,15 +71,13 @@ int amal_program_init(amal_program *self) {
void amal_program_deinit(amal_program *self) {
arena_allocator_deinit(&self->allocator);
- am_free(self->extern_func_indices);
am_free(self->string_indices);
- self->extern_func_indices = NULL;
self->string_indices = NULL;
if(self->data.data)
buffer_deinit(&self->data);
}
-int amal_program_add_extern_func(amal_program *self, BufferView name, void *func_ptr, int args_byte_size) {
+int amal_program_register_extern_func(amal_program *self, BufferView name, void *func_ptr, int args_byte_size) {
ProgramExternFunc extern_func;
extern_func.func = func_ptr;
extern_func.args_byte_size = args_byte_size;
@@ -93,44 +90,52 @@ int amal_program_add_extern_func(amal_program *self, BufferView name, void *func
static u8* amal_program_get_extern_funcs_start_by_import_index(amal_program *self, u8 import_index) {
BytecodeHeaderImport *header_import = (BytecodeHeaderImport*)self->imports_start;
+ u32 extern_function_index = 0;
header_import += import_index;
- return (u8*)self->data.data + header_import->extern_function_index;
+ assert(sizeof(extern_function_index) == sizeof(header_import->extern_function_index));
+ am_memcpy(&extern_function_index, &header_import->extern_function_index, sizeof(extern_function_index));
+ return (u8*)self->data.data + extern_function_index;
+}
+
+static u32 extern_func_get_total_param_size(BytecodeHeaderExternFunction *self) {
+ return self->params_fixed_size + self->params_num_pointers * sizeof(void*);
}
typedef struct {
- u8 num_params;
+ BytecodeHeaderExternFunction extern_func;
BufferView name;
-} BytecodeHeaderExternFunction;
+} BytecodeHeaderExternFunctionFull;
/* TODO: Optimize this */
-static void amal_program_get_header_extern_function_by_index(amal_program *self, u8 import_index, u16 index, BytecodeHeaderExternFunction *result) {
+static void amal_program_get_header_extern_function_by_index(amal_program *self, u8 import_index, u16 index, BytecodeHeaderExternFunctionFull *result) {
u32 i;
u8 *extern_funcs_start = amal_program_get_extern_funcs_start_by_import_index(self, import_index);
extern_funcs_start += sizeof(u16) + sizeof(u32);
for(i = 0; i < (u32)index; ++i) {
- u8 name_len = *(extern_funcs_start + sizeof(u8));
- /* +1 for the null-terminated character */
- extern_funcs_start += sizeof(u8) + sizeof(u8) + name_len + 1;
+ u8 name_len;
+ extern_funcs_start += sizeof(BytecodeHeaderExternFunction);
+ name_len = *extern_funcs_start;
+ extern_funcs_start += 1 + name_len + 1; /* +1 for skipping length byte and the null-terminated character */
}
- result->num_params = extern_funcs_start[0];
- result->name.size = extern_funcs_start[1];
- result->name.data = (const char*)extern_funcs_start + sizeof(u8) + sizeof(u8);
+ am_memcpy(&result->extern_func, extern_funcs_start, sizeof(result->extern_func));
+ result->name.size = *(extern_funcs_start + sizeof(result->extern_func));
+ result->name.data = (const char*)extern_funcs_start + sizeof(result->extern_func) + sizeof(u8);
}
static CHECK_RESULT int amal_program_get_extern_func_by_index(amal_program *self, u8 import_index, u16 index, ProgramExternFunc *result) {
- BytecodeHeaderExternFunction extern_func;
+ BytecodeHeaderExternFunctionFull extern_func;
amal_program_get_header_extern_function_by_index(self, import_index, index, &extern_func);
if(!hash_map_get(&self->extern_funcs_map, extern_func.name, result)) {
- amal_log_error("No such extern function: %.*s", extern_func.name.size, extern_func.name.data);
+ amal_log_error("Extern function \"%.*s\" has not been registered", extern_func.name.size, extern_func.name.data);
return AMAL_PROGRAM_NO_SUCH_EXTERNAL_FUNCTION;
}
/* TODO: This assumes all arguments are of size sizeof(isize) */
- if(result->args_byte_size != -1 && result->args_byte_size != extern_func.num_params * (int)sizeof(isize)) {
+ if(result->args_byte_size != -1 && result->args_byte_size != (int)extern_func_get_total_param_size(&extern_func.extern_func)) {
amal_log_error("Extern function %.*s was registered to take %d byte(s), but the program says it takes %d byte(s)",
- extern_func.name.size, extern_func.name.data, result->args_byte_size, extern_func.num_params * sizeof(isize));
+ extern_func.name.size, extern_func.name.data, result->args_byte_size, (int)extern_func_get_total_param_size(&extern_func.extern_func));
return AMAL_PROGRAM_NO_SUCH_EXTERNAL_FUNCTION;
}
return 0;
@@ -234,9 +239,6 @@ static CHECK_RESULT int amal_program_advance_section_magic_number(amal_program *
static CHECK_RESULT int amal_program_read_intermediates(amal_program *self) {
u32 intermediates_size;
- /*u32 read_end;*/
-
- return_if_error(amal_program_advance_section_magic_number(self));
if(bytes_left_to_read(self) < sizeof(intermediates_size)) {
amal_log_error("Not enough space in program to intermediates size");
@@ -262,8 +264,6 @@ static CHECK_RESULT int amal_program_read_strings(amal_program *self) {
u32 strings_size;
u32 *string_index_ptr;
- return_if_error(amal_program_advance_section_magic_number(self));
-
if(!amal_program_read_advance(self, &self->num_strings, sizeof(u16)))
return AMAL_PROGRAM_INVALID_STRINGS;
@@ -309,8 +309,6 @@ static CHECK_RESULT int amal_program_read_strings(amal_program *self) {
static CHECK_RESULT int amal_program_read_functions(amal_program *self) {
u32 funcs_size;
- return_if_error(amal_program_advance_section_magic_number(self));
-
if(!amal_program_read_advance(self, &self->num_functions, sizeof(u16)))
return AMAL_PROGRAM_INVALID_FUNCTIONS;
@@ -324,9 +322,6 @@ static CHECK_RESULT int amal_program_read_functions(amal_program *self) {
static CHECK_RESULT int amal_program_read_external_functions(amal_program *self) {
u32 extern_funcs_size;
- u32 *extern_func_index_ptr;
-
- return_if_error(amal_program_advance_section_magic_number(self));
if(!amal_program_read_advance(self, &self->num_extern_functions, sizeof(u16)))
return AMAL_PROGRAM_INVALID_EXTERNAL_FUNCTIONS;
@@ -337,46 +332,13 @@ static CHECK_RESULT int amal_program_read_external_functions(amal_program *self)
if(bytes_left_to_read(self) < extern_funcs_size)
return AMAL_PROGRAM_INVALID_EXTERNAL_FUNCTIONS_SIZE;
- am_free(self->extern_func_indices);
- self->extern_func_indices = NULL;
- if(am_malloc(sizeof(u32) * self->num_extern_functions, (void**)&self->extern_func_indices) != 0)
- return AMAL_PROGRAM_ALLOC_FAILURE;
- extern_func_index_ptr = self->extern_func_indices;
-
- {
- const u32 read_start = self->read_index;
- const u32 read_end = read_start + extern_funcs_size;
- self->extern_funcs_start = (u8*)(self->data.data + self->read_index);
- while(self->read_index < read_end) {
- u8 num_params;
- u8 func_name_size;
-
- if(bytes_left_to_read(self) < sizeof(num_params) + sizeof(func_name_size))
- return AMAL_PROGRAM_INVALID_EXTERNAL_FUNCTIONS;
-
- *extern_func_index_ptr = self->read_index - read_start;
- ++extern_func_index_ptr;
- num_params = self->data.data[self->read_index];
- func_name_size = self->data.data[self->read_index + sizeof(num_params)];
- self->read_index += sizeof(num_params) + sizeof(func_name_size);
-
- /* +1 to skip null-termination character */
- if(bytes_left_to_read(self) < func_name_size + 1U)
- return AMAL_PROGRAM_INVALID_EXTERNAL_FUNCTIONS;
-
- self->read_index += func_name_size + 1; /* +1 to skip null-termination character */
- }
- assert(self->read_index == read_end);
- }
-
+ self->read_index += extern_funcs_size;
return AMAL_PROGRAM_OK;
}
static CHECK_RESULT int amal_program_read_exported_functions(amal_program *self) {
u32 export_funcs_size;
- return_if_error(amal_program_advance_section_magic_number(self));
-
if(!amal_program_read_advance(self, &self->num_exported_functions, sizeof(u16)))
return AMAL_PROGRAM_INVALID_EXPORTED_FUNCTIONS;
@@ -399,8 +361,6 @@ static CHECK_RESULT int amal_program_read_exported_functions(amal_program *self)
static CHECK_RESULT int amal_program_read_imports(amal_program *self) {
u32 imports_size;
- return_if_error(amal_program_advance_section_magic_number(self));
-
if(!amal_program_read_advance(self, &self->num_imports, sizeof(u8)))
return AMAL_PROGRAM_INVALID_IMPORTS;
@@ -437,20 +397,26 @@ static CHECK_RESULT int amal_program_get_data_by_index(amal_program *self, u16 i
static u8* amal_program_get_funcs_start_by_import_index(amal_program *self, u8 import_index) {
BytecodeHeaderImport *header_import = (BytecodeHeaderImport*)self->imports_start;
+ u32 function_index = 0;
header_import += import_index;
- return (u8*)self->data.data + header_import->function_index;
+ assert(sizeof(function_index) == sizeof(header_import->function_index));
+ am_memcpy(&function_index, &header_import->function_index, sizeof(function_index));
+ return (u8*)self->data.data + function_index;
}
-static BytecodeHeaderFunction* amal_program_get_header_function_by_index(amal_program *self, u8 import_index, u16 index) {
+static void amal_program_get_header_function_by_index(amal_program *self, u8 import_index, u16 index, BytecodeHeaderFunction *result) {
u8 *funcs_start = amal_program_get_funcs_start_by_import_index(self, import_index);
BytecodeHeaderFunction *header_func = (BytecodeHeaderFunction*)(funcs_start + sizeof(u16) + sizeof(u32));
- return header_func + index;
+ am_memcpy(result, header_func + index, sizeof(BytecodeHeaderFunction));
}
static u64 deferred_func_call_get_key(amal_program *self, u8 import_index, u16 func_index) {
BytecodeHeaderImport *header_import = (BytecodeHeaderImport*)self->imports_start;
+ u32 function_index = 0;
header_import += import_index;
- return ((u64)func_index << 32) | (u64)header_import->function_index;
+ assert(sizeof(function_index) == sizeof(header_import->function_index));
+ am_memcpy(&function_index, &header_import->function_index, sizeof(function_index));
+ return ((u64)func_index << 32) | (u64)function_index;
}
static CHECK_RESULT int resolve_deferred_func_calls(amal_program *self, amal_executor *executor, u16 func_index) {
@@ -474,7 +440,8 @@ static CHECK_RESULT int resolve_deferred_func_calls(amal_program *self, amal_exe
static void header_func_set_offset(amal_program *self, u16 func_index, u32 code_offset) {
BytecodeHeaderFunction *header_func = ((BytecodeHeaderFunction*)self->funcs_start) + func_index;
- header_func->func_offset = code_offset;
+ assert(sizeof(header_func->func_offset) == sizeof(code_offset));
+ am_memcpy(&header_func->func_offset, &code_offset, sizeof(code_offset));
}
static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_executor *executor) {
@@ -489,8 +456,6 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
func_counter = 0;
self->return_value_index = 0;
- return_if_error(amal_program_advance_section_magic_number(self));
-
if(!amal_program_read_advance(self, &instructions_size, sizeof(instructions_size)))
return AMAL_PROGRAM_INVALID_INSTRUCTIONS_SIZE;
@@ -614,20 +579,22 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
u8 import_index;
u16 func_index;
u8 num_args;
- BytecodeHeaderFunction *func_def;
+ BytecodeHeaderFunction func_def;
i8 dst_reg;
am_memcpy(&import_index, self->data.data + self->read_index, sizeof(import_index));
am_memcpy(&func_index, self->data.data + self->read_index + sizeof(import_index), sizeof(func_index));
am_memcpy(&num_args, self->data.data + self->read_index + sizeof(import_index) + sizeof(func_index), sizeof(num_args));
- func_def = amal_program_get_header_function_by_index(self, import_index, func_index);
- assert(func_def->num_return_types == 1 && "TODO: Support 0 and more than 1 return values");
+ amal_program_get_header_function_by_index(self, import_index, func_index, &func_def);
+ assert(func_def.num_return_types == 1 && "TODO: Support 0 and more than 1 return values");
assert(self->return_value_index == 1);
dst_reg = self->return_values_stack[0];
- self->return_value_index -= func_def->num_return_types;
+ self->return_value_index -= func_def.num_return_types;
- if((char*)func_def < self->data.data + self->read_index) {
- return_if_error(amal_exec_call(executor, func_def->func_offset, num_args, dst_reg));
+ /* func_offset will only be non-zero when the function has been decoded (FUNC_START) */
+ if(func_def.func_offset != 0) {
+ /* TODO: Instead of pushing num args, push the sum of sizeof the last num_args */
+ return_if_error(amal_exec_call(executor, func_def.func_offset, num_args, dst_reg));
} else {
/*
The code for the function has not been generated yet (the function is defined after the current location).
@@ -746,6 +713,7 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
int amal_program_run(amal_program *self) {
int result;
amal_executor *executor;
+
if(self->data.size > PROGRAM_MAX_SIZE) {
amal_log_error("Program is too large. Max size is 1GB");
return AMAL_PROGRAM_ERR;
@@ -755,12 +723,25 @@ int amal_program_run(amal_program *self) {
cleanup_if_error(amal_program_read_header(self));
while(bytes_left_to_read(self) > 0) {
+ cleanup_if_error(amal_program_advance_section_magic_number(self));
cleanup_if_error(amal_program_read_intermediates(self));
+
+ cleanup_if_error(amal_program_advance_section_magic_number(self));
cleanup_if_error(amal_program_read_strings(self));
+
+ cleanup_if_error(amal_program_advance_section_magic_number(self));
cleanup_if_error(amal_program_read_functions(self));
+
+ cleanup_if_error(amal_program_advance_section_magic_number(self));
cleanup_if_error(amal_program_read_external_functions(self));
+
+ cleanup_if_error(amal_program_advance_section_magic_number(self));
cleanup_if_error(amal_program_read_exported_functions(self));
+
+ cleanup_if_error(amal_program_advance_section_magic_number(self));
cleanup_if_error(amal_program_read_imports(self));
+
+ cleanup_if_error(amal_program_advance_section_magic_number(self));
cleanup_if_error(amal_program_read_instructions(self, executor));
}
if(self->main_func_instruction_offset == ~(u32)0U) {
@@ -776,21 +757,22 @@ int amal_program_run(amal_program *self) {
}
int amal_program_save(amal_program *self, const char *filepath) {
- FILE *file;
- file = fopen(filepath, "wb");
+ int err = 0;
+ FILE *file = fopen(filepath, "wb");
if(!file) {
- int err;
- err = errno;
- perror(filepath);
- return -err;
+ err = -errno;
+ goto cleanup;
}
+
if(fwrite(self->data.data, 1, self->data.size, file) != self->data.size) {
- int err;
- err = errno;
- perror(filepath);
- return -err;
+ err = -errno;
+ goto cleanup;
}
- fclose(file);
- return 0;
-}
+ cleanup:
+ if(err != 0)
+ perror(filepath);
+ if(file)
+ fclose(file);
+ return err;
+}
diff --git a/src/std/arena_allocator.c b/src/std/arena_allocator.c
index 11fb40d..8b0083d 100644
--- a/src/std/arena_allocator.c
+++ b/src/std/arena_allocator.c
@@ -74,7 +74,8 @@ static usize align_ptr_ceil_offset(void *ptr, uintptr_t alignment) {
return (uintptr_t)align_ptr_ceil(ptr, alignment) - (uintptr_t)ptr;
}
-#define ALLOC_ALIGNMENT 8
+/* 16-byte alignment allows SIMD instructions to be operated on the data */
+#define ALLOC_ALIGNMENT 16
int arena_allocator_alloc(ArenaAllocator *self, usize size, void **mem) {
ArenaAllocatorNode *current;
@@ -103,6 +104,6 @@ int arena_allocator_alloc(ArenaAllocator *self, usize size, void **mem) {
int arena_allocator_add_mem(ArenaAllocator *self, usize *result_index) {
void *null_data;
null_data = NULL;
- *result_index = buffer_get_size(&self->mems, void*);
+ *result_index = self->mems.size;
return buffer_append(&self->mems, &null_data, sizeof(void*));
}
diff --git a/src/std/buffer.c b/src/std/buffer.c
index 021fce8..dca3b26 100644
--- a/src/std/buffer.c
+++ b/src/std/buffer.c
@@ -28,7 +28,6 @@ void buffer_deinit(Buffer *self) {
static CHECK_RESULT int buffer_ensure_capacity(Buffer *self, usize new_capacity) {
usize capacity;
void *new_mem;
- int alloc_result;
if(self->capacity >= new_capacity)
return BUFFER_OK;
@@ -45,15 +44,14 @@ static CHECK_RESULT int buffer_ensure_capacity(Buffer *self, usize new_capacity)
capacity = cap;
}
- alloc_result = am_realloc(self->data, capacity, &new_mem);
- if(alloc_result != ALLOC_OK)
+ if(am_realloc(self->data, capacity, &new_mem) != ALLOC_OK)
return BUFFER_ALLOC_FAIL;
self->data = new_mem;
self->capacity = capacity;
/* Update list of buffers in the allocator with the new address of the buffer data */
if(self->allocator)
- am_memcpy(self->allocator->mems.data + sizeof(void*) * self->allocator_index, &self->data, sizeof(void*));
+ am_memcpy(self->allocator->mems.data + self->allocator_index, &self->data, sizeof(void*));
return BUFFER_OK;
}
@@ -103,7 +101,7 @@ int buffer_set_capacity(Buffer *self, usize new_capacity) {
self->size = self->capacity;
/* Update list of buffers in the allocator with the new address of the buffer data */
if(self->allocator)
- am_memcpy(self->allocator->mems.data + sizeof(void*) * self->allocator_index, &self->data, sizeof(void*));
+ am_memcpy(self->allocator->mems.data + self->allocator_index, &self->data, sizeof(void*));
return BUFFER_OK;
}
diff --git a/src/std/buffer_view.c b/src/std/buffer_view.c
index 249928b..8763be2 100644
--- a/src/std/buffer_view.c
+++ b/src/std/buffer_view.c
@@ -1,5 +1,6 @@
#include "../../include/std/buffer_view.h"
#include "../../include/std/mem.h"
+#include <string.h>
BufferView create_buffer_view_null(void) {
BufferView buffer_view;
@@ -15,6 +16,13 @@ BufferView create_buffer_view(const char *data, usize size) {
return buffer_view;
}
+BufferView create_buffer_view_auto(const char *data) {
+ BufferView buffer_view;
+ buffer_view.data = data;
+ buffer_view.size = strlen(data);
+ return buffer_view;
+}
+
bool buffer_view_equals(const BufferView *self, const BufferView *other) {
return self->size == other->size && am_memeql(self->data, other->data, self->size);
}
diff --git a/src/tokenizer.c b/src/tokenizer.c
index fd516f6..de467c3 100644
--- a/src/tokenizer.c
+++ b/src/tokenizer.c
@@ -7,6 +7,7 @@
#include <limits.h>
#include <stdio.h>
#include <stdarg.h>
+#include <string.h>
static int isAlpha(int c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
@@ -399,16 +400,6 @@ int tokenizer_next(Tokenizer *self, Token *token) {
return result;
}
-static usize strlen(const char *str) {
- usize len;
- len = 0;
- while(*str != '\0') {
- ++len;
- ++str;
- }
- return len;
-}
-
/*
static const char* binop_to_string(BinopType binop_type) {
switch(binop_type) {
diff --git a/tests/glfw.amal b/tests/glfw.amal
new file mode 100644
index 0000000..8957127
--- /dev/null
+++ b/tests/glfw.amal
@@ -0,0 +1,9 @@
+extern const glfwInit: fn() i32;
+extern const glfwTerminate: fn() i32; // should return void....
+extern const glfwCreateWindow: fn(x: i32, y: i32, title: str, monitor: usize, share: usize) usize;
+
+const main = fn {
+ glfwInit();
+ glfwCreateWindow(50, 50, "hello, world", 0, 0);
+ glfwTerminate();
+} \ No newline at end of file
diff --git a/tests/main.c b/tests/main.c
index eec3a78..1a86769 100644
--- a/tests/main.c
+++ b/tests/main.c
@@ -1,12 +1,12 @@
-#include <stdio.h>
-#include <string.h>
#include "../include/compiler.h"
#include "../include/std/hash_map.h"
#include "../include/std/hash.h"
#include "../include/std/log.h"
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
+#include <GLFW/glfw3.h>
static int num_threads = 0;
static int num_successful_tests = 0;
@@ -142,6 +142,93 @@ static int print_extern_num(i64 num) {
return 0;
}
+static void test_load_gl(void) {
+ #if 0
+ GLFWwindow* window;
+
+ /* Initialize the library */
+ if (!glfwInit())
+ FAIL_TEST(full_path);
+
+ /* Create a windowed mode window and its OpenGL context */
+ window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
+ if (!window) {
+ glfwTerminate();
+ FAIL_TEST(full_path);
+ }
+
+ /* Make the window's context current */
+ glfwMakeContextCurrent(window);
+
+ /* Loop until the user closes the window */
+ while (!glfwWindowShouldClose(window))
+ {
+ /* Render here */
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+
+ /* Swap front and back buffers */
+ glfwSwapBuffers(window);
+
+ /* Poll for and process events */
+ glfwPollEvents();
+ }
+
+ glfwTerminate();
+ #endif
+ char *full_path = get_full_path("tests/glfw.amal");
+ amal_compiler_options options;
+ amal_program program;
+ int result;
+
+ amal_compiler_options_init(&options);
+ options.num_threads = num_threads;
+ ++num_tests_run;
+
+ if(amal_program_init(&program) != 0) {
+ fprintf(stderr, "Failed to initialize amal program\n");
+ FAIL_TEST_CLEANUP(full_path);
+ }
+
+ printf("glfw init ptr: %p, glfw terminate: %p\n", glfwInit, glfwTerminate);
+
+ if(amal_program_register_extern_func(&program, create_buffer_view_auto("glfwInit"), glfwInit, 0) != 0) {
+ fprintf(stderr, "Unexpected error (alloc failure)\n");
+ FAIL_TEST_CLEANUP(full_path);
+ }
+ if(amal_program_register_extern_func(&program, create_buffer_view_auto("glfwTerminate"), glfwTerminate, 0) != 0) {
+ fprintf(stderr, "Unexpected error (alloc failure)\n");
+ FAIL_TEST_CLEANUP(full_path);
+ }
+ if(amal_program_register_extern_func(&program, create_buffer_view_auto("glfwCreateWindow"), glfwCreateWindow, sizeof(int) + sizeof(int) + sizeof(const char*) + sizeof(void*) + sizeof(void*)) != 0) {
+ fprintf(stderr, "Unexpected error (alloc failure)\n");
+ FAIL_TEST_CLEANUP(full_path);
+ }
+ if(amal_program_register_extern_func(&program, create_buffer_view_auto("print_extern_num"), print_extern_num, sizeof(i64)) != 0) {
+ fprintf(stderr, "Unexpected error (alloc failure)\n");
+ FAIL_TEST_CLEANUP(full_path);
+ }
+
+ result = amal_compiler_load_file(&options, &program, full_path);
+ if(result != AMAL_COMPILER_OK) {
+ fprintf(stderr, "Failed to load file %s, result: %d\n", full_path, result);
+ FAIL_TEST_CLEANUP(full_path);
+ }
+
+ result = amal_program_run(&program);
+ if(result != 0) {
+ fprintf(stderr, "Failed to run the program %s, result: %d\n", full_path, result);
+ FAIL_TEST_CLEANUP(full_path);
+ }
+
+ fprintf(stderr, "Test succeeded as expected: %s\n", full_path);
+ ++num_successful_tests;
+
+ cleanup:
+ amal_program_deinit(&program);
+ free(full_path);
+}
+
static void test_load(const char *filepath) {
amal_compiler_options options;
amal_program program;
@@ -155,14 +242,14 @@ static void test_load(const char *filepath) {
if(amal_program_init(&program) != 0) {
fprintf(stderr, "Failed to initialize amal program\n");
- FAIL_TEST(full_path);
+ FAIL_TEST_CLEANUP(full_path);
}
- if(amal_program_add_extern_func(&program, create_buffer_view("print_extern", 12), print_extern, 0) != 0) {
+ if(amal_program_register_extern_func(&program, create_buffer_view_auto("print_extern"), print_extern, 0) != 0) {
fprintf(stderr, "Unexpected error (alloc failure)\n");
FAIL_TEST_CLEANUP(full_path);
}
- if(amal_program_add_extern_func(&program, create_buffer_view("print_extern_num", 16), print_extern_num, sizeof(i64)) != 0) {
+ if(amal_program_register_extern_func(&program, create_buffer_view_auto("print_extern_num"), print_extern_num, sizeof(i64)) != 0) {
fprintf(stderr, "Unexpected error (alloc failure)\n");
FAIL_TEST_CLEANUP(full_path);
}
@@ -301,7 +388,10 @@ int main(int argc, char **argv) {
if(argc == 1) {
run_all_tests();
} else if(argc == 2) {
- test_load(argv[1]);
+ if(strcmp(argv[1], "opengl") == 0)
+ test_load_gl();
+ else
+ test_load(argv[1]);
} else {
fprintf(stderr, "usage: test [test-file-path]\n");
fprintf(stderr, "If you run test without any files then all tests will run.\n");