aboutsummaryrefslogtreecommitdiff
path: root/src/checker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/checker.cpp')
-rw-r--r--src/checker.cpp731
1 files changed, 485 insertions, 246 deletions
diff --git a/src/checker.cpp b/src/checker.cpp
index e5dda2aa7..33121b453 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -380,16 +380,25 @@ gb_internal Entity *scope_lookup_current(Scope *s, String const &name) {
}
-gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entity **entity_) {
+gb_global std::atomic<bool> in_single_threaded_checker_stage;
+
+gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entity **entity_, u32 hash) {
+ bool is_single_threaded = in_single_threaded_checker_stage.load(std::memory_order_relaxed);
if (scope != nullptr) {
bool gone_thru_proc = false;
bool gone_thru_package = false;
- StringHashKey key = string_hash_string(name);
+ StringHashKey key = {};
+ if (hash) {
+ key.hash = hash;
+ key.string = name;
+ } else {
+ key = string_hash_string(name);
+ }
for (Scope *s = scope; s != nullptr; s = s->parent) {
Entity **found = nullptr;
- rw_mutex_shared_lock(&s->mutex);
+ if (!is_single_threaded) rw_mutex_shared_lock(&s->mutex);
found = string_map_get(&s->elements, key);
- rw_mutex_shared_unlock(&s->mutex);
+ if (!is_single_threaded) rw_mutex_shared_unlock(&s->mutex);
if (found) {
Entity *e = *found;
if (gone_thru_proc) {
@@ -424,9 +433,9 @@ gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **s
if (scope_) *scope_ = nullptr;
}
-gb_internal Entity *scope_lookup(Scope *s, String const &name) {
+gb_internal Entity *scope_lookup(Scope *s, String const &name, u32 hash) {
Entity *entity = nullptr;
- scope_lookup_parent(s, name, nullptr, &entity);
+ scope_lookup_parent(s, name, nullptr, &entity, hash);
return entity;
}
@@ -507,11 +516,9 @@ end:;
return result;
}
-gb_global bool in_single_threaded_checker_stage = false;
-
gb_internal Entity *scope_insert(Scope *s, Entity *entity) {
String name = entity->token.string;
- if (in_single_threaded_checker_stage) {
+ if (in_single_threaded_checker_stage.load(std::memory_order_relaxed)) {
return scope_insert_with_name_no_mutex(s, name, entity);
} else {
return scope_insert_with_name(s, name, entity);
@@ -722,9 +729,10 @@ gb_internal bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) {
gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_flags, bool per_entity) {
u64 original_vet_flags = vet_flags;
+
+ TEMPORARY_ALLOCATOR_GUARD();
Array<VettedEntity> vetted_entities = {};
- array_init(&vetted_entities, heap_allocator());
- defer (array_free(&vetted_entities));
+ array_init(&vetted_entities, temporary_allocator());
rw_mutex_shared_lock(&scope->mutex);
for (auto const &entry : scope->elements) {
@@ -782,8 +790,10 @@ gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_fl
// Is >256 KiB good enough?
if (sz > 1ll<<18) {
bool is_ref = false;
- if((e->flags & EntityFlag_ForValue) != 0) {
+ if ((e->flags & EntityFlag_ForValue) != 0) {
is_ref = type_deref(e->Variable.for_loop_parent_type) != NULL;
+ } else if ((e->flags & EntityFlag_SwitchValue) != 0) {
+ is_ref = !(e->flags & EntityFlag_Value);
}
if(!is_ref) {
gbString type_str = type_to_string(e->type);
@@ -852,9 +862,13 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
gb_internal void add_dependency(CheckerInfo *info, DeclInfo *d, Entity *e) {
- rw_mutex_lock(&d->deps_mutex);
- ptr_set_add(&d->deps, e);
- rw_mutex_unlock(&d->deps_mutex);
+ if (in_single_threaded_checker_stage.load(std::memory_order_relaxed)) {
+ ptr_set_add(&d->deps, e);
+ } else {
+ rw_mutex_lock(&d->deps_mutex);
+ ptr_set_add(&d->deps, e);
+ rw_mutex_unlock(&d->deps_mutex);
+ }
}
gb_internal void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type) {
if (d == nullptr || type == nullptr) {
@@ -911,6 +925,22 @@ gb_internal AstPackage *get_core_package(CheckerInfo *info, String name) {
return *found;
}
+
+gb_internal AstPackage *try_get_core_package(CheckerInfo *info, String name) {
+ if (name == "runtime") {
+ return get_runtime_package(info);
+ }
+
+ gbAllocator a = heap_allocator();
+ String path = get_fullpath_core_collection(a, name, nullptr);
+ defer (gb_free(a, path.text));
+ auto found = string_map_get(&info->packages, path);
+ if (found == nullptr) {
+ return nullptr;
+ }
+ return *found;
+}
+
gb_internal void add_package_dependency(CheckerContext *c, char const *package_name, char const *name, bool required=false) {
String n = make_string_c(name);
AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name));
@@ -1404,6 +1434,8 @@ gb_internal void init_universal(void) {
t_objc_SEL = alloc_type_pointer(t_objc_selector);
t_objc_Class = alloc_type_pointer(t_objc_class);
t_objc_Ivar = alloc_type_pointer(t_objc_ivar);
+
+ t_objc_instancetype = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_instancetype"), t_objc_id);
}
}
@@ -1419,13 +1451,10 @@ gb_internal void init_checker_info(CheckerInfo *i) {
array_init(&i->entities, a);
map_init(&i->global_untyped);
string_map_init(&i->foreigns);
- // map_init(&i->gen_procs);
- map_init(&i->gen_types);
type_set_init(&i->min_dep_type_info_set);
map_init(&i->min_dep_type_info_index_map);
- // map_init(&i->type_info_map);
string_map_init(&i->files);
string_map_init(&i->packages);
array_init(&i->variable_init_order, a);
@@ -1441,7 +1470,8 @@ gb_internal void init_checker_info(CheckerInfo *i) {
map_init(&i->objc_method_implementations);
string_map_init(&i->load_file_cache);
- array_init(&i->all_procedures, heap_allocator());
+ array_init(&i->all_procedures, a);
+ mpsc_init(&i->all_procedures_queue, a);
mpsc_init(&i->entity_queue, a); // 1<<20);
mpsc_init(&i->definition_queue, a); //); // 1<<20);
@@ -1463,8 +1493,6 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
array_free(&i->entities);
map_destroy(&i->global_untyped);
string_map_destroy(&i->foreigns);
- // map_destroy(&i->gen_procs);
- map_destroy(&i->gen_types);
type_set_destroy(&i->min_dep_type_info_set);
map_destroy(&i->min_dep_type_info_index_map);
@@ -1475,6 +1503,10 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
array_free(&i->required_foreign_imports_through_force);
array_free(&i->defineables);
+ array_free(&i->all_procedures);
+
+ mpsc_destroy(&i->all_procedures_queue);
+
mpsc_destroy(&i->entity_queue);
mpsc_destroy(&i->definition_queue);
mpsc_destroy(&i->required_global_variable_queue);
@@ -1487,9 +1519,12 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
map_destroy(&i->objc_msgSend_types);
string_set_destroy(&i->obcj_class_name_set);
- mpsc_destroy(&i->objc_class_implementations);
map_destroy(&i->objc_method_implementations);
+ // NOTE(harold): Disabling this: It can cause the 'count == 0' assert to trigger
+ // when there's checker errors and the queue is still full as it did not reach the generation stage.
+ // mpsc_destroy(&i->objc_class_implementations);
+
string_map_destroy(&i->load_file_cache);
string_map_destroy(&i->load_directory_cache);
map_destroy(&i->load_directory_map);
@@ -1502,12 +1537,12 @@ gb_internal CheckerContext make_checker_context(Checker *c) {
ctx.scope = builtin_pkg->scope;
ctx.pkg = builtin_pkg;
- ctx.type_path = new_checker_type_path();
+ ctx.type_path = new_checker_type_path(heap_allocator());
ctx.type_level = 0;
return ctx;
}
gb_internal void destroy_checker_context(CheckerContext *ctx) {
- destroy_checker_type_path(ctx->type_path);
+ destroy_checker_type_path(ctx->type_path, heap_allocator());
}
gb_internal bool add_curr_ast_file(CheckerContext *ctx, AstFile *file) {
@@ -1712,7 +1747,7 @@ gb_internal void check_remove_expr_info(CheckerContext *c, Ast *e) {
}
gb_internal isize type_info_index(CheckerInfo *info, TypeInfoPair pair, bool error_on_failure) {
- mutex_lock(&info->minimum_dependency_type_info_mutex);
+ rw_mutex_shared_lock(&info->minimum_dependency_type_info_mutex);
isize entry_index = -1;
u64 hash = pair.hash;
@@ -1720,7 +1755,7 @@ gb_internal isize type_info_index(CheckerInfo *info, TypeInfoPair pair, bool err
if (found_entry_index) {
entry_index = *found_entry_index;
}
- mutex_unlock(&info->minimum_dependency_type_info_mutex);
+ rw_mutex_shared_unlock(&info->minimum_dependency_type_info_mutex);
if (error_on_failure && entry_index < 0) {
compiler_error("Type_Info for '%s' could not be found", type_to_string(pair.type));
@@ -1758,7 +1793,7 @@ gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode,
check_set_expr_info(c, expr, mode, type, value);
}
-gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) {
+gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value, bool use_mutex) {
if (expr == nullptr) {
return;
}
@@ -1776,7 +1811,7 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo
mutex = &ctx->pkg->type_and_value_mutex;
}
- mutex_lock(mutex);
+ if (use_mutex) mutex_lock(mutex);
Ast *prev_expr = nullptr;
while (prev_expr != expr) {
prev_expr = expr;
@@ -1801,7 +1836,7 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo
break;
};
}
- mutex_unlock(mutex);
+ if (use_mutex) mutex_unlock(mutex);
}
gb_internal void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) {
@@ -2043,8 +2078,8 @@ gb_internal void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, En
add_entity_definition(info, identifier, e);
GB_ASSERT(e->decl_info == nullptr);
e->decl_info = d;
- d->entity = e;
e->pkg = c->pkg;
+ d->entity.store(e);
isize queue_count = -1;
bool is_lazy = false;
@@ -2345,11 +2380,9 @@ gb_internal void check_procedure_later(Checker *c, ProcInfo *info) {
}
if (DEBUG_CHECK_ALL_PROCEDURES) {
- MUTEX_GUARD_BLOCK(&c->info.all_procedures_mutex) {
- GB_ASSERT(info != nullptr);
- GB_ASSERT(info->decl != nullptr);
- array_add(&c->info.all_procedures, info);
- }
+ GB_ASSERT(info != nullptr);
+ GB_ASSERT(info->decl != nullptr);
+ mpsc_enqueue(&c->info.all_procedures_queue, info);
}
}
@@ -2377,7 +2410,7 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) {
return;
}
- if (type_set_update(&c->info.min_dep_type_info_set, t)) {
+ if (type_set_update_with_mutex(&c->info.min_dep_type_info_set, t, &c->info.min_dep_type_info_set_mutex)) {
return;
}
@@ -2552,15 +2585,15 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) {
}
}
+gb_internal void add_dependency_to_set_threaded(Checker *c, Entity *entity);
+
+gb_global std::atomic<Checker *> global_checker_ptr;
gb_internal void add_dependency_to_set(Checker *c, Entity *entity) {
if (entity == nullptr) {
return;
}
- CheckerInfo *info = &c->info;
- auto *set = &info->minimum_dependency_set;
-
if (entity->type != nullptr &&
is_type_polymorphic(entity->type)) {
DeclInfo *decl = decl_info_of_entity(entity);
@@ -2569,7 +2602,7 @@ gb_internal void add_dependency_to_set(Checker *c, Entity *entity) {
}
}
- if (ptr_set_update(set, entity)) {
+ if (entity->min_dep_count.fetch_add(1, std::memory_order_relaxed) > 0) {
return;
}
@@ -2580,29 +2613,108 @@ gb_internal void add_dependency_to_set(Checker *c, Entity *entity) {
for (TypeInfoPair const tt : decl->type_info_deps) {
add_min_dep_type_info(c, tt.type);
}
+ FOR_PTR_SET(e, decl->deps) {
+ switch (e->kind) {
+ case Entity_Procedure:
+ if (e->Procedure.is_foreign) {
+ Entity *fl = e->Procedure.foreign_library;
+ if (fl != nullptr) {
+ GB_ASSERT_MSG(fl->kind == Entity_LibraryName &&
+ (fl->flags&EntityFlag_Used),
+ "%.*s", LIT(entity->token.string));
+ add_dependency_to_set(c, fl);
+ }
+ }
+ break;
+ case Entity_Variable:
+ if (e->Variable.is_foreign) {
+ Entity *fl = e->Variable.foreign_library;
+ if (fl != nullptr) {
+ GB_ASSERT_MSG(fl->kind == Entity_LibraryName &&
+ (fl->flags&EntityFlag_Used),
+ "%.*s", LIT(entity->token.string));
+ add_dependency_to_set(c, fl);
+ }
+ }
+ break;
+ }
+ }
- for (Entity *e : decl->deps) {
+ FOR_PTR_SET(e, decl->deps) {
add_dependency_to_set(c, e);
- if (e->kind == Entity_Procedure && e->Procedure.is_foreign) {
- Entity *fl = e->Procedure.foreign_library;
- if (fl != nullptr) {
- GB_ASSERT_MSG(fl->kind == Entity_LibraryName &&
- (fl->flags&EntityFlag_Used),
- "%.*s", LIT(entity->token.string));
- add_dependency_to_set(c, fl);
+ }
+
+}
+gb_internal WORKER_TASK_PROC(add_dependency_to_set_worker) {
+ Checker *c = global_checker_ptr.load(std::memory_order_relaxed);
+ Entity *entity = cast(Entity *)data;
+ if (entity == nullptr) {
+ return 0;
+ }
+
+ if (entity->type != nullptr &&
+ is_type_polymorphic(entity->type)) {
+ DeclInfo *decl = decl_info_of_entity(entity);
+ if (decl != nullptr && decl->gen_proc_type == nullptr) {
+ return 0;
+ }
+ }
+
+ if (entity->min_dep_count.fetch_add(1, std::memory_order_relaxed) > 0) {
+ return 0;
+ }
+
+ DeclInfo *decl = decl_info_of_entity(entity);
+ if (decl == nullptr) {
+ return 0;
+ }
+ for (TypeInfoPair const tt : decl->type_info_deps) {
+ add_min_dep_type_info(c, tt.type);
+ }
+
+ FOR_PTR_SET(e, decl->deps) {
+ switch (e->kind) {
+ case Entity_Procedure:
+ if (e->Procedure.is_foreign) {
+ Entity *fl = e->Procedure.foreign_library;
+ if (fl != nullptr) {
+ GB_ASSERT_MSG(fl->kind == Entity_LibraryName &&
+ (fl->flags&EntityFlag_Used),
+ "%.*s", LIT(entity->token.string));
+ add_dependency_to_set_threaded(c, fl);
+ }
}
- } else if (e->kind == Entity_Variable && e->Variable.is_foreign) {
- Entity *fl = e->Variable.foreign_library;
- if (fl != nullptr) {
- GB_ASSERT_MSG(fl->kind == Entity_LibraryName &&
- (fl->flags&EntityFlag_Used),
- "%.*s", LIT(entity->token.string));
- add_dependency_to_set(c, fl);
+ break;
+ case Entity_Variable:
+ if (e->Variable.is_foreign) {
+ Entity *fl = e->Variable.foreign_library;
+ if (fl != nullptr) {
+ GB_ASSERT_MSG(fl->kind == Entity_LibraryName &&
+ (fl->flags&EntityFlag_Used),
+ "%.*s", LIT(entity->token.string));
+ add_dependency_to_set_threaded(c, fl);
+ }
}
+ break;
}
}
+
+ FOR_PTR_SET(e, decl->deps) {
+ add_dependency_to_set_threaded(c, e);
+ }
+
+ return 0;
+}
+
+
+gb_internal void add_dependency_to_set_threaded(Checker *c, Entity *entity) {
+ if (entity == nullptr) {
+ return;
+ }
+ thread_pool_add_task(add_dependency_to_set_worker, entity);
}
+
gb_internal void force_add_dependency_entity(Checker *c, Scope *scope, String const &name) {
Entity *e = scope_lookup(scope, name);
if (e == nullptr) {
@@ -2652,27 +2764,35 @@ gb_internal void collect_testing_procedures_of_package(Checker *c, AstPackage *p
}
gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *start) {
+ // auto const &add_to_set = add_dependency_to_set;
+ auto const &add_to_set = add_dependency_to_set_threaded;
+
+ Scope *builtin_scope = builtin_pkg->scope;
for_array(i, c->info.definitions) {
Entity *e = c->info.definitions[i];
- if (e->scope == builtin_pkg->scope) {
+ if (e->scope == builtin_scope) {
if (e->type == nullptr) {
- add_dependency_to_set(c, e);
+ add_to_set(c, e);
+ }
+ } else if (e->kind == Entity_Procedure) {
+ if (e->Procedure.is_export) {
+ add_to_set(c, e);
+ }
+ } else if (e->kind == Entity_Variable) {
+ if (e->Variable.is_export) {
+ add_to_set(c, e);
}
- } else if (e->kind == Entity_Procedure && e->Procedure.is_export) {
- add_dependency_to_set(c, e);
- } else if (e->kind == Entity_Variable && e->Variable.is_export) {
- add_dependency_to_set(c, e);
}
}
for (Entity *e; mpsc_dequeue(&c->info.required_foreign_imports_through_force_queue, &e); /**/) {
array_add(&c->info.required_foreign_imports_through_force, e);
- add_dependency_to_set(c, e);
+ add_to_set(c, e);
}
for (Entity *e; mpsc_dequeue(&c->info.required_global_variable_queue, &e); /**/) {
e->flags |= EntityFlag_Used;
- add_dependency_to_set(c, e);
+ add_to_set(c, e);
}
for_array(i, c->info.entities) {
@@ -2680,16 +2800,16 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st
switch (e->kind) {
case Entity_Variable:
if (e->Variable.is_export) {
- add_dependency_to_set(c, e);
+ add_to_set(c, e);
} else if (e->flags & EntityFlag_Require) {
- add_dependency_to_set(c, e);
+ add_to_set(c, e);
}
break;
case Entity_Procedure:
if (e->Procedure.is_export) {
- add_dependency_to_set(c, e);
+ add_to_set(c, e);
} else if (e->flags & EntityFlag_Require) {
- add_dependency_to_set(c, e);
+ add_to_set(c, e);
}
if (e->flags & EntityFlag_Init) {
Type *t = base_type(e->type);
@@ -2729,7 +2849,7 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st
if (is_init) {
- add_dependency_to_set(c, e);
+ add_to_set(c, e);
array_add(&c->info.init_procedures, e);
}
} else if (e->flags & EntityFlag_Fini) {
@@ -2764,7 +2884,7 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st
}
if (is_fini) {
- add_dependency_to_set(c, e);
+ add_to_set(c, e);
array_add(&c->info.fini_procedures, e);
}
}
@@ -2781,7 +2901,7 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st
Entity *e = entry.value;
if (e != nullptr) {
e->flags |= EntityFlag_Used;
- add_dependency_to_set(c, e);
+ add_to_set(c, e);
}
}
@@ -2796,16 +2916,11 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st
}
} else if (start != nullptr) {
start->flags |= EntityFlag_Used;
- add_dependency_to_set(c, start);
+ add_to_set(c, start);
}
}
gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) {
- isize entity_count = c->info.entities.count;
- isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor
-
- ptr_set_init(&c->info.minimum_dependency_set, min_dep_set_cap);
-
#define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do { \
if (condition) { \
String entities[] = {__VA_ARGS__}; \
@@ -2904,12 +3019,13 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) {
generate_minimum_dependency_set_internal(c, start);
+ thread_pool_wait();
+
#undef FORCE_ADD_RUNTIME_ENTITIES
}
-gb_internal bool is_entity_a_dependency(Entity *e) {
- if (e == nullptr) return false;
+gb_internal gb_inline bool is_entity_a_dependency(Entity *e) {
switch (e->kind) {
case Entity_Procedure:
return true;
@@ -2922,83 +3038,112 @@ gb_internal bool is_entity_a_dependency(Entity *e) {
return false;
}
-gb_internal Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info, gbAllocator allocator) {
- PtrMap<Entity *, EntityGraphNode *> M = {};
- map_init(&M, info->entities.count);
- defer (map_destroy(&M));
+gb_internal Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info, Arena *arena) {
+ PtrMap<Entity *, EntityGraphNode *> M_procs = {};
+ PtrMap<Entity *, EntityGraphNode *> M_vars = {};
+ PtrMap<Entity *, EntityGraphNode *> M_other = {};
+
+ map_init(&M_procs, info->entities.count);
+ defer (map_destroy(&M_procs));
+
+ map_init(&M_vars, info->entities.count);
+ defer (map_destroy(&M_vars));
+
+ map_init(&M_other, info->entities.count);
+ defer (map_destroy(&M_other));
+
for_array(i, info->entities) {
Entity *e = info->entities[i];
- if (is_entity_a_dependency(e)) {
- EntityGraphNode *n = gb_alloc_item(allocator, EntityGraphNode);
- n->entity = e;
- map_set(&M, e, n);
+ if (e == nullptr || !is_entity_a_dependency(e)) {
+ continue;
+ }
+ EntityGraphNode *n = arena_alloc_item<EntityGraphNode>(arena);
+ n->entity = e;
+ switch (e->kind) {
+ case Entity_Procedure: map_set(&M_procs, e, n); break;
+ case Entity_Variable: map_set(&M_vars, e, n); break;
+ default: map_set(&M_other, e, n); break;
}
}
TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 1");
// Calculate edges for graph M
- for (auto const &entry : M) {
+ for (auto const &entry : M_procs) {
EntityGraphNode *n = entry.value;
Entity *e = n->entity;
DeclInfo *decl = decl_info_of_entity(e);
GB_ASSERT(decl != nullptr);
- for (Entity *dep : decl->deps) {
+ FOR_PTR_SET(dep, decl->deps) {
+ GB_ASSERT(dep != nullptr);
if (dep->flags & EntityFlag_Field) {
continue;
}
- GB_ASSERT(dep != nullptr);
- if (is_entity_a_dependency(dep)) {
- EntityGraphNode *m = map_must_get(&M, dep);
- entity_graph_node_set_add(&n->succ, m);
- entity_graph_node_set_add(&m->pred, n);
+ if (!is_entity_a_dependency(dep)) {
+ continue;
+ }
+ EntityGraphNode *m = nullptr;
+
+ switch (dep->kind) {
+ case Entity_Procedure: m = map_must_get(&M_procs, dep); break;
+ case Entity_Variable: m = map_must_get(&M_vars, dep); break;
+ default: m = map_must_get(&M_other, dep); break;
}
+ entity_graph_node_set_add(&n->succ, m);
+ entity_graph_node_set_add(&m->pred, n);
}
}
- TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2");
- auto G = array_make<EntityGraphNode *>(allocator, 0, M.count);
+ TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2a (init)");
- for (auto const &m_entry : M) {
- auto *e = m_entry.key;
+ auto G = array_make<EntityGraphNode *>(arena_allocator(arena), 0, M_procs.count + M_vars.count + M_other.count);
+
+ TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2b (procs)");
+
+ for (auto const &m_entry : M_procs) {
EntityGraphNode *n = m_entry.value;
- if (e->kind == Entity_Procedure) {
- // Connect each pred 'p' of 'n' with each succ 's' and from
- // the procedure node
- for (EntityGraphNode *p : n->pred) {
+ // Connect each pred 'p' of 'n' with each succ 's' and from
+ // the procedure node
+ FOR_PTR_SET(p, n->pred) {
+ // Ignore self-cycles
+ if (p == n) {
+ continue;
+ }
+ // Each succ 's' of 'n' becomes a succ of 'p', and
+ // each pred 'p' of 'n' becomes a pred of 's'
+ FOR_PTR_SET(s, n->succ) {
// Ignore self-cycles
- if (p != n) {
- // Each succ 's' of 'n' becomes a succ of 'p', and
- // each pred 'p' of 'n' becomes a pred of 's'
- for (EntityGraphNode *s : n->succ) {
- // Ignore self-cycles
- if (s != n) {
- if (p->entity->kind == Entity_Procedure &&
- s->entity->kind == Entity_Procedure) {
- // NOTE(bill, 2020-11-15): Only care about variable initialization ordering
- // TODO(bill): This is probably wrong!!!!
- continue;
- }
- // IMPORTANT NOTE/TODO(bill, 2020-11-15): These three calls take the majority of the
- // the time to process
- entity_graph_node_set_add(&p->succ, s);
- entity_graph_node_set_add(&s->pred, p);
- // Remove edge to 'n'
- entity_graph_node_set_remove(&s->pred, n);
- }
- }
-
- // Remove edge to 'n'
- entity_graph_node_set_remove(&p->succ, n);
+ if (s == n) {
+ continue;
}
+ if (p->entity->kind == Entity_Procedure &&
+ s->entity->kind == Entity_Procedure) {
+ // NOTE(bill, 2020-11-15): Only care about variable initialization ordering
+ // TODO(bill): This is probably wrong!!!!
+ continue;
+ }
+ // IMPORTANT NOTE/TODO(bill, 2020-11-15): These three calls take the majority of the
+ // the time to process
+ entity_graph_node_set_add(&p->succ, s);
+ entity_graph_node_set_add(&s->pred, p);
+ // Remove edge to 'n'
+ entity_graph_node_set_remove(&s->pred, n);
}
- } else if (e->kind == Entity_Variable) {
- array_add(&G, n);
+
+ // Remove edge to 'n'
+ entity_graph_node_set_remove(&p->succ, n);
}
}
+ TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2c (vars)");
+
+ for (auto const &m_entry : M_vars) {
+ EntityGraphNode *n = m_entry.value;
+ array_add(&G, n);
+ }
+
TIME_SECTION("generate_entity_dependency_graph: Dependency Count Checker");
for_array(i, G) {
EntityGraphNode *n = G[i];
@@ -3082,19 +3227,17 @@ gb_internal Type *find_type_in_pkg(CheckerInfo *info, String const &pkg, String
return e->type;
}
-gb_internal CheckerTypePath *new_checker_type_path() {
- gbAllocator a = heap_allocator();
- auto *tp = gb_alloc_item(a, CheckerTypePath);
- array_init(tp, a, 0, 16);
+gb_internal CheckerTypePath *new_checker_type_path(gbAllocator allocator) {
+ auto *tp = gb_alloc_item(allocator, CheckerTypePath);
+ array_init(tp, allocator, 0, 16);
return tp;
}
-gb_internal void destroy_checker_type_path(CheckerTypePath *tp) {
+gb_internal void destroy_checker_type_path(CheckerTypePath *tp, gbAllocator allocator) {
array_free(tp);
- gb_free(heap_allocator(), tp);
+ gb_free(allocator, tp);
}
-
gb_internal void check_type_path_push(CheckerContext *c, Entity *e) {
GB_ASSERT(c->type_path != nullptr);
GB_ASSERT(e != nullptr);
@@ -3266,12 +3409,20 @@ gb_internal void init_core_map_type(Checker *c) {
t_raw_map_ptr = alloc_type_pointer(t_raw_map);
}
+gb_internal void init_core_objc_c(Checker *c) {
+ if (build_context.metrics.os == TargetOs_darwin) {
+ t_objc_super = find_core_type(c, str_lit("objc_super"));
+ t_objc_super_ptr = alloc_type_pointer(t_objc_super);
+ }
+}
+
gb_internal void init_preload(Checker *c) {
init_core_type_info(c);
init_mem_allocator(c);
init_core_context(c);
init_core_source_code_location(c);
init_core_map_type(c);
+ init_core_objc_c(c);
}
gb_internal ExactValue check_decl_attribute_value(CheckerContext *c, Ast *value) {
@@ -3430,7 +3581,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
return true;
} else if (name == "test") {
if (value != nullptr) {
- error(value, "'%.*s' expects no parameter, or a string literal containing \"file\" or \"package\"", LIT(name));
+ error(value, "Expected no value for '%.*s'", LIT(name));
}
ac->test = true;
return true;
@@ -3478,13 +3629,13 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
return true;
} else if (name == "init") {
if (value != nullptr) {
- error(value, "'%.*s' expects no parameter, or a string literal containing \"file\" or \"package\"", LIT(name));
+ error(value, "Expected no value for '%.*s'", LIT(name));
}
ac->init = true;
return true;
} else if (name == "fini") {
if (value != nullptr) {
- error(value, "'%.*s' expects no parameter, or a string literal containing \"file\" or \"package\"", LIT(name));
+ error(value, "Expected no value for '%.*s'", LIT(name));
}
ac->fini = true;
return true;
@@ -4849,7 +5000,7 @@ gb_internal void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d)
}
gb_internal void check_all_global_entities(Checker *c) {
- in_single_threaded_checker_stage = true;
+ in_single_threaded_checker_stage.store(true, std::memory_order_relaxed);
// NOTE(bill): This must be single threaded
// Don't bother trying
@@ -4871,7 +5022,7 @@ gb_internal void check_all_global_entities(Checker *c) {
}
}
- in_single_threaded_checker_stage = false;
+ in_single_threaded_checker_stage.store(false, std::memory_order_relaxed);
}
@@ -4960,26 +5111,22 @@ gb_internal void add_import_dependency_node(Checker *c, Ast *decl, PtrMap<AstPac
error(token, "Unable to find package: %.*s", LIT(path));
exit_with_errors();
}
- AstPackage *pkg = *found;
- GB_ASSERT(pkg->scope != nullptr);
+ AstPackage *child_pkg = *found;
+ GB_ASSERT(child_pkg->scope != nullptr);
- id->package = pkg;
+ id->package = child_pkg;
- ImportGraphNode **found_node = nullptr;
- ImportGraphNode *m = nullptr;
- ImportGraphNode *n = nullptr;
-
- found_node = map_get(M, pkg);
+ ImportGraphNode **found_node = map_get(M, child_pkg);
GB_ASSERT(found_node != nullptr);
- m = *found_node;
+ ImportGraphNode *child = *found_node;
found_node = map_get(M, parent_pkg);
GB_ASSERT(found_node != nullptr);
- n = *found_node;
+ ImportGraphNode *parent = *found_node;
- import_graph_node_set_add(&n->succ, m);
- import_graph_node_set_add(&m->pred, n);
- ptr_set_add(&m->scope->imported, n->scope);
+ import_graph_node_set_add(&parent->succ, child);
+ import_graph_node_set_add(&child->pred, parent);
+ ptr_set_add(&parent->scope->imported, child->scope);
case_end;
case_ast_node(ws, WhenStmt, decl);
@@ -5009,14 +5156,14 @@ gb_internal void add_import_dependency_node(Checker *c, Ast *decl, PtrMap<AstPac
}
}
-gb_internal Array<ImportGraphNode *> generate_import_dependency_graph(Checker *c) {
+gb_internal Array<ImportGraphNode *> generate_import_dependency_graph(Checker *c, gbAllocator allocator) {
PtrMap<AstPackage *, ImportGraphNode *> M = {};
map_init(&M, 2*c->parser->packages.count);
defer (map_destroy(&M));
for_array(i, c->parser->packages) {
AstPackage *pkg = c->parser->packages[i];
- ImportGraphNode *n = import_graph_node_create(heap_allocator(), pkg);
+ ImportGraphNode *n = import_graph_node_create(allocator, pkg);
map_set(&M, pkg, n);
}
@@ -5033,7 +5180,7 @@ gb_internal Array<ImportGraphNode *> generate_import_dependency_graph(Checker *c
}
Array<ImportGraphNode *> G = {};
- array_init(&G, heap_allocator(), 0, M.count);
+ array_init(&G, allocator, 0, M.count);
isize i = 0;
for (auto const &entry : M) {
@@ -5052,7 +5199,7 @@ struct ImportPathItem {
Ast * decl;
};
-gb_internal Array<ImportPathItem> find_import_path(Checker *c, AstPackage *start, AstPackage *end, PtrSet<AstPackage *> *visited) {
+gb_internal Array<ImportPathItem> find_import_path(Checker *c, AstPackage *start, AstPackage *end, PtrSet<AstPackage *> *visited, gbAllocator allocator) {
Array<ImportPathItem> empty_path = {};
if (ptr_set_update(visited, start)) {
@@ -5086,11 +5233,11 @@ gb_internal Array<ImportPathItem> find_import_path(Checker *c, AstPackage *start
ImportPathItem item = {pkg, decl};
if (pkg == end) {
- auto path = array_make<ImportPathItem>(heap_allocator());
+ auto path = array_make<ImportPathItem>(allocator);
array_add(&path, item);
return path;
}
- auto next_path = find_import_path(c, pkg, end, visited);
+ auto next_path = find_import_path(c, pkg, end, visited, allocator);
if (next_path.count > 0) {
array_add(&next_path, item);
return next_path;
@@ -5170,9 +5317,10 @@ gb_internal void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
GB_ASSERT(scope->flags&ScopeFlag_Pkg);
- if (ptr_set_update(&parent_scope->imported, scope)) {
- // error(token, "Multiple import of the same file within this scope");
- }
+ ptr_set_add(&parent_scope->imported, scope);
+ // if (ptr_set_update(&parent_scope->imported, scope)) {
+ // // error(token, "Multiple import of the same file within this scope");
+ // }
String import_name = path_to_entity_name(id->import_name.string, id->fullpath, false);
if (is_blank_ident(import_name)) {
@@ -5694,14 +5842,9 @@ gb_internal void check_export_entities(Checker *c) {
}
gb_internal void check_import_entities(Checker *c) {
- Array<ImportGraphNode *> dep_graph = generate_import_dependency_graph(c);
- defer ({
- for_array(i, dep_graph) {
- import_graph_node_destroy(dep_graph[i], heap_allocator());
- }
- array_free(&dep_graph);
- });
+ TEMPORARY_ALLOCATOR_GUARD();
+ Array<ImportGraphNode *> dep_graph = generate_import_dependency_graph(c, temporary_allocator());
TIME_SECTION("check_import_entities - sort packages");
// NOTE(bill): Priority queue
@@ -5711,8 +5854,7 @@ gb_internal void check_import_entities(Checker *c) {
defer (ptr_set_destroy(&emitted));
Array<ImportGraphNode *> package_order = {};
- array_init(&package_order, heap_allocator(), 0, c->parser->packages.count);
- defer (array_free(&package_order));
+ array_init(&package_order, temporary_allocator(), 0, c->parser->packages.count);
while (pq.queue.count > 0) {
ImportGraphNode *n = priority_queue_pop(&pq);
@@ -5720,11 +5862,12 @@ gb_internal void check_import_entities(Checker *c) {
AstPackage *pkg = n->pkg;
if (n->dep_count > 0) {
+ TEMPORARY_ALLOCATOR_GUARD();
+
PtrSet<AstPackage *> visited = {};
defer (ptr_set_destroy(&visited));
- auto path = find_import_path(c, pkg, pkg, &visited);
- defer (array_free(&path));
+ auto path = find_import_path(c, pkg, pkg, &visited, temporary_allocator());
if (path.count > 1) {
ImportPathItem item = path[path.count-1];
@@ -5739,7 +5882,7 @@ gb_internal void check_import_entities(Checker *c) {
}
}
- for (ImportGraphNode *p : n->pred) {
+ FOR_PTR_SET(p, n->pred) {
p->dep_count = gb_max(p->dep_count-1, 0);
priority_queue_fix(&pq, p->index);
}
@@ -5842,9 +5985,9 @@ gb_internal void check_import_entities(Checker *c) {
}
-gb_internal Array<Entity *> find_entity_path(Entity *start, Entity *end, PtrSet<Entity *> *visited = nullptr);
+gb_internal Array<Entity *> find_entity_path(Entity *start, Entity *end, gbAllocator allocator, PtrSet<Entity *> *visited = nullptr);
-gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSet<Entity *> *visited, Array<Entity *> *path_) {
+gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, gbAllocator allocator, PtrSet<Entity *> *visited, Array<Entity *> *path_) {
GB_ASSERT(path_ != nullptr);
if (tuple == nullptr) {
return false;
@@ -5856,14 +5999,15 @@ gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSet<Entity
if (var_decl == nullptr) {
continue;
}
- for (Entity *dep : var_decl->deps) {
+
+ FOR_PTR_SET(dep, var_decl->deps) {
if (dep == end) {
- auto path = array_make<Entity *>(heap_allocator());
+ auto path = array_make<Entity *>(allocator);
array_add(&path, dep);
*path_ = path;
return true;
}
- auto next_path = find_entity_path(dep, end, visited);
+ auto next_path = find_entity_path(dep, end, allocator, visited);
if (next_path.count > 0) {
array_add(&next_path, dep);
*path_ = next_path;
@@ -5875,7 +6019,7 @@ gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSet<Entity
return false;
}
-gb_internal Array<Entity *> find_entity_path(Entity *start, Entity *end, PtrSet<Entity *> *visited) {
+gb_internal Array<Entity *> find_entity_path(Entity *start, Entity *end, gbAllocator allocator, PtrSet<Entity *> *visited) {
PtrSet<Entity *> visited_ = {};
bool made_visited = false;
if (visited == nullptr) {
@@ -5899,20 +6043,20 @@ gb_internal Array<Entity *> find_entity_path(Entity *start, Entity *end, PtrSet<
GB_ASSERT(t->kind == Type_Proc);
Array<Entity *> path = {};
- if (find_entity_path_tuple(t->Proc.params, end, visited, &path)) {
+ if (find_entity_path_tuple(t->Proc.params, end, allocator, visited, &path)) {
return path;
}
- if (find_entity_path_tuple(t->Proc.results, end, visited, &path)) {
+ if (find_entity_path_tuple(t->Proc.results, end, allocator, visited, &path)) {
return path;
}
} else {
- for (Entity *dep : decl->deps) {
+ FOR_PTR_SET(dep, decl->deps) {
if (dep == end) {
- auto path = array_make<Entity *>(heap_allocator());
+ auto path = array_make<Entity *>(allocator);
array_add(&path, dep);
return path;
}
- auto next_path = find_entity_path(dep, end, visited);
+ auto next_path = find_entity_path(dep, end, allocator, visited);
if (next_path.count > 0) {
array_add(&next_path, dep);
return next_path;
@@ -5928,13 +6072,10 @@ gb_internal void calculate_global_init_order(Checker *c) {
CheckerInfo *info = &c->info;
TIME_SECTION("calculate_global_init_order: generate entity dependency graph");
- Array<EntityGraphNode *> dep_graph = generate_entity_dependency_graph(info, heap_allocator());
- defer ({
- for_array(i, dep_graph) {
- entity_graph_node_destroy(dep_graph[i], heap_allocator());
- }
- array_free(&dep_graph);
- });
+ Arena *temporary_arena = get_arena(ThreadArena_Temporary);
+ ArenaTempGuard temporary_arena_guard(temporary_arena);
+
+ Array<EntityGraphNode *> dep_graph = generate_entity_dependency_graph(info, temporary_arena);
TIME_SECTION("calculate_global_init_order: priority queue create");
// NOTE(bill): Priority queue
@@ -5949,8 +6090,8 @@ gb_internal void calculate_global_init_order(Checker *c) {
Entity *e = n->entity;
if (n->dep_count > 0) {
- auto path = find_entity_path(e, e);
- defer (array_free(&path));
+ TEMPORARY_ALLOCATOR_GUARD();
+ auto path = find_entity_path(e, e, temporary_allocator());
if (path.count > 0) {
Entity *e = path[0];
@@ -5963,7 +6104,7 @@ gb_internal void calculate_global_init_order(Checker *c) {
}
}
- for (EntityGraphNode *p : n->pred) {
+ FOR_PTR_SET(p, n->pred) {
p->dep_count -= 1;
p->dep_count = gb_max(p->dep_count, 0);
priority_queue_fix(&pq, p->index);
@@ -6067,7 +6208,7 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u
switch (pi->decl->proc_checked_state.load()) {
case ProcCheckedState_InProgress:
if (e) {
- GB_ASSERT(global_procedure_body_in_worker_queue.load());
+ GB_ASSERT(global_procedure_body_in_worker_queue.load() != 0);
}
return false;
case ProcCheckedState_Checked:
@@ -6156,7 +6297,7 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u
add_untyped_expressions(&c->info, ctx.untyped);
rw_mutex_shared_lock(&ctx.decl->deps_mutex);
- for (Entity *dep : ctx.decl->deps) {
+ FOR_PTR_SET(dep, ctx.decl->deps) {
if (dep && dep->kind == Entity_Procedure &&
(dep->flags & EntityFlag_ProcBodyChecked) == 0) {
check_procedure_later_from_entity(c, dep, NULL);
@@ -6185,8 +6326,10 @@ gb_internal void check_unchecked_bodies(Checker *c) {
// use the `procs_to_check` array
global_procedure_body_in_worker_queue = false;
- for (Entity *e : c->info.minimum_dependency_set) {
- check_procedure_later_from_entity(c, e, "check_unchecked_bodies");
+ for (Entity *e : c->info.entities) {
+ if (e->min_dep_count.load(std::memory_order_relaxed) > 0) {
+ check_procedure_later_from_entity(c, e, "check_unchecked_bodies");
+ }
}
if (!global_procedure_body_in_worker_queue) {
@@ -6209,8 +6352,9 @@ gb_internal void check_safety_all_procedures_for_unchecked(Checker *c) {
defer (map_destroy(&untyped));
- for_array(i, c->info.all_procedures) {
- ProcInfo *pi = c->info.all_procedures[i];
+ array_reserve(&c->info.all_procedures, c->info.all_procedures_queue.count.load());
+
+ for (ProcInfo *pi = nullptr; mpsc_dequeue(&c->info.all_procedures_queue, &pi); /**/) {
GB_ASSERT(pi != nullptr);
GB_ASSERT(pi->decl != nullptr);
Entity *e = pi->decl->entity;
@@ -6225,6 +6369,8 @@ gb_internal void check_safety_all_procedures_for_unchecked(Checker *c) {
consume_proc_info(c, pi, &untyped);
}
}
+
+ array_add(&c->info.all_procedures, pi);
}
}
@@ -6319,7 +6465,7 @@ gb_internal WORKER_TASK_PROC(check_proc_info_worker_proc) {
gb_internal void check_init_worker_data(Checker *c) {
u32 thread_count = cast(u32)global_thread_pool.threads.count;
- check_procedure_bodies_worker_data = gb_alloc_array(permanent_allocator(), CheckProcedureBodyWorkerData, thread_count);
+ check_procedure_bodies_worker_data = permanent_alloc_array<CheckProcedureBodyWorkerData>(thread_count);
for (isize i = 0; i < thread_count; i++) {
check_procedure_bodies_worker_data[i].c = c;
@@ -6381,7 +6527,7 @@ gb_internal Type *tuple_to_pointers(Type *ot) {
Type *t = alloc_type_tuple();
- t->Tuple.variables = slice_make<Entity *>(heap_allocator(), ot->Tuple.variables.count);
+ t->Tuple.variables = permanent_slice_make<Entity *>(ot->Tuple.variables.count);
Scope *scope = nullptr;
for_array(i, t->Tuple.variables) {
@@ -6887,9 +7033,11 @@ gb_internal void check_objc_context_provider_procedures(Checker *c) {
}
}
-gb_internal void check_unique_package_names(Checker *c) {
+gb_internal bool check_unique_package_names(Checker *c) {
ERROR_BLOCK();
+ bool ok = true;
+
StringMap<AstPackage *> pkgs = {}; // Key: package name
string_map_init(&pkgs, 2*c->info.packages.count);
defer (string_map_destroy(&pkgs));
@@ -6914,6 +7062,7 @@ gb_internal void check_unique_package_names(Checker *c) {
continue;
}
+ ok = false;
begin_error_block();
error(curr, "Duplicate declaration of 'package %.*s'", LIT(name));
@@ -6936,6 +7085,8 @@ gb_internal void check_unique_package_names(Checker *c) {
end_error_block();
}
+
+ return ok;
}
gb_internal void check_add_entities_from_queues(Checker *c) {
@@ -6960,6 +7111,7 @@ gb_internal void check_merge_queues_into_arrays(Checker *c) {
}
check_add_entities_from_queues(c);
check_add_definitions_from_queues(c);
+ thread_pool_wait();
}
gb_internal GB_COMPARE_PROC(init_procedures_cmp) {
@@ -7014,17 +7166,23 @@ gb_internal void check_sort_init_and_fini_procedures(Checker *c) {
}
gb_internal void add_type_info_for_type_definitions(Checker *c) {
- for_array(i, c->info.definitions) {
- Entity *e = c->info.definitions[i];
+ for (Entity *e : c->info.definitions) {
if (e->kind == Entity_TypeName && e->type != nullptr && is_type_typed(e->type)) {
+ #if 0
i64 align = type_align_of(e->type);
- if (align > 0 && ptr_set_exists(&c->info.minimum_dependency_set, e)) {
+ if (align > 0 && e->min_dep_count.load(std::memory_order_relaxed) > 0) {
add_type_info_type(&c->builtin_ctx, e->type);
}
+ #else
+ if (e->min_dep_count.load(std::memory_order_relaxed) > 0) {
+ add_type_info_type(&c->builtin_ctx, e->type);
+ }
+ #endif
}
}
}
+#if 0
gb_internal void check_walk_all_dependencies(DeclInfo *decl) {
if (decl == nullptr) {
return;
@@ -7046,9 +7204,116 @@ gb_internal void check_update_dependency_tree_for_procedures(Checker *c) {
check_walk_all_dependencies(decl);
}
}
+#else
+gb_internal void check_walk_all_dependencies(DeclInfo *decl);
+
+gb_internal WORKER_TASK_PROC(check_walk_all_dependencies_worker_proc) {
+ if (data == nullptr) {
+ return 0;
+ }
+ DeclInfo *decl = cast(DeclInfo *)data;
+
+ for (DeclInfo *child = decl->next_child; child != nullptr; child = child->next_sibling) {
+ thread_pool_add_task(check_walk_all_dependencies_worker_proc, child);
+ check_walk_all_dependencies(child);
+ }
+
+ add_deps_from_child_to_parent(decl);
+ return 0;
+}
+
+gb_internal void check_walk_all_dependencies(DeclInfo *decl) {
+ if (decl != nullptr) {
+ thread_pool_add_task(check_walk_all_dependencies_worker_proc, decl);
+ }
+}
+
+gb_internal void check_update_dependency_tree_for_procedures(Checker *c) {
+ mutex_lock(&c->nested_proc_lits_mutex);
+ for (DeclInfo *decl : c->nested_proc_lits) {
+ check_walk_all_dependencies(decl);
+ }
+ mutex_unlock(&c->nested_proc_lits_mutex);
+ for (Entity *e : c->info.entities) {
+ DeclInfo *decl = e->decl_info;
+ check_walk_all_dependencies(decl);
+ }
+
+ thread_pool_wait();
+}
+#endif
+
+gb_internal WORKER_TASK_PROC(check_scope_usage_file_worker) {
+ Checker *c = global_checker_ptr.load(std::memory_order_relaxed);
+ AstFile *f = cast(AstFile *)data;
+ u64 vet_flags = ast_file_vet_flags(f);
+ check_scope_usage(c, f->scope, vet_flags);
+ return 0;
+}
+
+gb_internal WORKER_TASK_PROC(check_scope_usage_pkg_worker) {
+ Checker *c = global_checker_ptr.load(std::memory_order_relaxed);
+ AstPackage *pkg = cast(AstPackage *)data;
+ check_scope_usage_internal(c, pkg->scope, 0, true);
+ return 0;
+}
+
+
+
+gb_internal void check_all_scope_usages(Checker *c) {
+ for (auto const &entry : c->info.files) {
+ AstFile *f = entry.value;
+ thread_pool_add_task(check_scope_usage_file_worker, f);
+ }
+ for (auto const &entry : c->info.packages) {
+ AstPackage *pkg = entry.value;
+ thread_pool_add_task(check_scope_usage_pkg_worker, pkg);
+ }
+
+ thread_pool_wait();
+}
+
+
+gb_internal void check_for_type_cycles(Checker *c) {
+ // NOTE(bill): Check for illegal cyclic type declarations
+ for_array(i, c->info.definitions) {
+ Entity *e = c->info.definitions[i];
+ if (e->kind != Entity_TypeName) {
+ continue;
+ }
+ if (e->type != nullptr && is_type_typed(e->type)) {
+ if (e->TypeName.is_type_alias) {
+ // Ignore for the time being
+ } else {
+ (void)type_align_of(e->type);
+ }
+ }
+ }
+}
+
+gb_internal void check_for_inline_cycles(Checker *c) {
+ for_array(i, c->info.definitions) {
+ Entity *e = c->info.definitions[i];
+ if (e->kind != Entity_Procedure) {
+ continue;
+ }
+ DeclInfo *decl = e->decl_info;
+ ast_node(pl, ProcLit, decl->proc_lit);
+ if (pl->inlining == ProcInlining_inline) {
+ FOR_PTR_SET(dep, decl->deps) {
+ if (dep == e) {
+ error(e->token, "Cannot inline recursive procedure '%.*s'", LIT(e->token.string));
+ break;
+ }
+ }
+ }
+ }
+}
gb_internal void check_parsed_files(Checker *c) {
+ global_checker_ptr.store(c, std::memory_order_relaxed);
+
TIME_SECTION("map full filepaths to scope");
add_type_info_type(&c->builtin_ctx, t_invalid);
@@ -7112,16 +7377,9 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("add entities from procedure bodies");
check_merge_queues_into_arrays(c);
- TIME_SECTION("check scope usage");
- for (auto const &entry : c->info.files) {
- AstFile *f = entry.value;
- u64 vet_flags = ast_file_vet_flags(f);
- check_scope_usage(c, f->scope, vet_flags);
- }
- for (auto const &entry : c->info.packages) {
- AstPackage *pkg = entry.value;
- check_scope_usage_internal(c, pkg->scope, 0, true);
- }
+ TIME_SECTION("check all scope usages");
+ check_all_scope_usages(c);
+
TIME_SECTION("add basic type information");
// Add "Basic" type information
@@ -7134,29 +7392,11 @@ gb_internal void check_parsed_files(Checker *c) {
}
check_merge_queues_into_arrays(c);
- TIME_SECTION("check for type cycles and inline cycles");
- // NOTE(bill): Check for illegal cyclic type declarations
- for_array(i, c->info.definitions) {
- Entity *e = c->info.definitions[i];
- if (e->kind == Entity_TypeName && e->type != nullptr && is_type_typed(e->type)) {
- if (e->TypeName.is_type_alias) {
- // Ignore for the time being
- } else {
- (void)type_align_of(e->type);
- }
- } else if (e->kind == Entity_Procedure) {
- DeclInfo *decl = e->decl_info;
- ast_node(pl, ProcLit, decl->proc_lit);
- if (pl->inlining == ProcInlining_inline) {
- for (Entity *dep : decl->deps) {
- if (dep == e) {
- error(e->token, "Cannot inline recursive procedure '%.*s'", LIT(e->token.string));
- break;
- }
- }
- }
- }
- }
+ TIME_SECTION("check for type cycles");
+ check_for_type_cycles(c);
+
+ TIME_SECTION("check for inline cycles");
+ check_for_inline_cycles(c);
TIME_SECTION("check deferred procedures");
check_deferred_procedures(c);
@@ -7181,11 +7421,9 @@ gb_internal void check_parsed_files(Checker *c) {
check_unchecked_bodies(c);
TIME_SECTION("check #soa types");
-
check_merge_queues_into_arrays(c);
- thread_pool_wait();
- TIME_SECTION("update minimum dependency set");
+ TIME_SECTION("update minimum dependency set again");
generate_minimum_dependency_set_internal(c, c->info.entry_point);
// NOTE(laytan): has to be ran after generate_minimum_dependency_set,
@@ -7231,7 +7469,7 @@ gb_internal void check_parsed_files(Checker *c) {
debugf("Total Procedure Bodies Checked: %td\n", total_bodies_checked.load(std::memory_order_relaxed));
TIME_SECTION("check unique package names");
- check_unique_package_names(c);
+ bool package_names_are_unique = check_unique_package_names(c);
TIME_SECTION("sanity checks");
check_merge_queues_into_arrays(c);
@@ -7250,7 +7488,6 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("add untyped expression values");
- // Add untyped expression values
for (UntypedExprInfo u = {}; mpsc_dequeue(&c->global_untyped_queue, &u); /**/) {
GB_ASSERT(u.expr != nullptr && u.info != nullptr);
if (is_type_typed(u.info->type)) {
@@ -7261,9 +7498,10 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("initialize and check for collisions in type info array");
{
+ TEMPORARY_ALLOCATOR_GUARD();
+
Array<TypeInfoPair> type_info_types; // sorted after filled
- array_init(&type_info_types, heap_allocator());
- defer (array_free(&type_info_types));
+ array_init(&type_info_types, temporary_allocator());
for (auto const &tt : c->info.min_dep_type_info_set) {
array_add(&type_info_types, tt);
@@ -7288,7 +7526,8 @@ gb_internal void check_parsed_files(Checker *c) {
c->info.type_info_types_hash_map[index] = tt;
bool exists = map_set_if_not_previously_exists(&c->info.min_dep_type_info_index_map, tt.hash, index);
- if (exists) {
+ // Because we've already written a nice error about a duplicate package declaration, skip this panic if the package names aren't unique.
+ if (package_names_are_unique && exists) {
for (auto const &entry : c->info.min_dep_type_info_index_map) {
if (entry.key != tt.hash) {
continue;