Improve check_struct_fields performance; use CheckerTypePath free list

This commit is contained in:
gingerBill
2026-03-17 11:42:03 +00:00
parent 04cb889aed
commit b19e89578f
5 changed files with 76 additions and 29 deletions

View File

@@ -1329,7 +1329,7 @@ gb_internal bool polymorphic_assign_index(Type **gt_, i64 *dst_count, i64 source
Type *gt = *gt_;
GB_ASSERT(gt->kind == Type_Generic);
Entity *e = scope_lookup(gt->Generic.scope, gt->Generic.interned_name);
Entity *e = scope_lookup(gt->Generic.scope, gt->Generic.interned_name, 0);
GB_ASSERT(e != nullptr);
if (e->kind == Entity_TypeName) {
*gt_ = nullptr;
@@ -1430,7 +1430,7 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T
if (poly->Array.generic_count != nullptr) {
Type *gt = poly->Array.generic_count;
GB_ASSERT(gt->kind == Type_Generic);
Entity *e = scope_lookup(gt->Generic.scope, gt->Generic.interned_name);
Entity *e = scope_lookup(gt->Generic.scope, gt->Generic.interned_name, 0);
GB_ASSERT(e != nullptr);
if (e->kind == Entity_TypeName) {
Type *index = source->EnumeratedArray.index;
@@ -1772,7 +1772,7 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam
o->expr = n;
auto name = n->Ident.token.string;
Entity *e = scope_lookup(c->scope, n->Ident.interned);
Entity *e = scope_lookup(c->scope, n->Ident.interned, n->Ident.hash);
if (e == nullptr) {
if (is_blank_ident(name)) {
error(n, "'_' cannot be used as a value");
@@ -5459,7 +5459,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *
}
} else */if (node->kind == Ast_Ident) {
String name = node->Ident.token.string;
return scope_lookup(c->scope, node->Ident.interned);
return scope_lookup(c->scope, node->Ident.interned, node->Ident.hash);
} else if (!ident_only) if (node->kind == Ast_SelectorExpr) {
ast_node(se, SelectorExpr, node);
if (se->token.kind == Token_ArrowRight) {
@@ -5481,7 +5481,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *
if (op_expr->kind == Ast_Ident) {
String op_name = op_expr->Ident.token.string;
Entity *e = scope_lookup(c->scope,op_expr->Ident.interned);
Entity *e = scope_lookup(c->scope, op_expr->Ident.interned, op_expr->Ident.hash);
if (e == nullptr) {
return nullptr;
}
@@ -5578,7 +5578,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
if (op_expr->kind == Ast_Ident) {
String op_name = op_expr->Ident.token.string;
Entity *e = scope_lookup(c->scope, op_expr->Ident.interned);
Entity *e = scope_lookup(c->scope, op_expr->Ident.interned, op_expr->Ident.hash);
add_entity_use(c, op_expr, e);
expr_entity = e;
@@ -6001,7 +6001,7 @@ gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = fals
return true;
}
} else {
Entity *e = scope_lookup(s, i->interned);
Entity *e = scope_lookup(s, i->interned, i->hash);
if (e != nullptr) {
if (out_scope) *out_scope = e->scope;
return true;

View File

@@ -105,9 +105,6 @@ gb_internal bool does_field_type_allow_using(Type *t) {
gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields, String **tags, Slice<Ast *> const &params,
isize init_field_capacity, Type *struct_type, String context) {
auto fields_array = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
auto tags_array = array_make<String>(heap_allocator(), 0, init_field_capacity);
GB_ASSERT(node->kind == Ast_StructType);
GB_ASSERT(struct_type->kind == Type_Struct);
@@ -120,6 +117,12 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entit
}
}
init_field_capacity = gb_max(init_field_capacity, variable_count);
auto fields_array = array_make<Entity *>(permanent_allocator(), 0, init_field_capacity);
auto tags_array = array_make<String>(permanent_allocator(), 0, init_field_capacity);
defer (GB_ASSERT(fields_array.count == init_field_capacity));
// Allocate all at once
Entity *entities_to_use = permanent_alloc_array<Entity>(variable_count);
isize entities_to_use_index = 0;
@@ -175,7 +178,10 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entit
// Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
Entity *field = &entities_to_use[entities_to_use_index++];
INTERNAL_ENTITY_INIT(field, Entity_Variable, ctx->scope, name_token, type);
field->state = EntityState_Unresolved;
field->interned_name.store(name->Ident.interned);
field->interned_name_hash.store(name->Ident.hash);
field->flags |= EntityFlag_Field;
if (is_using) field->flags |= EntityFlag_Using;
field->Variable.field_index = field_src_index;
@@ -976,6 +982,10 @@ gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *nam
Entity *e = &entities_to_use[entities_to_use_index++];
Token token = ident->Ident.token;
INTERNAL_ENTITY_INIT(e, Entity_Constant, ctx->scope, token, constant_type);
e->interned_name.store(ident->Ident.interned);
e->interned_name_hash.store(ident->Ident.hash);
e->Constant.value = iota;
e->identifier = ident;
e->flags |= EntityFlag_Visited;
@@ -1519,7 +1529,7 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special
// NOTE(bill, 2018-12-14): This is needed to override polymorphic named constants in types
if (st->kind == Type_Generic && t_e->kind == Entity_Constant) {
Entity *e = scope_lookup(st->Generic.scope, st->Generic.interned_name);
Entity *e = scope_lookup(st->Generic.scope, st->Generic.interned_name, 0);
GB_ASSERT(e != nullptr);
if (modify_type) {
e->kind = Entity_Constant;
@@ -1572,7 +1582,7 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special
// NOTE(bill, 2018-12-14): This is needed to override polymorphic named constants in types
if (st->kind == Type_Generic && t_e->kind == Entity_Constant) {
Entity *e = scope_lookup(st->Generic.scope, st->Generic.interned_name);
Entity *e = scope_lookup(st->Generic.scope, st->Generic.interned_name, 0);
GB_ASSERT(e != nullptr);
if (modify_type) {
e->kind = Entity_Constant;

View File

@@ -667,7 +667,8 @@ gb_internal bool check_vet_shadowing(Checker *c, Entity *e, VettedEntity *ve) {
return false;
}
Entity *shadowed = scope_lookup(parent, entity_interned_name(e));
auto interned = entity_interned_name(e);
Entity *shadowed = scope_lookup(parent, interned, e->interned_name_hash.load());
if (shadowed == nullptr) {
return false;
}
@@ -949,9 +950,10 @@ gb_internal AstPackage *try_get_core_package(CheckerInfo *info, String name) {
gb_internal void add_package_dependency(CheckerContext *c, char const *package_name, char const *name, bool required=false) {
String n = make_string_c(name);
InternedString key = string_interner_insert(n);
u32 hash = 0;
InternedString key = string_interner_insert(n, 0, &hash);
AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name));
Entity *e = scope_lookup(p->scope, key);
Entity *e = scope_lookup(p->scope, key, hash);
GB_ASSERT_MSG(e != nullptr, "%s", name);
GB_ASSERT(c->decl != nullptr);
e->flags |= EntityFlag_Used;
@@ -963,9 +965,10 @@ gb_internal void add_package_dependency(CheckerContext *c, char const *package_n
gb_internal void try_to_add_package_dependency(CheckerContext *c, char const *package_name, char const *name) {
String n = make_string_c(name);
InternedString key = string_interner_insert(n);
u32 hash = 0;
InternedString key = string_interner_insert(n, 0, &hash);
AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name));
Entity *e = scope_lookup(p->scope, key);
Entity *e = scope_lookup(p->scope, key, hash);
if (e == nullptr) {
return;
}
@@ -2756,7 +2759,9 @@ gb_internal void add_dependency_to_set_threaded(Checker *c, Entity *entity) {
gb_internal void force_add_dependency_entity(Checker *c, Scope *scope, String const &name) {
Entity *e = scope_lookup(scope, string_interner_insert(name));
u32 hash = 0;
auto interned = string_interner_insert(name, 0, &hash);
Entity *e = scope_lookup(scope, interned, hash);
if (e == nullptr) {
return;
}
@@ -3277,16 +3282,48 @@ gb_internal Type *find_type_in_pkg(CheckerInfo *info, String const &pkg, String
return e->type;
}
struct CheckerTypePathStore {
CheckerTypePath path;
std::atomic<CheckerTypePathStore *> next;
};
gb_internal gb_thread_local std::atomic<CheckerTypePathStore *> checker_type_path_free_list;
gb_internal CheckerTypePath *new_checker_type_path(gbAllocator allocator) {
// TODO(bill): Cache to reuse `CheckerTypePath`
auto *tp = gb_alloc_item(heap_allocator(), CheckerTypePath);
array_init(tp, allocator, 0, 16);
return tp;
// TODO(bill): Cache to reuse `CheckerTypePath
CheckerTypePathStore *tp = nullptr;
for (;;) {
tp = checker_type_path_free_list.load(std::memory_order_acquire);
if (tp == nullptr) {
tp = permanent_alloc_item<CheckerTypePathStore>();
array_init(&tp->path, allocator, 0, 16);
return &tp->path;
}
if (checker_type_path_free_list.compare_exchange_weak(tp, tp->next.load(std::memory_order_acquire), std::memory_order_acquire, std::memory_order_relaxed)) {
tp->next.store(nullptr);
return &tp->path;
}
}
}
gb_internal void destroy_checker_type_path(CheckerTypePath *tp, gbAllocator allocator) {
array_free(tp);
gb_free(allocator, tp);
gb_internal void destroy_checker_type_path(CheckerTypePath *path, gbAllocator allocator) {
auto *tp = cast(CheckerTypePathStore *)path;
array_clear(&tp->path);
for (;;) {
auto *head = checker_type_path_free_list.load(std::memory_order_relaxed);
tp->next.store(head);
if (checker_type_path_free_list.compare_exchange_weak(head, tp, std::memory_order_release, std::memory_order_relaxed)) {
return;
}
}
// array_free(&tp->path);
}
gb_internal void check_type_path_push(CheckerContext *c, Entity *e) {

View File

@@ -883,8 +883,8 @@ gb_internal Entity *entity_of_node(Ast *expr);
// gb_internal Entity *scope_lookup_current(Scope *s, String const &name, u32 hash=0);
gb_internal Entity *scope_lookup (Scope *s, InternedString interned, u32 hash=0);
gb_internal void scope_lookup_parent (Scope *s, InternedString name, Scope **scope_, Entity **entity_, u32 hash=0);
gb_internal Entity *scope_lookup (Scope *s, InternedString interned, u32 hash);
gb_internal void scope_lookup_parent (Scope *s, InternedString name, Scope **scope_, Entity **entity_, u32 hash);
gb_internal Entity *scope_insert (Scope *s, Entity *entity);

View File

@@ -369,13 +369,13 @@ gb_global std::atomic<u64> global_entity_id;
if ((token_).pos.file_id) { \
e_->file = thread_unsafe_get_ast_file_from_id((token_).pos.file_id); \
} \
entity_interned_name(e_); \
} while (0)
gb_internal Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) {
Entity *entity = permanent_alloc_item<Entity>();
INTERNAL_ENTITY_INIT(entity, kind, scope, token, type);
entity_interned_name(entity);
return entity;
}