mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-09 11:58:10 +00:00
Remove use of queues for procedure checking.
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
108
src/checker.cpp
108
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<bool> 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<isize> 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();
|
||||
|
||||
|
||||
@@ -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<Entity *> procs_with_deferred_to_check;
|
||||
|
||||
ProcBodyQueue procs_to_check_queue;
|
||||
Semaphore procs_to_check_semaphore;
|
||||
Array<ProcInfo *> procs_to_check;
|
||||
|
||||
// TODO(bill): Technically MPSC queue
|
||||
MPMCQueue<UntypedExprInfo> global_untyped_queue;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user