diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 59beae56d..4e3c1b405 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -986,7 +986,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { GB_ASSERT(pl->body->kind == Ast_BlockStmt); if (!pt->is_polymorphic) { - check_procedure_later(ctx, ctx->file, e->token, d, proc_type, pl->body, pl->tags); + check_procedure_later(ctx->checker, ctx->file, e->token, d, proc_type, pl->body, pl->tags); } } else if (!is_foreign) { if (e->Procedure.is_export) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ed1ddd1f1..eb9f76547 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -417,8 +417,6 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E CheckerContext nctx = *old_c; - nctx.procs_to_check_queue = old_c->procs_to_check_queue; - Scope *scope = create_scope(info, base_entity->scope); scope->flags |= ScopeFlag_Proc; nctx.scope = scope; @@ -566,7 +564,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E } // NOTE(bill): Check the newly generated procedure body - check_procedure_later(&nctx, proc_info); + check_procedure_later(nctx.checker, proc_info); return true; } @@ -6187,7 +6185,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op decl->where_clauses_evaluated = true; if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { - check_procedure_later(c, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); + check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); } } return data; @@ -6225,7 +6223,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op decl->where_clauses_evaluated = true; if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { - check_procedure_later(c, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); + check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); } } return data; @@ -9447,7 +9445,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast } pl->decl = decl; - check_procedure_later(&ctx, ctx.file, empty_token, decl, type, pl->body, pl->tags); + check_procedure_later(ctx.checker, ctx.file, empty_token, decl, type, pl->body, pl->tags); } check_close_scope(&ctx); diff --git a/src/checker.cpp b/src/checker.cpp index 1e40f04a6..30e7409f9 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1195,7 +1195,6 @@ gb_internal void reset_checker_context(CheckerContext *ctx, AstFile *file, Untyp GB_ASSERT(ctx->checker != nullptr); mutex_lock(&ctx->mutex); - auto *queue = ctx->procs_to_check_queue; auto type_path = ctx->type_path; array_clear(type_path); @@ -1211,7 +1210,6 @@ gb_internal void reset_checker_context(CheckerContext *ctx, AstFile *file, Untyp add_curr_ast_file(ctx, file); - ctx->procs_to_check_queue = queue; ctx->untyped = untyped; mutex_unlock(&ctx->mutex); @@ -1232,7 +1230,7 @@ gb_internal void init_checker(Checker *c) { mpmc_init(&c->procs_with_deferred_to_check, a, 1<<10); // NOTE(bill): 1 Mi elements should be enough on average - mpmc_init(&c->procs_to_check_queue, heap_allocator(), 1<<20); + array_init(&c->procs_to_check, heap_allocator(), 0, 1<<20); mpmc_init(&c->global_untyped_queue, a, 1<<20); @@ -1244,7 +1242,7 @@ gb_internal void destroy_checker(Checker *c) { destroy_checker_context(&c->builtin_ctx); - mpmc_destroy(&c->procs_to_check_queue); + array_free(&c->procs_to_check); mpmc_destroy(&c->global_untyped_queue); } @@ -1941,23 +1939,19 @@ gb_global std::atomic global_procedure_body_in_worker_queue = false; gb_internal WORKER_TASK_PROC(check_proc_info_worker_proc); -gb_internal void check_procedure_later(CheckerContext *c, ProcInfo *info) { +gb_internal void check_procedure_later(Checker *c, ProcInfo *info) { GB_ASSERT(info != nullptr); GB_ASSERT(info->decl != nullptr); if (MULTITHREAD_CHECKER && global_procedure_body_in_worker_queue) { thread_pool_add_task(check_proc_info_worker_proc, info); } else { - if (build_context.threaded_checker && global_procedure_body_in_worker_queue) { - GB_ASSERT(c->procs_to_check_queue != nullptr); - } - - auto *queue = c->procs_to_check_queue ? c->procs_to_check_queue : &c->checker->procs_to_check_queue; - mpmc_enqueue(queue, info); + GB_ASSERT(global_procedure_body_in_worker_queue == false); + array_add(&c->procs_to_check, info); } } -gb_internal void check_procedure_later(CheckerContext *c, AstFile *file, Token token, DeclInfo *decl, Type *type, Ast *body, u64 tags) { +gb_internal void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, Ast *body, u64 tags) { ProcInfo *info = gb_alloc_item(permanent_allocator(), ProcInfo); info->file = file; info->token = token; @@ -4677,11 +4671,7 @@ struct CollectEntityWorkerData { gb_global CollectEntityWorkerData *collect_entity_worker_data; gb_internal WORKER_TASK_PROC(check_collect_entities_all_worker_proc) { - isize thread_idx = 0; - if (current_thread) { - thread_idx = current_thread->idx; - } - CollectEntityWorkerData *wd = &collect_entity_worker_data[thread_idx]; + CollectEntityWorkerData *wd = &collect_entity_worker_data[current_thread_index()]; Checker *c = wd->c; CheckerContext *ctx = &wd->ctx; @@ -4738,10 +4728,8 @@ gb_internal void check_export_entities_in_pkg(CheckerContext *ctx, AstPackage *p } gb_internal WORKER_TASK_PROC(check_export_entities_worker_proc) { - isize thread_idx = current_thread ? current_thread->idx : 0; - AstPackage *pkg = (AstPackage *)data; - auto *wd = &collect_entity_worker_data[thread_idx]; + auto *wd = &collect_entity_worker_data[current_thread_index()]; check_export_entities_in_pkg(&wd->ctx, pkg, &wd->untyped); return 0; } @@ -5069,7 +5057,7 @@ gb_internal void calculate_global_init_order(Checker *c) { } -gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped, ProcBodyQueue *procs_to_check_queue) { +gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped) { if (pi == nullptr) { return false; } @@ -5085,17 +5073,16 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u } return true; } + if (e != nullptr && (e->flags & EntityFlag_ProcBodyChecked) != 0) { + GB_ASSERT(pi->decl->proc_checked); + return true; + } + pi->decl->proc_checked = true; + if (e != nullptr) { + e->flags |= EntityFlag_ProcBodyChecked; + } } - CheckerContext ctx = make_checker_context(c); - defer (destroy_checker_context(&ctx)); - reset_checker_context(&ctx, pi->file, untyped); - ctx.decl = pi->decl; - - GB_ASSERT(procs_to_check_queue != nullptr || MULTITHREAD_CHECKER); - - ctx.procs_to_check_queue = procs_to_check_queue; - GB_ASSERT(pi->type->kind == Type_Proc); TypeProc *pt = &pi->type->Proc; String name = pi->token.string; @@ -5116,6 +5103,12 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u } } + + CheckerContext ctx = make_checker_context(c); + defer (destroy_checker_context(&ctx)); + reset_checker_context(&ctx, pi->file, untyped); + ctx.decl = pi->decl; + bool bounds_check = (pi->tags & ProcTag_bounds_check) != 0; bool no_bounds_check = (pi->tags & ProcTag_no_bounds_check) != 0; @@ -5138,24 +5131,14 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u ctx.state_flags &= ~StateFlag_type_assert; } - if (pi->body != nullptr && e != nullptr) { - GB_ASSERT((e->flags & EntityFlag_ProcBodyChecked) == 0); - } - check_proc_body(&ctx, pi->token, pi->decl, pi->type, pi->body); - MUTEX_GUARD_BLOCK(&pi->decl->proc_checked_mutex) { - if (e != nullptr) { - e->flags |= EntityFlag_ProcBodyChecked; - } - pi->decl->proc_checked = true; - } add_untyped_expressions(&c->info, ctx.untyped); return true; } GB_STATIC_ASSERT(sizeof(isize) == sizeof(void *)); -gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, ProcBodyQueue *q, UntypedExprInfoMap *untyped); +gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped); gb_internal void check_unchecked_bodies(Checker *c) { // NOTE(2021-02-26, bill): Sanity checker @@ -5193,15 +5176,13 @@ gb_internal void check_unchecked_bodies(Checker *c) { } debugf("unchecked: %.*s\n", LIT(e->token.string)); - mpmc_enqueue(&c->procs_to_check_queue, pi); + array_add(&c->procs_to_check, pi); } } - auto *q = &c->procs_to_check_queue; - ProcInfo *pi = nullptr; - while (mpmc_dequeue(q, &pi)) { + for (ProcInfo *pi : c->procs_to_check) { Entity *e = pi->decl->entity; - if (consume_proc_info_queue(c, pi, q, &untyped)) { + if (consume_proc_info_queue(c, pi, &untyped)) { add_dependency_to_set(c, e); GB_ASSERT(e->flags & EntityFlag_ProcBodyChecked); } @@ -5245,7 +5226,7 @@ gb_internal void check_test_procedures(Checker *c) { gb_global std::atomic total_bodies_checked; -gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, ProcBodyQueue *q, UntypedExprInfoMap *untyped) { +gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped) { GB_ASSERT(pi->decl != nullptr); if (pi->decl->parent && pi->decl->parent->entity) { Entity *parent = pi->decl->parent->entity; @@ -5253,14 +5234,14 @@ gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, ProcBodyQueue // This is prevent any possible race conditions in evaluation when multithreaded // NOTE(bill): In single threaded mode, this should never happen if (parent->kind == Entity_Procedure && (parent->flags & EntityFlag_ProcBodyChecked) == 0) { - mpmc_enqueue(q, pi); + check_procedure_later(c, pi); return false; } } if (untyped) { map_clear(untyped); } - bool ok = check_proc_info(c, pi, untyped, q); + bool ok = check_proc_info(c, pi, untyped); total_bodies_checked.fetch_add(1, std::memory_order_relaxed); return ok; } @@ -5273,12 +5254,9 @@ struct CheckProcedureBodyWorkerData { gb_global CheckProcedureBodyWorkerData *check_procedure_bodies_worker_data; gb_internal WORKER_TASK_PROC(check_proc_info_worker_proc) { - isize thread_idx = 0; - if (current_thread) { - thread_idx = current_thread->idx; - } - UntypedExprInfoMap *untyped = &check_procedure_bodies_worker_data[thread_idx].untyped; - Checker *c = check_procedure_bodies_worker_data[thread_idx].c; + auto *wd = &check_procedure_bodies_worker_data[current_thread_index()]; + UntypedExprInfoMap *untyped = &wd->untyped; + Checker *c = wd->c; ProcInfo *pi = cast(ProcInfo *)data; @@ -5294,7 +5272,7 @@ gb_internal WORKER_TASK_PROC(check_proc_info_worker_proc) { } } map_clear(untyped); - bool ok = check_proc_info(c, pi, untyped, nullptr); + bool ok = check_proc_info(c, pi, untyped); total_bodies_checked.fetch_add(1, std::memory_order_relaxed); return !ok; } @@ -5321,13 +5299,11 @@ gb_internal void check_procedure_bodies(Checker *c) { }); if (thread_count == 1) { - auto *this_queue = &c->procs_to_check_queue; - UntypedExprInfoMap *untyped = &check_procedure_bodies_worker_data[0].untyped; - - for (ProcInfo *pi = nullptr; mpmc_dequeue(this_queue, &pi); /**/) { - consume_proc_info_queue(c, pi, this_queue, untyped); + for_array(i, c->procs_to_check) { + consume_proc_info_queue(c, c->procs_to_check[i], untyped); } + array_clear(&c->procs_to_check); debugf("Total Procedure Bodies Checked: %td\n", total_bodies_checked.load(std::memory_order_relaxed)); return; @@ -5335,12 +5311,12 @@ gb_internal void check_procedure_bodies(Checker *c) { global_procedure_body_in_worker_queue = true; - for (ProcInfo *pi = nullptr; mpmc_dequeue(&c->procs_to_check_queue, &pi); /**/) { - thread_pool_add_task(check_proc_info_worker_proc, pi); + isize prev_procs_to_check_count = c->procs_to_check.count; + for_array(i, c->procs_to_check) { + thread_pool_add_task(check_proc_info_worker_proc, c->procs_to_check[i]); } - - isize global_remaining = c->procs_to_check_queue.count.load(std::memory_order_relaxed); - GB_ASSERT(global_remaining == 0); + GB_ASSERT(prev_procs_to_check_count == c->procs_to_check.count); + array_clear(&c->procs_to_check); thread_pool_wait(); diff --git a/src/checker.hpp b/src/checker.hpp index 1d6019b79..eaad1fa63 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -418,8 +418,6 @@ struct CheckerContext { Scope * polymorphic_scope; Ast *assignment_lhs_hint; - - ProcBodyQueue *procs_to_check_queue; }; @@ -430,9 +428,7 @@ struct Checker { CheckerContext builtin_ctx; MPMCQueue procs_with_deferred_to_check; - - ProcBodyQueue procs_to_check_queue; - Semaphore procs_to_check_semaphore; + Array procs_to_check; // TODO(bill): Technically MPSC queue MPMCQueue global_untyped_queue; diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index 9ac1af039..939d3c533 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -21,6 +21,10 @@ struct ThreadPool { Futex tasks_left; }; +gb_internal isize current_thread_index(void) { + return current_thread ? current_thread->idx : 0; +} + gb_internal void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_name) { pool->allocator = a; slice_init(&pool->threads, a, thread_count + 1);