diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index ea3ca8d3a..4b3e8807e 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2413,13 +2413,14 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o } String name = arg->Ident.token.string; + auto interned = arg->Ident.interned; operand->type = def.type; operand->mode = def.mode; operand->value = def.value; - Entity *found = scope_lookup_current(config_pkg->scope, name); + Entity *found = scope_lookup_current(config_pkg->scope, interned); if (found != nullptr) { if (found->kind != Entity_Constant) { error(arg, "'#config' entity '%.*s' found but expected a constant", LIT(name)); @@ -2804,7 +2805,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } GB_ASSERT(type != nullptr); - String field_name = {}; + InternedString field_name = {}; if (field_arg == nullptr) { error(call, "Expected an identifier for field argument"); @@ -2812,9 +2813,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } if (field_arg->kind == Ast_Ident) { - field_name = field_arg->Ident.token.string; + field_name = field_arg->Ident.interned; } - if (field_name.len == 0) { + if (field_name.value == 0) { error(field_arg, "Expected an identifier for field argument"); return false; } @@ -2847,19 +2848,19 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As ERROR_BLOCK(); gbString type_str = type_to_string_shorthand(type); error(ce->args[0], - "'%s' has no field named '%.*s'", type_str, LIT(field_name)); + "'%s' has no field named '%s'", type_str, field_name.cstring()); gb_string_free(type_str); Type *bt = base_type(type); if (bt->kind == Type_Struct) { - check_did_you_mean_type(field_name, bt->Struct.fields); + check_did_you_mean_type(field_name.string(), bt->Struct.fields); } return false; } if (sel.indirect) { gbString type_str = type_to_string_shorthand(type); error(ce->args[0], - "Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str); + "Field '%s' is embedded via a pointer in '%s'", field_name.cstring(), type_str); gb_string_free(type_str); return false; } @@ -2891,7 +2892,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } GB_ASSERT(type != nullptr); - String field_name = {}; + InternedString field_name = {}; if (field_arg == nullptr) { error(call, "Expected a constant (not-empty) string for field argument"); @@ -2901,9 +2902,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Operand x = {}; check_expr(c, &x, field_arg); if (x.mode == Addressing_Constant && x.value.kind == ExactValue_String) { - field_name = x.value.value_string; + field_name = string_interner_insert(x.value.value_string); } - if (field_name.len == 0) { + if (field_name.value == 0) { error(field_arg, "Expected a constant (non-empty) string for field argument"); return false; } @@ -2921,19 +2922,19 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As ERROR_BLOCK(); gbString type_str = type_to_string_shorthand(type); error(ce->args[0], - "'%s' has no field named '%.*s'", type_str, LIT(field_name)); + "'%s' has no field named '%s'", type_str, field_name.cstring()); gb_string_free(type_str); Type *bt = base_type(type); if (bt->kind == Type_Struct) { - check_did_you_mean_type(field_name, bt->Struct.fields); + check_did_you_mean_type(field_name.string(), bt->Struct.fields); } return false; } if (sel.indirect) { gbString type_str = type_to_string_shorthand(type); error(ce->args[0], - "Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str); + "Field '%s' is embedded via a pointer in '%s'", field_name.string(), type_str); gb_string_free(type_str); return false; } @@ -4436,7 +4437,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } if (!fail && first_is_field_value) { for_array(i, names) { - Selection sel = lookup_field(et, names[i], false); + Selection sel = lookup_field(et, string_interner_insert(names[i]), false); if (sel.entity == nullptr) { goto soa_zip_end; } @@ -6785,7 +6786,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } - String field_name = x.value.value_string; + InternedString field_name = string_interner_insert(x.value.value_string); Selection sel = lookup_field(type, field_name, false); operand->mode = Addressing_Constant; @@ -6865,12 +6866,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } - String field_name = x.value.value_string; + InternedString field_name = string_interner_insert(x.value.value_string); Selection sel = lookup_field(type, field_name, false); if (sel.index.count == 0) { gbString t = type_to_string(type); - error(ce->args[1], "'%.*s' is not a field of type %s", LIT(field_name), t); + error(ce->args[1], "'%s' is not a field of type %s", field_name.cstring(), t); gb_string_free(t); return false; } @@ -7625,25 +7626,25 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } - String field_name = x.value.value_string; + InternedString field_name = string_interner_insert(x.value.value_string); Selection sel = lookup_field(type, field_name, false); if (sel.entity == nullptr) { ERROR_BLOCK(); gbString type_str = type_to_string(bt); error(ce->args[0], - "'%s' has no field named '%.*s'", type_str, LIT(field_name)); + "'%s' has no field named '%s'", type_str, field_name.cstring()); gb_string_free(type_str); if (bt->kind == Type_Struct) { - check_did_you_mean_type(field_name, bt->Struct.fields); + check_did_you_mean_type(field_name.string(), bt->Struct.fields); } return false; } if (sel.indirect) { gbString type_str = type_to_string(bt); error(ce->args[0], - "Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str); + "Field '%s' is embedded via a pointer in '%s'", field_name.cstring(), type_str); gb_string_free(type_str); return false; } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 9c849d1e2..4f224affa 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -156,9 +156,12 @@ gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_e // NOTE(bill): The original_entity's scope may not be same scope that it was inserted into // e.g. file entity inserted into its package scope String original_name = original_entity->token.string; + auto original_intern = entity_interned_name(original_entity); + u32 hash = original_entity->interned_name_hash.load(); + Scope *found_scope = nullptr; Entity *found_entity = nullptr; - scope_lookup_parent(original_entity->scope, original_name, &found_scope, &found_entity); + scope_lookup_parent(original_entity->scope, original_intern, &found_scope, &found_entity, hash); if (found_scope == nullptr) { return; } @@ -170,9 +173,8 @@ gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_e // Therefore two things can be done: the type can be assigned to state that it // has been "evaluated" and the variant data can be copied across - u32 hash = string_hash(original_name); rw_mutex_lock(&found_scope->mutex); - scope_map_insert(&found_scope->elements, original_name, hash, new_entity); + scope_map_insert(&found_scope->elements, original_intern, hash, new_entity); rw_mutex_unlock(&found_scope->mutex); original_entity->flags |= EntityFlag_Overridden; @@ -993,7 +995,7 @@ gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) error(ident, "foreign library names must be an identifier"); } else { String name = ident->Ident.token.string; - Entity *found = scope_lookup(ctx->scope, name, ident->Ident.hash); + Entity *found = scope_lookup(ctx->scope, ident->Ident.interned, ident->Ident.hash); if (found == nullptr) { if (is_blank_ident(name)) { @@ -1192,26 +1194,26 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon if (!ac.objc_is_class_method) { bool ok = true; for (TypeNameObjCMetadataEntry const &entry : md->value_entries) { - if (entry.name == ac.objc_name) { + if (entry.interned.string() == ac.objc_name) { error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name)); ok = false; break; } } if (ok) { - array_add(&md->value_entries, TypeNameObjCMetadataEntry{ac.objc_name, e}); + array_add(&md->value_entries, TypeNameObjCMetadataEntry{string_interner_insert(ac.objc_name), e}); } } else { bool ok = true; for (TypeNameObjCMetadataEntry const &entry : md->type_entries) { - if (entry.name == ac.objc_name) { + if (entry.interned.string() == ac.objc_name) { error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name)); ok = false; break; } } if (ok) { - array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_name, e}); + array_add(&md->type_entries, TypeNameObjCMetadataEntry{string_interner_insert(ac.objc_name), e}); } } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 152031fa7..f02322430 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -183,11 +183,11 @@ gb_internal void populate_check_did_you_mean_objc_entity(StringSet *set, Entity if (is_type) { for (auto const &entry : objc_metadata->type_entries) { - string_set_add(set, entry.name); + string_set_add(set, entry.interned.string()); } } else { for (auto const &entry : objc_metadata->value_entries) { - string_set_add(set, entry.name); + string_set_add(set, entry.interned.string()); } } @@ -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.name); + Entity *e = scope_lookup(gt->Generic.scope, gt->Generic.interned_name); 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.name); + Entity *e = scope_lookup(gt->Generic.scope, gt->Generic.interned_name); GB_ASSERT(e != nullptr); if (e->kind == Entity_TypeName) { Type *index = source->EnumeratedArray.index; @@ -1770,9 +1770,9 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam GB_ASSERT(n->kind == Ast_Ident); o->mode = Addressing_Invalid; o->expr = n; - String name = n->Ident.token.string; + auto name = n->Ident.token.string; - Entity *e = scope_lookup(c->scope, name, n->Ident.hash); + Entity *e = scope_lookup(c->scope, n->Ident.interned); if (e == nullptr) { if (is_blank_ident(name)) { error(n, "'_' cannot be used as a value"); @@ -5192,7 +5192,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v continue; } ast_node(fv, FieldValue, elem); - String name = fv->field->Ident.token.string; + auto name = fv->field->Ident.interned; Selection sub_sel = lookup_field(node->tav.type, name, false); if (sub_sel.index.count > 0 && sub_sel.index[0] == index) { @@ -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, name, node->Ident.hash); + return scope_lookup(c->scope, node->Ident.interned); } 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_name, op_expr->Ident.hash); + Entity *e = scope_lookup(c->scope,op_expr->Ident.interned); if (e == nullptr) { return nullptr; } @@ -5494,7 +5494,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast * // If you can clean this up, please do but be really careful String import_name = op_name; Scope *import_scope = e->ImportName.scope; - String entity_name = selector->Ident.token.string; + auto entity_name = selector->Ident.interned; check_op_expr = false; entity = scope_lookup_current(import_scope, entity_name); @@ -5520,7 +5520,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast * } if (entity == nullptr && selector->kind == Ast_Ident) { - String field_name = selector->Ident.token.string; + auto field_name = selector->Ident.interned; if (is_type_dynamic_array(type_deref(operand.type))) { init_mem_allocator(c->checker); } @@ -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_name, op_expr->Ident.hash); + Entity *e = scope_lookup(c->scope, op_expr->Ident.interned); add_entity_use(c, op_expr, e); expr_entity = e; @@ -5596,6 +5596,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod String import_name = op_name; Scope *import_scope = e->ImportName.scope; String entity_name = selector->Ident.token.string; + InternedString entity_name_interned = selector->Ident.interned; if (import_scope == nullptr) { ERROR_BLOCK(); @@ -5606,7 +5607,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } check_op_expr = false; - entity = scope_lookup_current(import_scope, entity_name); + entity = scope_lookup_current(import_scope, entity_name_interned); bool allow_builtin = false; if (!is_entity_declared_for_selector(entity, import_scope, &allow_builtin)) { ERROR_BLOCK(); @@ -5654,7 +5655,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } if (entity == nullptr && selector->kind == Ast_Ident) { - String field_name = selector->Ident.token.string; + auto field_name = selector->Ident.interned; Type *t = type_deref(operand->type); if (t == nullptr) { error(operand->expr, "Cannot use a selector expression on 0-value expression"); @@ -5993,15 +5994,14 @@ gb_internal bool is_type_valid_atomic_type(Type *elem) { gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = false, Scope **out_scope = nullptr) { switch (node->kind) { case_ast_node(i, Ident, node); - String name = i->token.string; if (nested) { - Entity *e = scope_lookup_current(s, name); + Entity *e = scope_lookup_current(s, i->interned, i->hash); if (e != nullptr) { if (out_scope) *out_scope = e->scope; return true; } } else { - Entity *e = scope_lookup(s, name, i->hash); + Entity *e = scope_lookup(s, i->interned); if (e != nullptr) { if (out_scope) *out_scope = e->scope; return true; @@ -8972,7 +8972,7 @@ gb_internal bool attempt_implicit_selector_expr(CheckerContext *c, Operand *o, A Type *enum_type = base_type(th); GB_ASSERT(enum_type->kind == Type_Enum); - String name = ise->selector->Ident.token.string; + auto name = ise->selector->Ident.interned; Entity *e = scope_lookup_current(enum_type->Enum.scope, name); if (e == nullptr) { @@ -9907,8 +9907,9 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, SliceIdent.token.string; + auto interned = ident->Ident.interned; - Selection sel = lookup_field(type, name, o->mode == Addressing_Type); + Selection sel = lookup_field(type, interned, o->mode == Addressing_Type); bool is_unknown = sel.entity == nullptr; if (is_unknown) { error(ident, "Unknown field '%.*s' in structure literal", LIT(name)); @@ -10863,8 +10864,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * continue; } String name = fv->field->Ident.token.string; + auto interned = fv->field->Ident.interned; - Selection sel = lookup_field(type, name, o->mode == Addressing_Type); + Selection sel = lookup_field(type, interned, o->mode == Addressing_Type); if (sel.entity == nullptr) { error(elem, "Unknown field '%.*s' in 'any' literal", LIT(name)); continue; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index a690308cb..5775c3e53 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -484,7 +484,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O } if (ident_node != nullptr) { ast_node(i, Ident, ident_node); - e = scope_lookup(ctx->scope, i->token.string, i->hash); + e = scope_lookup(ctx->scope, i->interned, i->hash); if (e != nullptr && e->kind == Entity_Variable) { used = (e->flags & EntityFlag_Used) != 0; // NOTE(bill): Make backup just in case } @@ -791,10 +791,10 @@ gb_internal bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, for (auto const &entry : scope->elements) { Entity *decl = entry.value; if (!is_entity_exported(decl, true)) continue; - String name = scope->elements.keys[entry.hash & (scope->elements.cap-1)]; u32 hash = entry.hash; + auto interned = scope->elements.keys[hash & (scope->elements.cap-1)]; - Entity *found = scope_insert_with_name(ctx->scope, name, hash, decl); + Entity *found = scope_insert_with_name(ctx->scope, interned, hash, decl); if (found != nullptr) { gbString expr_str = expr_to_string(expr); error(us->token, @@ -1067,7 +1067,7 @@ gb_internal void check_unroll_range_stmt(CheckerContext *ctx, Ast *node, u32 mod Entity *found = nullptr; if (!is_blank_ident(str)) { - found = scope_lookup_current(ctx->scope, str); + found = scope_lookup_current(ctx->scope, name->Ident.interned, name->Ident.hash); } if (found == nullptr) { entity = alloc_entity_variable(ctx->scope, token, type, EntityState_Resolved); @@ -1836,10 +1836,10 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) { AstIdent *ident = &rs->vals[0]->Ident; - String name = ident->token.string; - Entity *found = scope_lookup(ctx->scope, name, ident->hash); + Entity *found = scope_lookup(ctx->scope, ident->interned, ident->hash); if (found && are_types_identical(found->type, t->BitSet.elem)) { ERROR_BLOCK(); + String name = ident->token.string; gbString s = expr_to_string(expr); error(rs->vals[0], "'%.*s' shadows a previous declaration which might be ambiguous with 'for (%.*s in %s)'", LIT(name), LIT(name), s); error_line("\tSuggestion: Use a different identifier if iteration is wanted, or surround in parentheses if a normal for loop is wanted\n"); @@ -1888,10 +1888,10 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) { AstIdent *ident = &rs->vals[0]->Ident; - String name = ident->token.string; - Entity *found = scope_lookup(ctx->scope, name, ident->hash); + Entity *found = scope_lookup(ctx->scope, ident->interned, ident->hash); if (found && are_types_identical(found->type, t->Map.key)) { ERROR_BLOCK(); + String name = ident->token.string; gbString s = expr_to_string(expr); error(rs->vals[0], "'%.*s' shadows a previous declaration which might be ambiguous with 'for (%.*s in %s)'", LIT(name), LIT(name), s); error_line("\tSuggestion: Use a different identifier if iteration is wanted, or surround in parentheses if a normal for loop is wanted\n"); @@ -2032,7 +2032,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) Entity *found = nullptr; if (!is_blank_ident(str)) { - found = scope_lookup_current(ctx->scope, str); + found = scope_lookup_current(ctx->scope, name->Ident.interned, name->Ident.hash); } if (found == nullptr) { entity = alloc_entity_variable(ctx->scope, token, type, EntityState_Resolved); @@ -2126,7 +2126,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f Entity *found = nullptr; // NOTE(bill): Ignore assignments to '_' if (!is_blank_ident(str)) { - found = scope_lookup_current(ctx->scope, str); + found = scope_lookup_current(ctx->scope, name->Ident.interned, name->Ident.hash); new_name_count += 1; } if (found == nullptr) { diff --git a/src/check_type.cpp b/src/check_type.cpp index 9612fc4f6..bd86e7c3d 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -5,7 +5,9 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para gb_internal void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) { t = base_type(t); GB_ASSERT(t->kind == Type_Array); - Entity *e = scope_lookup_current(ctx->scope, name); + InternedString interned = string_interner_insert(name); + + Entity *e = scope_lookup_current(ctx->scope, interned); if (e != nullptr) { gbString str = nullptr; defer (gb_string_free(str)); @@ -47,7 +49,8 @@ gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, Ast for (Entity *f : t->Struct.fields) { GB_ASSERT(f->kind == Entity_Variable); String name = f->token.string; - Entity *e = scope_lookup_current(ctx->scope, name); + InternedString interned = entity_interned_name(f); + Entity *e = scope_lookup_current(ctx->scope, interned); if (e != nullptr && name != "_") { gbString ot = type_to_string(original_type); // TODO(bill): Better type error @@ -423,7 +426,7 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly Ast *s = type_expr->TypeidType.specialization; specialization = check_type(ctx, s); } - type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization); + type = alloc_type_generic(ctx->scope, 0, string_interner_insert(str_lit("")), specialization); } else { type = check_type(ctx, type_expr); if (is_type_polymorphic(type)) { @@ -981,7 +984,9 @@ gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *nam e->Constant.docs = docs; e->Constant.comment = comment; - if (scope_lookup_current(ctx->scope, name) != nullptr) { + auto interned = entity_interned_name(e); + + if (scope_lookup_current(ctx->scope, interned) != nullptr) { error(ident, "'%.*s' is already declared in this enumeration", LIT(name)); } else { add_entity(ctx, ctx->scope, nullptr, e); @@ -1043,6 +1048,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, CommentGroup *comment = f->comment; String name = f->name->Ident.token.string; + InternedString interned = f->name->Ident.interned; if (f->type == nullptr) { error(field, "A bit_field's field must have a type"); @@ -1093,7 +1099,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, gb_string_free(s); } - if (scope_lookup_current(ctx->scope, name) != nullptr) { + if (scope_lookup_current(ctx->scope, interned) != nullptr) { error(f->name, "'%.*s' is already declared in this bit_field", LIT(name)); } else { i64 bit_size_i64 = exact_value_to_i64(bit_size); @@ -1513,7 +1519,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.name); + Entity *e = scope_lookup(st->Generic.scope, st->Generic.interned_name); GB_ASSERT(e != nullptr); if (modify_type) { e->kind = Entity_Constant; @@ -1566,7 +1572,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.name); + Entity *e = scope_lookup(st->Generic.scope, st->Generic.interned_name); GB_ASSERT(e != nullptr); if (modify_type) { e->kind = Entity_Constant; @@ -1905,7 +1911,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para detemine_type_from_operand = true; type = t_invalid; } else { - type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization); + type = alloc_type_generic(ctx->scope, 0, string_interner_insert(str_lit("")), specialization); } } else { type = t_typeid; @@ -2330,8 +2336,7 @@ gb_internal bool ast_references_poly_params(Scope *scope, Ast *node) { } switch (node->kind) { case Ast_Ident: { - String name = node->Ident.token.string; - Entity *e = scope_lookup(scope, name); + Entity *e = scope_lookup(scope, node->Ident.interned, node->Ident.hash); if (e != nullptr && e->kind == Entity_TypeName && e->type != nullptr && e->type->kind == Type_Generic) { return true; } @@ -2408,7 +2413,7 @@ gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_res param_value = handle_parameter_value(ctx, nullptr, &type, default_value, false); } else { if (ctx->allow_polymorphic_types && ast_references_poly_params(ctx->scope, field->type)) { - type = alloc_type_generic(ctx->scope, 0, str_lit("$deferred_return"), nullptr); + type = alloc_type_generic(ctx->scope, 0, string_interner_insert(str_lit("$deferred_return")), nullptr); } else { type = check_type(ctx, field->type); } @@ -3534,7 +3539,7 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T Ast *s = pt->specialization; specific = check_type(&c, s); } - Type *t = alloc_type_generic(ctx->scope, 0, token.string, specific); + Type *t = alloc_type_generic(ctx->scope, 0, ident->Ident.interned, specific); if (ctx->allow_polymorphic_types) { if (ctx->disallow_polymorphic_return_types) { error(ident, "Undeclared polymorphic parameter '%.*s' in return type", LIT(token.string)); diff --git a/src/checker.cpp b/src/checker.cpp index aca0e90a6..021b03dc9 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -372,10 +372,10 @@ gb_internal void check_close_scope(CheckerContext *c) { } -gb_internal Entity *scope_lookup_current(Scope *s, String const &name, u32 hash) { +gb_internal Entity *scope_lookup_current(Scope *s, InternedString name, u32 hash) { // Entity **found = string_map_get(&s->elements, name); if (hash == 0) { - hash = string_hash(name); + hash = name.hash(); } Entity *found = scope_map_get(&s->elements, name, hash); if (found) { @@ -387,13 +387,13 @@ gb_internal Entity *scope_lookup_current(Scope *s, String const &name, u32 hash) gb_global std::atomic in_single_threaded_checker_stage; -gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entity **entity_, u32 hash) { +gb_internal void scope_lookup_parent(Scope *scope, InternedString 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; if (!hash) { - hash = string_hash(name); + hash = name.hash(); } for (Scope *s = scope; s != nullptr; s = s->parent) { Entity *found = nullptr; @@ -434,14 +434,14 @@ 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, u32 hash) { +gb_internal Entity *scope_lookup(Scope *s, InternedString interned, u32 hash) { Entity *entity = nullptr; - scope_lookup_parent(s, name, nullptr, &entity, hash); + scope_lookup_parent(s, interned, nullptr, &entity, hash); return entity; } -gb_internal Entity *scope_insert_with_name_no_mutex(Scope *s, String const &name, u32 hash, Entity *entity) { - if (name == "") { +gb_internal Entity *scope_insert_with_name_no_mutex(Scope *s, InternedString name, u32 hash, Entity *entity) { + if (name.value == 0) { return nullptr; } Entity *found = nullptr; @@ -476,8 +476,8 @@ end:; } -gb_internal Entity *scope_insert_with_name(Scope *s, String const &name, u32 hash, Entity *entity) { - if (name == "") { +gb_internal Entity *scope_insert_with_name(Scope *s, InternedString name, u32 hash, Entity *entity) { + if (name.value == 0) { return nullptr; } Entity *found = nullptr; @@ -519,15 +519,9 @@ end:; } gb_internal Entity *scope_insert(Scope *s, Entity *entity) { - String name = entity->token.string; - u32 hash = 0; - Ast *ident = entity->identifier.load(std::memory_order_relaxed); - if (ident != nullptr) { - hash = ident->Ident.hash; - } - if (hash == 0) { - hash = string_hash(name); - } + auto name = entity_interned_name(entity); + u32 hash = entity->interned_name_hash.load(std::memory_order_relaxed); + GB_ASSERT(hash != 0); if (in_single_threaded_checker_stage.load(std::memory_order_relaxed)) { return scope_insert_with_name_no_mutex(s, name, hash, entity); } else { @@ -536,15 +530,9 @@ gb_internal Entity *scope_insert(Scope *s, Entity *entity) { } gb_internal Entity *scope_insert_no_mutex(Scope *s, Entity *entity) { - String name = entity->token.string; - u32 hash = 0; - Ast *ident = entity->identifier.load(std::memory_order_relaxed); - if (ident != nullptr) { - hash = ident->Ident.hash; - } - if (hash == 0) { - hash = string_hash(name); - } + auto name = string_interner_insert(entity->token.string); + u32 hash = entity->interned_name_hash.load(std::memory_order_relaxed); + GB_ASSERT(hash != 0); return scope_insert_with_name_no_mutex(s, name, hash, entity); } @@ -679,7 +667,7 @@ gb_internal bool check_vet_shadowing(Checker *c, Entity *e, VettedEntity *ve) { return false; } - Entity *shadowed = scope_lookup(parent, name); + Entity *shadowed = scope_lookup(parent, entity_interned_name(e)); if (shadowed == nullptr) { return false; } @@ -961,8 +949,9 @@ 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); AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name)); - Entity *e = scope_lookup(p->scope, n); + Entity *e = scope_lookup(p->scope, key); GB_ASSERT_MSG(e != nullptr, "%s", name); GB_ASSERT(c->decl != nullptr); e->flags |= EntityFlag_Used; @@ -974,8 +963,9 @@ 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); AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name)); - Entity *e = scope_lookup(p->scope, n); + Entity *e = scope_lookup(p->scope, key); if (e == nullptr) { return; } @@ -1373,6 +1363,9 @@ gb_internal void init_universal(void) { BuiltinProcId id = cast(BuiltinProcId)i; String name = builtin_procs[i].name; if (name != "") { + u32 hash = 0; + InternedString interned = string_interner_insert(name, 0, &hash); + Entity *entity = alloc_entity(Entity_Builtin, nullptr, make_token_ident(name), t_invalid); entity->Builtin.id = id; switch (builtin_procs[i].pkg) { @@ -1381,7 +1374,7 @@ gb_internal void init_universal(void) { break; case BuiltinProcPkg_intrinsics: add_global_entity(entity, intrinsics_pkg->scope); - GB_ASSERT(scope_lookup_current(intrinsics_pkg->scope, name) != nullptr); + GB_ASSERT(scope_lookup_current(intrinsics_pkg->scope, interned, hash) != nullptr); break; } } @@ -2763,7 +2756,7 @@ 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, name); + Entity *e = scope_lookup(scope, string_interner_insert(name)); if (e == nullptr) { return; } @@ -2775,7 +2768,9 @@ gb_internal void force_add_dependency_entity(Checker *c, Scope *scope, String co gb_internal void collect_testing_procedures_of_package(Checker *c, AstPackage *pkg) { AstPackage *testing_package = get_core_package(&c->info, str_lit("testing")); Scope *testing_scope = testing_package->scope; - Entity *test_signature = scope_lookup_current(testing_scope, str_lit("Test_Signature")); + u32 hash = 0; + InternedString interned = string_interner_insert(str_lit("Test_Signature"), 0, &hash); + Entity *test_signature = scope_lookup_current(testing_scope, interned, hash); Scope *s = pkg->scope; for (auto const &entry : s->elements) { @@ -3229,7 +3224,9 @@ gb_internal void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d); gb_internal Entity *find_core_entity(Checker *c, String name) { - Entity *e = scope_lookup_current(c->info.runtime_package->scope, name); + u32 hash = 0; + InternedString interned = string_interner_insert(name, 0, &hash); + Entity *e = scope_lookup_current(c->info.runtime_package->scope, interned, hash); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s'\n" , LIT(name)); @@ -3239,7 +3236,9 @@ gb_internal Entity *find_core_entity(Checker *c, String name) { } gb_internal Type *find_core_type(Checker *c, String name) { - Entity *e = scope_lookup_current(c->info.runtime_package->scope, name); + u32 hash = 0; + InternedString interned = string_interner_insert(name, 0, &hash); + Entity *e = scope_lookup_current(c->info.runtime_package->scope, interned, hash); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s'\n" , LIT(name)); @@ -3254,8 +3253,10 @@ gb_internal Type *find_core_type(Checker *c, String name) { gb_internal Entity *find_entity_in_pkg(CheckerInfo *info, String const &pkg, String const &name) { + u32 hash = 0; + InternedString interned = string_interner_insert(name, 0, &hash); AstPackage *package = get_core_package(info, pkg); - Entity *e = scope_lookup_current(package->scope, name); + Entity *e = scope_lookup_current(package->scope, interned, hash); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s.%.*s'\n", LIT(pkg), LIT(name)); // NOTE(bill): This will exit the program as it's cannot continue without it! @@ -3264,8 +3265,10 @@ gb_internal Entity *find_entity_in_pkg(CheckerInfo *info, String const &pkg, Str } gb_internal Type *find_type_in_pkg(CheckerInfo *info, String const &pkg, String const &name) { + u32 hash = 0; + InternedString interned = string_interner_insert(name, 0, &hash); AstPackage *package = get_core_package(info, pkg); - Entity *e = scope_lookup_current(package->scope, name); + Entity *e = scope_lookup_current(package->scope, interned, hash); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s.%.*s'\n", LIT(pkg), LIT(name)); // NOTE(bill): This will exit the program as it's cannot continue without it! @@ -4558,7 +4561,9 @@ gb_internal void check_builtin_attributes(CheckerContext *ctx, Entity *e, Array< if (name == "builtin") { mutex_lock(&ctx->info->builtin_mutex); add_entity(ctx, builtin_pkg->scope, nullptr, e); - GB_ASSERT(scope_lookup(builtin_pkg->scope, e->token.string) != nullptr); + auto interned = entity_interned_name(e); + u32 hash = e->interned_name_hash.load(); + GB_ASSERT(scope_lookup(builtin_pkg->scope, interned, hash) != nullptr); if (value != nullptr) { error(value, "'builtin' cannot have a field value"); } @@ -7514,7 +7519,7 @@ gb_internal void check_parsed_files(Checker *c) { Scope *s = c->info.init_scope; GB_ASSERT(s != nullptr); GB_ASSERT(s->flags&ScopeFlag_Init); - Entity *e = scope_lookup_current(s, str_lit("main")); + Entity *e = scope_lookup_current(s, string_interner_insert(str_lit("main"))); if (e == nullptr) { Token token = {}; token.pos.file_id = 0; diff --git a/src/checker.hpp b/src/checker.hpp index ef68f9c74..335794535 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -278,12 +278,12 @@ struct ScopeMapSlot { enum { SCOPE_MAP_INLINE_CAP = 16 }; struct ScopeMap { - String inline_keys [SCOPE_MAP_INLINE_CAP]; - ScopeMapSlot inline_slots[SCOPE_MAP_INLINE_CAP]; - String * keys; - ScopeMapSlot *slots; - u32 count; - u32 cap; + InternedString inline_keys [SCOPE_MAP_INLINE_CAP]; + ScopeMapSlot inline_slots[SCOPE_MAP_INLINE_CAP]; + InternedString *keys; + ScopeMapSlot * slots; + u32 count; + u32 cap; }; gb_internal gb_inline u32 scope_map_max_load(u32 cap) { @@ -298,8 +298,8 @@ gb_internal gb_inline void scope_map_init(ScopeMap *m) { gb_internal Entity *scope_map_insert_for_rehash( - String *keys, ScopeMapSlot *slots, u32 mask, - String key, u32 hash, Entity *value) { + InternedString *keys, ScopeMapSlot *slots, u32 mask, + InternedString key, u32 hash, Entity *value) { u32 pos = hash & mask; u32 dist = 0; @@ -316,7 +316,7 @@ gb_internal Entity *scope_map_insert_for_rehash( u32 existing_dist = (pos - s->hash) & mask; if (dist > existing_dist) { - String tmp_key = keys[pos]; + auto tmp_key = keys[pos]; u32 tmp_hash = s->hash; Entity *tmp_value = s->value; @@ -335,12 +335,12 @@ gb_internal Entity *scope_map_insert_for_rehash( } } -gb_internal gb_inline void scope_map_allocate_entries(u32 cap, String **keys, ScopeMapSlot **slots) { +gb_internal gb_inline void scope_map_allocate_entries(u32 cap, InternedString **keys, ScopeMapSlot **slots) { Arena *arena = get_arena(ThreadArena_Permanent); - isize size = (gb_size_of(String) + gb_size_of(ScopeMapSlot)) * cap; + isize size = (gb_size_of(InternedString) + gb_size_of(ScopeMapSlot)) * cap; u8 *data = cast(u8 *)arena_alloc(arena, size, 8); - *keys = cast(String *)data; + *keys = cast(InternedString *)data; *slots = cast(ScopeMapSlot *)(*keys + cap); // *keys = permanent_alloc_array(cap); @@ -352,8 +352,8 @@ gb_internal void scope_map_grow(ScopeMap *m) { u32 new_cap = m->cap << 1; u32 new_mask = new_cap - 1; - String * new_keys; - ScopeMapSlot *new_slots; + InternedString *new_keys; + ScopeMapSlot * new_slots; scope_map_allocate_entries(new_cap, &new_keys, &new_slots); if (m->count > 0) { @@ -383,7 +383,7 @@ gb_internal void scope_map_reserve(ScopeMap *m, isize capacity) { -gb_internal Entity *scope_map_insert(ScopeMap *m, String key, u32 hash, Entity *value) { +gb_internal Entity *scope_map_insert(ScopeMap *m, InternedString key, u32 hash, Entity *value) { if (m->slots == nullptr) { scope_map_init(m); } @@ -415,7 +415,7 @@ gb_internal Entity *scope_map_insert(ScopeMap *m, String key, u32 hash, Entity * u32 existing_dist = (pos - s->hash) & mask; if (dist > existing_dist) { - String tmp_key = m->keys[pos]; + auto tmp_key = m->keys[pos]; u32 tmp_hash = s->hash; Entity *tmp_value = s->value; @@ -434,7 +434,7 @@ gb_internal Entity *scope_map_insert(ScopeMap *m, String key, u32 hash, Entity * } } -gb_internal Entity *scope_map_get(ScopeMap *m, String key, u32 hash) { +gb_internal Entity *scope_map_get(ScopeMap *m, InternedString key, u32 hash) { u32 mask = m->cap-1; u32 pos = hash & mask; u32 dist = 0; @@ -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, String const &name, u32 hash=0); -gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_, 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_insert (Scope *s, Entity *entity); diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 89b7802ae..3f5d4876a 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -1050,7 +1050,8 @@ gb_internal OdinDocArray odin_doc_add_pkg_entries(OdinDocWrit defer (array_free(&entries)); for (auto const &element : pkg->scope->elements) { - String name = pkg->scope->elements.keys[element.hash & (pkg->scope->elements.cap-1)]; + u32 hash = element.hash; + auto interned = pkg->scope->elements.keys[hash & (pkg->scope->elements.cap-1)]; Entity *e = element.value; switch (e->kind) { case Entity_Invalid: @@ -1079,7 +1080,7 @@ gb_internal OdinDocArray odin_doc_add_pkg_entries(OdinDocWrit } OdinDocScopeEntry entry = {}; - entry.name = odin_doc_write_string(w, name); + entry.name = odin_doc_write_string(w, interned.string()); entry.entity = odin_doc_add_entity(w, e); array_add(&entries, entry); } diff --git a/src/entity.cpp b/src/entity.cpp index 5fcd62071..2f0046972 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -141,7 +141,7 @@ enum ProcedureOptimizationMode : u8 { BlockingMutex global_type_name_objc_metadata_mutex; struct TypeNameObjCMetadataEntry { - String name; + InternedString interned; Entity *entity; }; struct TypeNameObjCMetadata { @@ -169,6 +169,10 @@ struct Entity { Scope * scope; Type * type; std::atomic identifier; // Can be nullptr + + std::atomic interned_name; + std::atomic interned_name_hash; + DeclInfo * decl_info; std::atomic parent_proc_decl; // nullptr if in file/global scope AstFile * file; @@ -300,6 +304,16 @@ struct Entity { }; }; +gb_internal InternedString entity_interned_name(Entity *entity) { + auto name = entity->interned_name.load(); + if (name.value == 0) { + name = string_interner_insert(entity->token.string); + entity->interned_name.store(name); + entity->interned_name_hash.store(name.hash()); + } + return name; +} + gb_internal bool is_entity_kind_exported(EntityKind kind, bool allow_builtin = false) { switch (kind) { case Entity_Builtin: @@ -345,16 +359,17 @@ gb_internal bool entity_has_deferred_procedure(Entity *e) { gb_global std::atomic global_entity_id; // NOTE(bill): This exists to allow for bulk allocations of entities all at once to improve performance for type generation -#define INTERNAL_ENTITY_INIT(entity, kind_, scope_, token_, type_) do { \ - (entity)->kind = (kind_); \ - (entity)->state = EntityState_Unresolved; \ - (entity)->scope = (scope_); \ - (entity)->token = (token_); \ - (entity)->type = (type_); \ - (entity)->id = 1 + global_entity_id.fetch_add(1); \ - if ((token_).pos.file_id) { \ - entity->file = thread_unsafe_get_ast_file_from_id((token_).pos.file_id); \ - } \ +#define INTERNAL_ENTITY_INIT(e_, kind_, scope_, token_, type_) do { \ + (e_)->kind = (kind_); \ + (e_)->state = EntityState_Unresolved; \ + (e_)->scope = (scope_); \ + (e_)->token = (token_); \ + (e_)->type = (type_); \ + (e_)->id = 1 + global_entity_id.fetch_add(1); \ + if ((token_).pos.file_id) { \ + e_->file = thread_unsafe_get_ast_file_from_id((token_).pos.file_id); \ + } \ + entity_interned_name(e_); \ } while (0) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index fac3e3354..b2246c90e 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2946,7 +2946,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star AstPackage *pkg = get_runtime_package(m->info); String name = str_lit("exit"); - Entity *e = scope_lookup_current(pkg->scope, name); + Entity *e = scope_lookup_current(pkg->scope, string_interner_insert(name)); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s.%.*s'\n", LIT(pkg->name), LIT(name)); } diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 954545db6..762243ee3 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -1819,11 +1819,12 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb for (isize i = 0; i < elem_count; i++) { ast_node(fv, FieldValue, cl->elems[i]); String name = fv->field->Ident.token.string; + InternedString interned = fv->field->Ident.interned; TypeAndValue tav = fv->value->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - Selection sel = lookup_field(type, name, false); + Selection sel = lookup_field(type, interned, false); GB_ASSERT(!sel.indirect); Entity *f = type->Struct.fields[sel.index[0]]; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index c71409a8e..39cdcd54f 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4362,9 +4362,9 @@ gb_internal lbAddr lb_get_soa_variable_addr(lbProcedure *p, Entity *e) { } gb_internal lbValue lb_get_using_variable(lbProcedure *p, Entity *e) { GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Using); - String name = e->token.string; + InternedString interned = entity_interned_name(e); Entity *parent = e->using_parent; - Selection sel = lookup_field(parent->type, name, false); + Selection sel = lookup_field(parent->type, interned, false); GB_ASSERT(sel.entity != nullptr); lbValue *pv = map_get(&p->module->values, parent); @@ -4379,7 +4379,7 @@ gb_internal lbValue lb_get_using_variable(lbProcedure *p, Entity *e) { } else if (pv != nullptr) { v = *pv; } else { - GB_ASSERT_MSG(e->using_expr != nullptr, "%.*s", LIT(name)); + GB_ASSERT_MSG(e->using_expr != nullptr, "%.*s", LIT(e->token.string)); v = lb_build_addr_ptr(p, e->using_expr); } GB_ASSERT(v.value != nullptr); @@ -5362,8 +5362,8 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { for (Ast *elem : cl->elems) { ast_node(fv, FieldValue, elem); - String name = fv->field->Ident.token.string; - Selection sel = lookup_field(bt, name, false); + InternedString interned = fv->field->Ident.interned; + Selection sel = lookup_field(bt, interned, false); GB_ASSERT(sel.is_bit_field); GB_ASSERT(!sel.indirect); GB_ASSERT(sel.index.count == 1); @@ -5556,8 +5556,8 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (elem->kind == Ast_FieldValue) { ast_node(fv, FieldValue, elem); - String name = fv->field->Ident.token.string; - Selection sel = lookup_field(bt, name, false); + InternedString interned = fv->field->Ident.interned; + Selection sel = lookup_field(bt, interned, false); GB_ASSERT(!sel.indirect); elem = fv->value; @@ -5811,12 +5811,12 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (elem->kind == Ast_FieldValue) { ast_node(fv, FieldValue, elem); - Selection sel = lookup_field(bt, fv->field->Ident.token.string, false); + Selection sel = lookup_field(bt, fv->field->Ident.interned, false); index = sel.index[0]; elem = fv->value; } else { TypeAndValue tav = type_and_value_of_expr(elem); - Selection sel = lookup_field(bt, field_names[field_index], false); + Selection sel = lookup_field(bt, string_interner_insert(field_names[field_index]), false); index = sel.index[0]; } @@ -5958,7 +5958,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { case_ast_node(se, SelectorExpr, expr); Ast *sel_node = unparen_expr(se->selector); if (sel_node->kind == Ast_Ident) { - String selector = sel_node->Ident.token.string; + InternedString selector = sel_node->Ident.interned; TypeAndValue tav = type_and_value_of_expr(se->expr); if (tav.mode == Addressing_Invalid) { @@ -5978,7 +5978,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT(e->kind == Entity_Procedure); return lb_addr(lb_find_value_from_entity(p->module, e)); } - GB_PANIC("Unreachable %.*s", LIT(selector)); + GB_PANIC("Unreachable %s", selector.cstring()); } if (se->swizzle_count > 0) { diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 35a0f5f65..b15eb8333 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -3406,7 +3406,7 @@ gb_internal lbAddr lb_add_global_generated_from_procedure(lbProcedure *p, Type * gb_internal lbValue lb_find_runtime_value(lbModule *m, String const &name) { AstPackage *p = m->info->runtime_package; - Entity *e = scope_lookup_current(p->scope, name); + Entity *e = scope_lookup_current(p->scope, string_interner_insert(name)); return lb_find_value_from_entity(m, e); } gb_internal lbValue lb_find_package_value(lbModule *m, String const &pkg, String const &name) { diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 121b8c550..36d736b0f 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1012,7 +1012,7 @@ gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue gb_internal lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name) { AstPackage *pkg = m->info->runtime_package; - Entity *e = scope_lookup_current(pkg->scope, name); + Entity *e = scope_lookup_current(pkg->scope, string_interner_insert(name)); GB_ASSERT_MSG(e != nullptr, "Runtime procedure not found: %s", name); return lb_find_procedure_value_from_entity(m, e); } diff --git a/src/main.cpp b/src/main.cpp index 1f0df6add..4d68d3d73 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3588,7 +3588,7 @@ int main(int arg_count, char const **arg_ptr) { MAIN_TIME_SECTION("initialization"); - g_string_interner = string_interner_create(); + init_string_interner(); init_global_error_collector(); init_keyword_hash_table(); init_terminal(); diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index a99dec0af..1a4ca6439 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -559,6 +559,8 @@ gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) { // no prefix return; } + InternedString interned = entity_interned_name(e); + if (e->parent_proc_decl.load(std::memory_order_relaxed)) { Entity *p = e->parent_proc_decl.load(std::memory_order_relaxed)->entity; write_canonical_parent_prefix(w, p); @@ -569,7 +571,7 @@ gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) { } type_writer_appendc(w, CANONICAL_NAME_SEPARATOR); - } else if (e->pkg && (scope_lookup_current(e->pkg->scope, e->token.string) == e)) { + } else if (e->pkg && (scope_lookup_current(e->pkg->scope, interned) == e)) { type_writer_append(w, e->pkg->name.text, e->pkg->name.len); if (e->pkg->name == "llvm") { type_writer_appendc(w, "$"); diff --git a/src/string_interner.cpp b/src/string_interner.cpp index f8496e3b0..660dbc61d 100644 --- a/src/string_interner.cpp +++ b/src/string_interner.cpp @@ -10,8 +10,11 @@ struct InternedString { return this->value == other.value; } - String load() const; - char const *load_cstring() const; + String string() const; + char const *cstring() const; + u32 hash() const; + + bool is_blank() const; }; struct alignas(STRING_INTERN_CACHE_LINE) StringInternCell { std::atomic hashes [STRING_INTERNER_CELL_WIDTH]; @@ -38,10 +41,11 @@ struct StringInterner { }; gb_internal StringInterner *string_interner_create(); -gb_internal InternedString string_interner_insert(String str, u32 hash=0); +gb_internal InternedString string_interner_insert(String str, u32 hash=0, u32 *new_hash_=nullptr); gb_internal String string_interner_load(InternedString interned); gb_global StringInterner *g_string_interner; +gb_global InternedString g_interned_blank_ident; struct StringInternerThreadLocalArena { u8 *data; @@ -52,7 +56,7 @@ gb_thread_local gb_global StringInternerThreadLocalArena g_interner_arena; gb_internal void string_interner_thread_local_arena_init(StringInternerThreadLocalArena *tl_arena); gb_internal void *string_interner_thread_local_arena_alloc(StringInternerThreadLocalArena *tl_arena, isize size, isize alignment); -gb_internal StringInterner *string_interner_create() { +gb_internal void init_string_interner() { StaticArena arena = {}; static_arena_init(&arena, 1<<30, STATIC_ARENA_DEFAULT_COMMIT_BLOCK_SIZE); @@ -63,7 +67,10 @@ gb_internal StringInterner *string_interner_create() { interner->cell_mask = cell_mask; interner->cells = cast(StringInternCell *)static_arena_alloc(&interner->arena, cell_size * gb_size_of(StringInternCell), STRING_INTERN_CACHE_LINE); interner->track_count = false; - return interner; + + g_string_interner = interner; + + g_interned_blank_ident = string_interner_insert(str_lit("_")); } gb_internal String string_interner_load(InternedString interned) { @@ -89,22 +96,31 @@ gb_internal char const *string_interner_load_cstring(InternedString interned) { return cast(char const *)text; } -String InternedString::load() const { +String InternedString::string() const { return string_interner_load(*this); } -char const *InternedString::load_cstring() const { +char const *InternedString::cstring() const { return string_interner_load_cstring(*this); } +u32 InternedString::hash() const { + String s = string_interner_load(*this); + return string_hash(s); +} +bool InternedString::is_blank() const { + return this->value == g_interned_blank_ident.value; +} -gb_internal InternedString string_interner_insert(String str, u32 hash) { +gb_internal InternedString string_interner_insert(String str, u32 hash, u32 *new_hash_) { StringInterner* interner = g_string_interner; if (str.len == 0) { + if (new_hash_) *new_hash_ = string_hash(String{}); return {}; } if (hash == 0) { hash = string_hash(str); } + if (new_hash_) *new_hash_ = hash; u64 cell_idx = hash & interner->cell_mask; StringInternCell *cell = &interner->cells[cell_idx]; @@ -175,14 +191,14 @@ gb_internal InternedString string_interner_insert(String str, u32 hash) { return offset; } -gb_internal char const *string_intern_cstring(String str) { - InternedString i = string_interner_insert(str, 0); +gb_internal char const *string_intern_cstring(String str, u32 *hash_=nullptr) { + InternedString i = string_interner_insert(str, 0, hash_); return string_interner_load_cstring(i); } -gb_internal String string_intern_string(String str) { - InternedString i = string_interner_insert(str, 0); +gb_internal String string_intern_string(String str, u32 *hash_=nullptr) { + InternedString i = string_interner_insert(str, 0, hash_); return string_interner_load(i); } diff --git a/src/types.cpp b/src/types.cpp index abe7b104c..f4b708e57 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -226,6 +226,7 @@ struct TypeNamed { TYPE_KIND(Generic, struct { \ i64 id; \ String name; \ + InternedString interned_name; \ Type * specialized; \ Scope * scope; \ Entity *entity; \ @@ -986,10 +987,11 @@ gb_internal Type *alloc_type(TypeKind kind) { } -gb_internal Type *alloc_type_generic(Scope *scope, i64 id, String name, Type *specialized) { +gb_internal Type *alloc_type_generic(Scope *scope, i64 id, InternedString interned_name, Type *specialized) { Type *t = alloc_type(Type_Generic); t->Generic.id = id; - t->Generic.name = name; + t->Generic.name = interned_name.string(); + t->Generic.interned_name = interned_name; t->Generic.specialized = specialized; t->Generic.scope = scope; return t; @@ -3569,9 +3571,9 @@ gb_internal ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) -gb_internal Selection lookup_field_with_selection(Type *type_, String field_name, bool is_type, Selection sel, bool allow_blank_ident=false); +gb_internal Selection lookup_field_with_selection(Type *type_, InternedString field_name, bool is_type, Selection sel, bool allow_blank_ident=false); -gb_internal Selection lookup_field(Type *type_, String field_name, bool is_type, bool allow_blank_ident=false) { +gb_internal Selection lookup_field(Type *type_, InternedString field_name, bool is_type, bool allow_blank_ident=false) { return lookup_field_with_selection(type_, field_name, is_type, empty_selection, allow_blank_ident); } @@ -3624,13 +3626,13 @@ gb_internal Selection lookup_field_from_index(Type *type, i64 index) { return empty_selection; } -gb_internal Entity *scope_lookup_current(Scope *s, String const &name, u32 hash=0); +gb_internal Entity *scope_lookup_current(Scope *s, InternedString name, u32 hash=0); gb_internal bool has_type_got_objc_class_attribute(Type *t); -gb_internal Selection lookup_field_with_selection(Type *type_, String field_name, bool is_type, Selection sel, bool allow_blank_ident) { +gb_internal Selection lookup_field_with_selection(Type *type_, InternedString field_name, bool is_type, Selection sel, bool allow_blank_ident) { GB_ASSERT(type_ != nullptr); - if (!allow_blank_ident && is_blank_ident(field_name)) { + if (!allow_blank_ident && field_name.is_blank()) { return empty_selection; } @@ -3652,7 +3654,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name defer (mutex_unlock(md->mutex)); for (TypeNameObjCMetadataEntry const &entry : md->type_entries) { GB_ASSERT(entry.entity->kind == Entity_Procedure || entry.entity->kind == Entity_ProcGroup); - if (entry.name == field_name) { + if (entry.interned == field_name) { sel.entity = entry.entity; sel.pseudo_field = true; return sel; @@ -3679,7 +3681,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name for_array(i, type->Enum.fields) { Entity *f = type->Enum.fields[i]; GB_ASSERT(f->kind == Entity_Constant); - String str = f->token.string; + auto str = entity_interned_name(f); if (field_name == str) { sel.entity = f; @@ -3730,7 +3732,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name defer (mutex_unlock(md->mutex)); for (TypeNameObjCMetadataEntry const &entry : md->value_entries) { GB_ASSERT(entry.entity->kind == Entity_Procedure || entry.entity->kind == Entity_ProcGroup); - if (entry.name == field_name) { + if (entry.interned == field_name) { sel.entity = entry.entity; sel.pseudo_field = true; return sel; @@ -3759,7 +3761,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) { continue; } - String str = f->token.string; + auto str = entity_interned_name(f); if (field_name == str) { selection_add_index(&sel, i); // HACK(bill): Leaky memory sel.entity = f; @@ -3788,11 +3790,12 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name bool is_soa_of_array = is_soa && is_type_array(type->Struct.soa_elem); if (is_soa_of_array) { - String mapped_field_name = {}; - if (field_name == "r") mapped_field_name = str_lit("x"); - else if (field_name == "g") mapped_field_name = str_lit("y"); - else if (field_name == "b") mapped_field_name = str_lit("z"); - else if (field_name == "a") mapped_field_name = str_lit("w"); + InternedString mapped_field_name = {}; + String n = field_name.string(); + if (n == "r") mapped_field_name = string_interner_insert(str_lit("x")); + else if (n == "g") mapped_field_name = string_interner_insert(str_lit("y")); + else if (n == "b") mapped_field_name = string_interner_insert(str_lit("z")); + else if (n == "a") mapped_field_name = string_interner_insert(str_lit("w")); return lookup_field_with_selection(type, mapped_field_name, is_type, sel, allow_blank_ident); } } else if (type->kind == Type_BitField) { @@ -3801,7 +3804,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) { continue; } - String str = f->token.string; + auto str = entity_interned_name(f); if (field_name == str) { selection_add_index(&sel, i); // HACK(bill): Leaky memory sel.entity = f; @@ -3819,11 +3822,12 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name gb_local_persist Entity *entity__any_data = alloc_entity_field(nullptr, make_token_ident(data_str), t_rawptr, false, 0); gb_local_persist Entity *entity__any_id = alloc_entity_field(nullptr, make_token_ident(id_str), t_typeid, false, 1); - if (field_name == data_str) { + String n = field_name.string(); + if (n == data_str) { selection_add_index(&sel, 0); sel.entity = entity__any_data; return sel; - } else if (field_name == id_str) { + } else if (n == id_str) { selection_add_index(&sel, 1); sel.entity = entity__any_id; return sel; @@ -3841,19 +3845,21 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name gb_local_persist Entity *entity__x = alloc_entity_field(nullptr, make_token_ident(x), t_f16, false, 0); gb_local_persist Entity *entity__y = alloc_entity_field(nullptr, make_token_ident(y), t_f16, false, 1); gb_local_persist Entity *entity__z = alloc_entity_field(nullptr, make_token_ident(z), t_f16, false, 2); - if (field_name == w) { + + String n = field_name.string(); + if (n == w) { selection_add_index(&sel, 3); sel.entity = entity__w; return sel; - } else if (field_name == x) { + } else if (n == x) { selection_add_index(&sel, 0); sel.entity = entity__x; return sel; - } else if (field_name == y) { + } else if (n == y) { selection_add_index(&sel, 1); sel.entity = entity__y; return sel; - } else if (field_name == z) { + } else if (n == z) { selection_add_index(&sel, 2); sel.entity = entity__z; return sel; @@ -3870,19 +3876,21 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name gb_local_persist Entity *entity__x = alloc_entity_field(nullptr, make_token_ident(x), t_f32, false, 0); gb_local_persist Entity *entity__y = alloc_entity_field(nullptr, make_token_ident(y), t_f32, false, 1); gb_local_persist Entity *entity__z = alloc_entity_field(nullptr, make_token_ident(z), t_f32, false, 2); - if (field_name == w) { + + String n = field_name.string(); + if (n == w) { selection_add_index(&sel, 3); sel.entity = entity__w; return sel; - } else if (field_name == x) { + } else if (n == x) { selection_add_index(&sel, 0); sel.entity = entity__x; return sel; - } else if (field_name == y) { + } else if (n == y) { selection_add_index(&sel, 1); sel.entity = entity__y; return sel; - } else if (field_name == z) { + } else if (n == z) { selection_add_index(&sel, 2); sel.entity = entity__z; return sel; @@ -3899,19 +3907,21 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name gb_local_persist Entity *entity__x = alloc_entity_field(nullptr, make_token_ident(x), t_f64, false, 0); gb_local_persist Entity *entity__y = alloc_entity_field(nullptr, make_token_ident(y), t_f64, false, 1); gb_local_persist Entity *entity__z = alloc_entity_field(nullptr, make_token_ident(z), t_f64, false, 2); - if (field_name == w) { + + String n = field_name.string(); + if (n == w) { selection_add_index(&sel, 3); sel.entity = entity__w; return sel; - } else if (field_name == x) { + } else if (n == x) { selection_add_index(&sel, 0); sel.entity = entity__x; return sel; - } else if (field_name == y) { + } else if (n == y) { selection_add_index(&sel, 1); sel.entity = entity__y; return sel; - } else if (field_name == z) { + } else if (n == z) { selection_add_index(&sel, 2); sel.entity = entity__z; return sel; @@ -3928,19 +3938,21 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name gb_local_persist Entity *entity__x = alloc_entity_field(nullptr, make_token_ident(x), t_untyped_float, false, 0); gb_local_persist Entity *entity__y = alloc_entity_field(nullptr, make_token_ident(y), t_untyped_float, false, 1); gb_local_persist Entity *entity__z = alloc_entity_field(nullptr, make_token_ident(z), t_untyped_float, false, 2); - if (field_name == w) { + + String n = field_name.string(); + if (n == w) { selection_add_index(&sel, 3); sel.entity = entity__w; return sel; - } else if (field_name == x) { + } else if (n == x) { selection_add_index(&sel, 0); sel.entity = entity__x; return sel; - } else if (field_name == y) { + } else if (n == y) { selection_add_index(&sel, 1); sel.entity = entity__y; return sel; - } else if (field_name == z) { + } else if (n == z) { selection_add_index(&sel, 2); sel.entity = entity__z; return sel; @@ -3955,7 +3967,8 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name String allocator_str = str_lit("allocator"); gb_local_persist Entity *entity__allocator = alloc_entity_field(nullptr, make_token_ident(allocator_str), t_allocator, false, 3); - if (field_name == allocator_str) { + String n = field_name.string(); + if (n == allocator_str) { selection_add_index(&sel, 3); sel.entity = entity__allocator; return sel; @@ -3965,7 +3978,8 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name String allocator_str = str_lit("allocator"); gb_local_persist Entity *entity__allocator = alloc_entity_field(nullptr, make_token_ident(allocator_str), t_allocator, false, 2); - if (field_name == allocator_str) { + String n = field_name.string(); + if (n == allocator_str) { selection_add_index(&sel, 2); sel.entity = entity__allocator; return sel; @@ -3973,7 +3987,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name #define _ARRAY_FIELD_CASE_IF(_length, _name) \ - if (field_name == (_name)) { \ + if (n == (_name)) { \ selection_add_index(&sel, (_length)-1); \ sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), elem, (_length)-1); \ return sel; \ @@ -3986,7 +4000,7 @@ case (_length): \ } else if (type->kind == Type_Array) { - + String n = field_name.string(); Type *elem = type->Array.elem; if (type->Array.count <= 4) { @@ -4001,8 +4015,9 @@ case (_length): \ } } } else if (type->kind == Type_SimdVector) { - + String n = field_name.string(); Type *elem = type->SimdVector.elem; + if (type->SimdVector.count <= 4) { // HACK(bill): Memory leak switch (type->SimdVector.count) {