diff options
Diffstat (limited to 'src/compiler.c')
-rw-r--r-- | src/compiler.c | 143 |
1 files changed, 112 insertions, 31 deletions
diff --git a/src/compiler.c b/src/compiler.c index b8bca1c..e44ba6a 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -38,6 +38,7 @@ int amal_compiler_init(amal_compiler *self) { am_memset(&self->allocator, 0, sizeof(self->allocator)); am_memset(&self->main_thread_allocator, 0, sizeof(self->main_thread_allocator)); self->started = bool_false; + self->resolve_ast_index = 0; amal_mutex_init(&self->mutex); return_if_error(scoped_allocator_init(&self->allocator)); @@ -80,7 +81,26 @@ typedef struct { BufferView filepath; } CompilerParserThreadUserData; -static CHECK_RESULT int amal_compiler_load_first_this_thread(amal_compiler *self, BufferView filepath, ScopedAllocator *allocator) { +typedef struct { + amal_compiler *compiler; + ParserThreadData *parser_thread_data; + Parser *parser; +} CompilerAstResolverThreadUserData; + +typedef enum { + THREAD_WORK_PARSE, + THREAD_WORK_RESOLVE_AST +} ThreadWorkType; + +typedef struct { + union { + BufferView filepath; + Parser *parser; + } value; + ThreadWorkType type; +} ThreadWorkData; + +static CHECK_RESULT int amal_compiler_load_in_this_thread(amal_compiler *self, BufferView filepath, ScopedAllocator *allocator) { Parser parser; int result; result = AMAL_COMPILER_ERR; @@ -88,7 +108,7 @@ static CHECK_RESULT int amal_compiler_load_first_this_thread(amal_compiler *self return_if_error(parser_init(&parser, self, allocator)); cleanup_if_error(parser_parse_file(&parser, filepath)); - cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_load_first_this_thread")); + cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_load_in_this_thread")); cleanup_if_error(buffer_append(&self->parsers, &parser, sizeof(parser))); result = AMAL_COMPILER_OK; @@ -99,54 +119,92 @@ static CHECK_RESULT int amal_compiler_load_first_this_thread(amal_compiler *self /* TODO: Handle errors (stop parsing in all other threads and report errors/warnings) */ static void* thread_callback_parse_file(void *userdata) { - int _; BufferView next_file; CompilerParserThreadUserData compiler_parser_userdata; - (void)_; - next_file = create_buffer_view_null(); assert(!amal_thread_is_main()); am_memcpy(&compiler_parser_userdata, userdata, sizeof(compiler_parser_userdata)); am_free(userdata); - cleanup_if_error(amal_compiler_load_first_this_thread(compiler_parser_userdata.compiler, - compiler_parser_userdata.filepath, - &compiler_parser_userdata.parser_thread_data->allocator)); - cleanup_if_error(amal_mutex_lock(&compiler_parser_userdata.compiler->mutex, "thread_callback_parse_file")); - if(compiler_parser_userdata.compiler->queued_files.size > 0) - _ = buffer_pop(&compiler_parser_userdata.compiler->queued_files, &next_file, sizeof(next_file)); + next_file = compiler_parser_userdata.filepath; + for(;;) { + cleanup_if_error(amal_compiler_load_in_this_thread(compiler_parser_userdata.compiler, + next_file, + &compiler_parser_userdata.parser_thread_data->allocator)); + cleanup_if_error(amal_mutex_lock(&compiler_parser_userdata.compiler->mutex, "thread_callback_parse_file")); + cleanup_if_error(buffer_pop(&compiler_parser_userdata.compiler->queued_files, &next_file, sizeof(next_file))); + amal_mutex_tryunlock(&compiler_parser_userdata.compiler->mutex); + } cleanup: - if(!next_file.data) - compiler_parser_userdata.parser_thread_data->status = PARSER_THREAD_STATUS_IDLE; + compiler_parser_userdata.parser_thread_data->status = PARSER_THREAD_STATUS_IDLE; amal_mutex_tryunlock(&compiler_parser_userdata.compiler->mutex); - if(next_file.data) { - _ = amal_compiler_load_first_this_thread(compiler_parser_userdata.compiler, - next_file, - &compiler_parser_userdata.parser_thread_data->allocator); + return NULL; +} + +/* TODO: Handle errors (stop resolving ast in all other threads and report errors/warnings) */ +static void* thread_callback_resolve_ast(void *userdata) { + Parser *parser; + CompilerAstResolverThreadUserData compiler_ast_resolver_userdata; + assert(!amal_thread_is_main()); + + am_memcpy(&compiler_ast_resolver_userdata, userdata, sizeof(compiler_ast_resolver_userdata)); + am_free(userdata); + parser = compiler_ast_resolver_userdata.parser; + for(;;) { + amal_log_debug("Resolving AST for file: %.*s", parser->tokenizer.code_name.size, parser->tokenizer.code_name.data); + scope_resolve(&parser->scope); + cleanup_if_error(amal_mutex_lock(&compiler_ast_resolver_userdata.compiler->mutex, "thread_callback_resolve_ast")); + if(compiler_ast_resolver_userdata.compiler->resolve_ast_index + 1 >= (int)buffer_get_size(&compiler_ast_resolver_userdata.compiler->parsers, Parser)) + break; + ++compiler_ast_resolver_userdata.compiler->resolve_ast_index; + parser = buffer_get(&compiler_ast_resolver_userdata.compiler->parsers, compiler_ast_resolver_userdata.compiler->resolve_ast_index, sizeof(Parser)); + amal_mutex_tryunlock(&compiler_ast_resolver_userdata.compiler->mutex); } + + cleanup: + compiler_ast_resolver_userdata.parser_thread_data->status = PARSER_THREAD_STATUS_IDLE; + amal_mutex_tryunlock(&compiler_ast_resolver_userdata.compiler->mutex); return NULL; } -static CHECK_RESULT int amal_compiler_load_file_select_thread(amal_compiler *self, BufferView filepath, ParserThreadData **thread_selected) { +static CHECK_RESULT int amal_compiler_select_thread_for_work(amal_compiler *self, ThreadWorkData work_data, ParserThreadData **thread_selected) { int i; int result; ParserThreadData *parser_thread_data; - CompilerParserThreadUserData *thread_user_data; + void *thread_user_data; thread_user_data = NULL; *thread_selected = NULL; result = AMAL_COMPILER_ERR; - cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_load_file_select_thread")); + cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_select_thread_for_work")); for(i = 0; i < self->usable_thread_count; ++i) { parser_thread_data = &self->threads[i]; if(parser_thread_data->status == PARSER_THREAD_STATUS_RUNNING) continue; - cleanup_if_error(am_malloc(sizeof(CompilerParserThreadUserData), (void**)&thread_user_data)); - thread_user_data->compiler = self; - thread_user_data->parser_thread_data = parser_thread_data; - thread_user_data->filepath = filepath; - result = parser_thread_data_start(parser_thread_data, thread_callback_parse_file, thread_user_data); + switch(work_data.type) { + case THREAD_WORK_PARSE: { + CompilerParserThreadUserData *userdata; + cleanup_if_error(am_malloc(sizeof(CompilerParserThreadUserData), (void**)&userdata)); + thread_user_data = userdata; + userdata->compiler = self; + userdata->parser_thread_data = parser_thread_data; + userdata->filepath = work_data.value.filepath; + result = parser_thread_data_start(parser_thread_data, thread_callback_parse_file, userdata); + break; + } + case THREAD_WORK_RESOLVE_AST: { + CompilerAstResolverThreadUserData *userdata; + cleanup_if_error(am_malloc(sizeof(CompilerAstResolverThreadUserData), (void**)&userdata)); + thread_user_data = userdata; + userdata->compiler = self; + userdata->parser_thread_data = parser_thread_data; + userdata->parser = work_data.value.parser; + ++self->resolve_ast_index; + result = parser_thread_data_start(parser_thread_data, thread_callback_resolve_ast, userdata); + break; + } + } *thread_selected = parser_thread_data; break; } @@ -158,13 +216,13 @@ static CHECK_RESULT int amal_compiler_load_file_select_thread(amal_compiler *sel return result; } -static CHECK_RESULT int amal_compiler_all_threads_done(amal_compiler *self, bool *done) { +static CHECK_RESULT int amal_compiler_check_all_threads_done(amal_compiler *self, bool *done) { int i; int result; result = AMAL_COMPILER_OK; *done = bool_false; - cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_all_threads_done")); + cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_check_all_threads_done")); for(i = 0; i < self->usable_thread_count; ++i) { ParserThreadData *parser_thread_data; parser_thread_data = &self->threads[i]; @@ -201,11 +259,10 @@ static CHECK_RESULT int amal_compiler_load_file_join_threads(amal_compiler *self amal_mutex_tryunlock(&self->mutex); if(result != 0) goto cleanup; - amal_log_debug("Joining thread %d, status %d", i, parser_thread_data->status); ignore_result_int(parser_thread_data_join(parser_thread_data, &thread_return_data)); } - cleanup_if_error(amal_compiler_all_threads_done(self, &done)); + cleanup_if_error(amal_compiler_check_all_threads_done(self, &done)); if(done) break; } @@ -215,12 +272,33 @@ static CHECK_RESULT int amal_compiler_load_file_join_threads(amal_compiler *self return result; } +static CHECK_RESULT int amal_compiler_resolve_ast(amal_compiler *self) { + Parser *parser; + Parser *parser_end; + parser = buffer_start(&self->parsers); + parser_end = buffer_end(&self->parsers); + for(; parser != parser_end; ++parser) { + ParserThreadData *thread_selected; + ThreadWorkData thread_work_data; + thread_work_data.type = THREAD_WORK_RESOLVE_AST; + thread_work_data.value.parser = parser; + return_if_error(amal_compiler_select_thread_for_work(self, thread_work_data, &thread_selected)); + /* After all threads have been used, they will handle using the remaining parsers */ + if(!thread_selected) + break; + } + return amal_compiler_load_file_join_threads(self); +} + int amal_compiler_load_file(amal_compiler *self, BufferView filepath) { int result; ParserThreadData *parser_thread_data; + ThreadWorkData thread_work_data; result = AMAL_COMPILER_ERR; + thread_work_data.type = THREAD_WORK_PARSE; + thread_work_data.value.filepath = filepath; - return_if_error(amal_compiler_load_file_select_thread(self, filepath, &parser_thread_data)); + return_if_error(amal_compiler_select_thread_for_work(self, thread_work_data, &parser_thread_data)); /* amal_compiler_load_file is called by the user for the first file to compile @@ -230,7 +308,10 @@ int amal_compiler_load_file(amal_compiler *self, BufferView filepath) { self->started = bool_true; /*amal_log_info("Parsing %.*s using %d thread(s)", (int)filepath.size, filepath.data, self->usable_thread_count);*/ /*return_if_error(amal_compiler_load_first_this_thread(self, filepath, &self->main_thread_allocator));*/ - return amal_compiler_load_file_join_threads(self); + return_if_error(amal_compiler_load_file_join_threads(self)); + amal_log_debug("Finished parsing all files, resolving AST"); + return_if_error(amal_compiler_resolve_ast(self)); + return AMAL_COMPILER_OK; } if(parser_thread_data) |