aboutsummaryrefslogtreecommitdiff
path: root/src/compiler.c
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-07-17 19:23:16 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-25 14:36:46 +0200
commit84e65c63e7482590d535e86f7660a00ae8a0cecb (patch)
treec79de87b7136e96b977003db85d43e5e676bbfc1 /src/compiler.c
parent85c654a102701958d3748e82ecac9c1bc4dbbcba (diff)
Start on amal program
Fix mutex issue in lhs expr which can cause a deadlock when a file has an error and throws and doesn't close the mutex and another thread waits for that mutex. The mutex can instead be removed and ignore race conditions which are uncommon. This should improve memory usage and performance.
Diffstat (limited to 'src/compiler.c')
-rw-r--r--src/compiler.c81
1 files changed, 50 insertions, 31 deletions
diff --git a/src/compiler.c b/src/compiler.c
index e7b242b..1af9537 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -12,6 +12,8 @@
#include <limits.h>
#include <assert.h>
+static void amal_compiler_deinit(amal_compiler *self);
+
static usize strnlen(const char *str, usize max_length) {
usize len;
len = 0;
@@ -31,9 +33,7 @@ static CHECK_RESULT int create_default_type(amal_compiler *compiler, const char
return_if_error(structdecl_init(struct_decl, &compiler->root_scope, &compiler->allocator));
return_if_error(scoped_allocator_alloc(&compiler->allocator, sizeof(LhsExpr), (void**)lhs_expr));
- return_if_error(lhsexpr_init(*lhs_expr, bool_true, bool_true, bool_true,
- create_buffer_view(name, strnlen(name, PATH_MAX)),
- &compiler->allocator));
+ lhsexpr_init(*lhs_expr, bool_true, bool_true, bool_true, create_buffer_view(name, strnlen(name, PATH_MAX)));
return_if_error(ast_create(&compiler->allocator, struct_decl, AST_STRUCT_DECL, &(*lhs_expr)->rhs_expr));
return_if_error(ast_create(&compiler->allocator, *lhs_expr, AST_LHS, &expr));
expr->resolve_data.type = *lhs_expr;
@@ -64,7 +64,7 @@ void amal_compiler_options_init(amal_compiler_options *self) {
self->num_threads = 0;
}
-int amal_compiler_init(amal_compiler *self, const amal_compiler_options *options) {
+static CHECK_RESULT int amal_compiler_init(amal_compiler *self, const amal_compiler_options *options, amal_program *program) {
int i;
self->usable_thread_count = options ? options->num_threads : 0;
@@ -72,19 +72,20 @@ int amal_compiler_init(amal_compiler *self, const amal_compiler_options *options
self->usable_thread_count = amal_get_usable_thread_count();
if(self->usable_thread_count == 0) {
amal_log_warning("Unable to get the number of threads available on the system, using 1 thread.");
- amal_log_warning("You can override the number of threads using by setting compiler option for number of thread to use.");
+ amal_log_warning("You can override the number of threads used by setting compiler option for number of thread to use.");
self->usable_thread_count = 1;
}
}
+ amal_log_info("Using %d threads", self->usable_thread_count);
am_memset(&self->allocator, 0, sizeof(self->allocator));
am_memset(&self->root_scope, 0, sizeof(self->root_scope));
if(options)
- am_memcpy(&self->options, options, sizeof(self->options));
+ self->options = *options;
else
- am_memset(&self->options, 0, sizeof(self->options));
+ amal_compiler_options_init(&self->options);
+ self->program = program;
self->started = bool_false;
- self->used = bool_false;
self->generic_work_object_index = 0;
amal_mutex_init(&self->mutex);
@@ -92,7 +93,7 @@ int amal_compiler_init(amal_compiler *self, const amal_compiler_options *options
cleanup_if_error(scope_init(&self->root_scope, NULL, &self->allocator));
cleanup_if_error(buffer_init(&self->parsers, &self->allocator));
cleanup_if_error(buffer_init(&self->queued_files, &self->allocator));
- cleanup_if_error(hash_map_init(&self->file_scopes, &self->allocator, sizeof(FileScopeReference*), hash_compare_string, amal_hash_string));
+ cleanup_if_error(hash_map_init(&self->file_scopes, &self->allocator, sizeof(FileScopeReference*), hash_map_compare_string, amal_hash_string));
cleanup_if_error(scoped_allocator_alloc(&self->allocator,
self->usable_thread_count * sizeof(ParserThreadData),
(void**)&self->threads));
@@ -102,25 +103,18 @@ int amal_compiler_init(amal_compiler *self, const amal_compiler_options *options
return AMAL_COMPILER_OK;
cleanup:
- ignore_result_int(amal_compiler_deinit(self));
+ amal_compiler_deinit(self);
return AMAL_COMPILER_ERR;
}
-int amal_compiler_deinit(amal_compiler *self) {
+void amal_compiler_deinit(amal_compiler *self) {
int i;
- int result;
- result = AMAL_COMPILER_OK;
-
for(i = 0; i < self->usable_thread_count; ++i) {
- int r;
- r = parser_thread_data_deinit(&self->threads[i]);
- if(r != 0)
- result = r;
+ parser_thread_data_deinit(&self->threads[i]);
}
amal_mutex_deinit(&self->mutex);
scoped_allocator_deinit(&self->allocator);
- return result;
}
typedef enum {
@@ -199,13 +193,19 @@ static void* thread_callback_parse_file(void *userdata) {
cleanup:
/*
- To stop all other parsers from working cleanly, we simply clear the file queue,
- and the other threads will stop when they are done with the file they are currently parsing.
+ To stop all other parsers from working cleanly, we simply clear the file queue,
+ and the other threads will stop when they are done with the file they are currently parsing.
*/
if(result != NULL) {
ignore_result_int(amal_mutex_lock(&compiler_parser_userdata.compiler->mutex, "thread_callback_parse_file"));
buffer_clear(&compiler_parser_userdata.compiler->queued_files);
}
+ /*
+ There can be a data race between writing to this and when this is read in @amal_compiler_load_file_join_threads.
+ This is intentional and it's ok, because the join_threads function checks against this status is guaranteed at this point
+ to not be a certain value that it checks for. Writing to an int is atomic.
+ TODO: Verify this is ok on all platforms.
+ */
compiler_parser_userdata.parser_thread_data->status = PARSER_THREAD_STATUS_IDLE;
amal_mutex_tryunlock(&compiler_parser_userdata.compiler->mutex);
return result;
@@ -215,6 +215,7 @@ static CHECK_RESULT int thread_resolve_ast(amal_compiler *compiler, Parser *pars
AstCompilerContext compiler_context;
int result;
compiler_context.compiler = compiler;
+ compiler_context.parser = parser;
compiler_context.scope = NULL;
result = setjmp(compiler_context.env);
if(result == 0) {
@@ -245,14 +246,15 @@ static CHECK_RESULT int thread_generate_bytecode(Parser *parser) {
BytecodeCompilerContext compiler_context;
int result;
- return_if_error(scoped_allocator_alloc(parser->allocator, sizeof(Bytecode), (void**)&compiler_context.bytecode));
- return_if_error(bytecode_init(compiler_context.bytecode, parser->allocator));
+ return_if_error(bytecode_init(&compiler_context.bytecode, parser->allocator));
compiler_context.parser = parser;
amal_log_debug("Generating bytecode for file: %.*s", parser->tokenizer.code_name.size, parser->tokenizer.code_name.data);
result = setjmp(compiler_context.env);
- if(result == 0)
+ if(result == 0) {
generate_bytecode_from_ssa(&compiler_context);
+ parser->bytecode = compiler_context.bytecode;
+ }
return result;
}
@@ -443,6 +445,17 @@ static CHECK_RESULT int amal_compiler_dispatch_generic(amal_compiler *self, Thre
return amal_compiler_load_file_join_threads(self);
}
+static CHECK_RESULT int amal_compiler_generate_program(amal_compiler *self) {
+ Parser **parser;
+ Parser **parser_end;
+ parser = buffer_begin(&self->parsers);
+ parser_end = buffer_end(&self->parsers);
+ for(; parser != parser_end; ++parser) {
+ return_if_error(amal_program_append_bytecode(self->program, &(*parser)->bytecode));
+ }
+ return 0;
+}
+
static CHECK_RESULT int try_create_file_scope(amal_compiler *compiler, const char *filepath, FileScopeReference **file_scope, bool *new_entry) {
int ret;
char *result_path;
@@ -472,12 +485,16 @@ static CHECK_RESULT int try_create_file_scope(amal_compiler *compiler, const cha
return ret;
}
-int amal_compiler_load_file(amal_compiler *self, const char *filepath) {
+int amal_compiler_load_file(amal_compiler_options *options, amal_program *program, const char *filepath) {
+ assert(program);
+ assert(filepath);
+ amal_compiler compiler;
FileScopeReference *file_scope;
- if(self->used)
- return AMAL_COMPILER_ERR;
- self->used = bool_true;
- return amal_compiler_internal_load_file(self, filepath, &file_scope);
+ int result;
+ return_if_error(amal_compiler_init(&compiler, options, program));
+ result = amal_compiler_internal_load_file(&compiler, filepath, &file_scope);
+ amal_compiler_deinit(&compiler);
+ return result;
}
int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath, FileScopeReference **file_scope) {
@@ -510,8 +527,7 @@ int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath,
return_if_error(amal_compiler_select_thread_for_work(self, thread_work_data, &parser_thread_data));
if(main_job) {
- /*doc(CompilerFlow)
- # Compiler flow
+ /*doc(Compiler flow)
(Tokenize&parse -> Resolve AST -> Generate SSA -> Generate bytecode) -> Generate program\
Each step except the last is done using multiple threads in parallel and the output of each step is used
in the next step. The last step is not done in parallel because the last step is combining all bytecode
@@ -535,6 +551,9 @@ int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath,
assert(amal_compiler_check_all_threads_done(self));
amal_log_info("Finished generating bytecode");
+ return_if_error(amal_compiler_generate_program(self));
+ amal_log_info("Finished generating program");
+
return AMAL_COMPILER_OK;
}