Merge pull request #6438 from odin-lang/bill/interning-things

Continuous Compiler Improvements
This commit is contained in:
gingerBill
2026-03-17 14:55:50 +00:00
committed by GitHub
21 changed files with 534 additions and 282 deletions

View File

@@ -57,6 +57,8 @@ gb_internal void big_int_dealloc(BigInt *dst) {
mp_clear(dst);
}
gb_internal bool big_int_can_be_represented_in_64_bits(BigInt const *x);
gb_internal BigInt big_int_make(BigInt const *b, bool abs=false);
gb_internal BigInt big_int_make_abs(BigInt const *b);
gb_internal BigInt big_int_make_u64(u64 x);
@@ -293,6 +295,11 @@ gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success
gb_internal bool big_int_can_be_represented_in_64_bits(BigInt const *x) {
int bits_used = (x->used-1) * MP_DIGIT_BIT;
return bits_used <= 64;
}
gb_internal u64 big_int_to_u64(BigInt const *x) {
GB_ASSERT(x->sign == 0);
return mp_get_u64(x);

View File

@@ -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;
}

View File

@@ -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});
}
}
}

View File

@@ -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());
}
}
@@ -1090,18 +1090,20 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
return;
}
// Grab definite or indefinite article matching `context_name`, or "" if not found.
String article = error_article(context_name);
if (is_type_untyped(operand->type)) {
Type *target_type = type;
if (type == nullptr || is_type_any(type)) {
if (type == nullptr && is_type_untyped_uninit(operand->type)) {
String article = error_article(context_name); // Grab definite or indefinite article matching `context_name`, or "" if not found.
error(operand->expr, "Use of --- in %.*s%.*s", LIT(article), LIT(context_name));
operand->mode = Addressing_Invalid;
return;
}
if (type == nullptr && is_type_untyped_nil(operand->type)) {
String article = error_article(context_name); // Grab definite or indefinite article matching `context_name`, or "" if not found.
error(operand->expr, "Use of untyped nil in %.*s%.*s", LIT(article), LIT(context_name));
operand->mode = Addressing_Invalid;
return;
@@ -1159,6 +1161,8 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
defer (gb_string_free(op_type_str));
defer (gb_string_free(expr_str));
String article = error_article(context_name); // Grab definite or indefinite article matching `context_name`, or "" if not found.
// TODO(bill): is this a good enough error message?
error(operand->expr,
"Cannot assign overloaded procedure group '%s' to '%s' in %.*s%.*s",
@@ -1187,6 +1191,8 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
defer (gb_string_free(op_type_str));
defer (gb_string_free(expr_str));
String article = error_article(context_name); // Grab definite or indefinite article matching `context_name`, or "" if not found.
switch (operand->mode) {
case Addressing_Builtin:
error(operand->expr,
@@ -1329,7 +1335,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, 0);
GB_ASSERT(e != nullptr);
if (e->kind == Entity_TypeName) {
*gt_ = nullptr;
@@ -1430,7 +1436,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, 0);
GB_ASSERT(e != nullptr);
if (e->kind == Entity_TypeName) {
Type *index = source->EnumeratedArray.index;
@@ -1770,9 +1776,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, n->Ident.hash);
if (e == nullptr) {
if (is_blank_ident(name)) {
error(n, "'_' cannot be used as a value");
@@ -2161,9 +2167,13 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i
BigInt i = v.value_integer;
i64 byte_size = type_size_of(type);
BigInt umax = {};
BigInt imin = {};
BigInt imax = {};
BigInt umax;
BigInt imin;
BigInt imax;
u64 umax_64 = 0;
i64 imin_64 = 0;
i64 imax_64 = 0;
if (c->bit_field_bit_size > 0) {
i64 bit_size = gb_min(cast(i64)(8*byte_size), cast(i64)c->bit_field_bit_size);
@@ -2186,10 +2196,10 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i
big_int_shl_eq(&imax, &bi);
mp_decr(&imax);
} else {
if (byte_size < 16) {
big_int_from_u64(&umax, unsigned_integer_maxs[byte_size]);
big_int_from_i64(&imin, signed_integer_mins[byte_size]);
big_int_from_i64(&imax, signed_integer_maxs[byte_size]);
if (byte_size <= 8) {
umax_64 = unsigned_integer_maxs[byte_size];
imin_64 = signed_integer_mins[byte_size];
imax_64 = signed_integer_maxs[byte_size];
} else {
big_int_from_u64(&umax, 1);
big_int_from_i64(&imin, 1);
@@ -2217,16 +2227,27 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i
case Basic_i16:
case Basic_i32:
case Basic_i64:
case Basic_i128:
case Basic_int:
case Basic_i16le:
case Basic_i32le:
case Basic_i64le:
case Basic_i128le:
case Basic_i16be:
case Basic_i32be:
case Basic_i64be:
if (c->bit_field_bit_size == 0) {
// return imin <= i && i <= imax;
if (!big_int_can_be_represented_in_64_bits(&i)) {
return false;
}
i64 val64 = big_int_to_i64(&i);
return imin_64 <= val64 && val64 <= imax_64;
}
/*fallthrough*/
case Basic_i128le:
case Basic_i128:
case Basic_i128be:
{
// return imin <= i && i <= imax;
@@ -2239,17 +2260,30 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i
case Basic_u16:
case Basic_u32:
case Basic_u64:
case Basic_u128:
case Basic_uint:
case Basic_uintptr:
case Basic_u16le:
case Basic_u32le:
case Basic_u64le:
case Basic_u128le:
case Basic_u16be:
case Basic_u32be:
case Basic_u64be:
if (c->bit_field_bit_size == 0) {
if (big_int_is_neg(&i)) {
return false;
}
if (!big_int_can_be_represented_in_64_bits(&i)) {
return false;
}
u64 val64 = big_int_to_u64(&i);
return val64 <= umax_64;
}
/*fallthrough*/
case Basic_u128:
case Basic_u128le:
case Basic_u128be:
{
// return 0ull <= i && i <= umax;
@@ -5192,7 +5226,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) {
@@ -5458,8 +5492,12 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *
return e;
}
} else */if (node->kind == Ast_Ident) {
Entity *e = node->Ident.entity.load();
if (e != nullptr) {
return e;
}
String name = node->Ident.token.string;
return scope_lookup(c->scope, name, node->Ident.hash);
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 +5519,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, op_expr->Ident.hash);
if (e == nullptr) {
return nullptr;
}
@@ -5494,7 +5532,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 +5558,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 +5616,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, op_expr->Ident.hash);
add_entity_use(c, op_expr, e);
expr_entity = e;
@@ -5596,6 +5634,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 +5645,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 +5693,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 +6032,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, i->hash);
if (e != nullptr) {
if (out_scope) *out_scope = e->scope;
return true;
@@ -7816,11 +7854,14 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
{
// NOTE(bill, 2019-10-26): Allow a cycle in the parameters but not in the fields themselves
auto prev_type_path = c->type_path;
c->type_path = new_checker_type_path();
defer ({
destroy_checker_type_path(c->type_path);
c->type_path = prev_type_path;
});
TEMPORARY_ALLOCATOR_GUARD();
c->type_path = new_checker_type_path(temporary_allocator());
defer (c->type_path = prev_type_path);
if (is_call_expr_field_value(ce)) {
named_fields = true;
operands = array_make<Operand>(temporary_allocator(), ce->args.count);
@@ -8972,7 +9013,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 +9948,9 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
continue;
}
String name = ident->Ident.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 +10905,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;

View File

@@ -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) {

View File

@@ -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));
@@ -37,22 +39,20 @@ gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, Ast
}
Type *original_type = t;
t = base_type(type_deref(t));
gbString str = nullptr;
defer (gb_string_free(str));
if (node != nullptr) {
str = expr_to_string(node);
}
if (t->kind == Type_Struct) {
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
if (str != nullptr) {
if (node != nullptr) {
gbString str = expr_to_string(node);
error(e->token, "'%.*s' is already declared in '%s', through 'using' from '%s'", LIT(name), str, ot);
gb_string_free(str);
} else {
error(e->token, "'%.*s' is already declared, through 'using' from '%s'", LIT(name), ot);
}
@@ -102,9 +102,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);
@@ -117,6 +114,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;
@@ -172,7 +175,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;
@@ -423,7 +429,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)) {
@@ -973,6 +979,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;
@@ -981,7 +991,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 +1055,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 +1106,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 +1526,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, 0);
GB_ASSERT(e != nullptr);
if (modify_type) {
e->kind = Entity_Constant;
@@ -1566,7 +1579,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, 0);
GB_ASSERT(e != nullptr);
if (modify_type) {
e->kind = Entity_Constant;
@@ -1844,6 +1857,11 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
bool is_c_vararg = false;
auto variables = array_make<Entity *>(permanent_allocator(), 0, variable_count);
i32 field_group_index = -1;
Entity *entities_to_use = permanent_alloc_array<Entity>(variable_count);
isize entities_to_use_index = 0;
for_array(i, params) {
Ast *param = params[i];
if (param->kind != Ast_Field) {
@@ -1905,7 +1923,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;
@@ -2083,7 +2101,12 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
p->flags &= ~FieldFlag_no_capture;
}
param = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved);
param = &entities_to_use[entities_to_use_index++];
INTERNAL_ENTITY_INIT(param, Entity_TypeName, scope, name->Ident.token, type);
param->state = EntityState_Resolved;
param->interned_name.store(name->Ident.interned);
param->interned_name_hash.store(name->Ident.hash);
param->TypeName.is_type_alias = true;
} else {
ExactValue poly_const = {};
@@ -2237,10 +2260,36 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
// failed
}
param = alloc_entity_const_param(scope, name->Ident.token, type, poly_const, is_type_polymorphic(type));
// param = alloc_entity_const_param(scope, name->Ident.token, type, poly_const, is_type_polymorphic(type));
param = &entities_to_use[entities_to_use_index++];
INTERNAL_ENTITY_INIT(param, Entity_Constant, scope, name->Ident.token, type);
param->flags |= EntityFlag_Used|EntityFlag_Param;
if (is_type_polymorphic(type)) {
param->flags |= EntityFlag_PolyConst;
}
param->Constant.value = poly_const;
param->interned_name.store(name->Ident.interned);
param->interned_name_hash.store(name->Ident.hash);
param->Constant.field_group_index = field_group_index;
} else {
param = alloc_entity_param(scope, name->Ident.token, type, is_using, true);
// param = alloc_entity_param(scope, name->Ident.token, type, is_using, true);
param = &entities_to_use[entities_to_use_index++];
INTERNAL_ENTITY_INIT(param, Entity_Variable, scope, name->Ident.token, type);
param->state = EntityState_Resolved;
param->flags |= EntityFlag_Used|EntityFlag_Param|EntityFlag_Value;
if (is_using) {
param->flags |= EntityFlag_Using;
}
param->interned_name.store(name->Ident.interned);
param->interned_name_hash.store(name->Ident.hash);
param->Variable.param_value = param_value;
param->Variable.field_group_index = field_group_index;
param->Variable.type_expr = type_expr;
@@ -2330,8 +2379,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;
}
@@ -2394,6 +2442,9 @@ gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_res
}
}
Entity *entities_to_use = permanent_alloc_array<Entity>(variable_count);
isize entities_to_use_index = 0;
auto variables = array_make<Entity *>(permanent_allocator(), 0, variable_count);
i32 field_group_index = -1;
for_array(i, results) {
@@ -2408,7 +2459,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);
}
@@ -2432,7 +2483,12 @@ gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_res
if (field->names.count == 0) {
Token token = ast_token(field->type);
token.string = str_lit("");
Entity *param = alloc_entity_param(scope, token, type, false, false);
// Entity *param = alloc_entity_param(scope, token, type, false, false);
Entity *param = &entities_to_use[entities_to_use_index++];
INTERNAL_ENTITY_INIT(param, Entity_Variable, scope, token, type);
param->state = EntityState_Resolved;
param->flags |= EntityFlag_Used|EntityFlag_Param|EntityFlag_Result;
param->Variable.param_value = param_value;
param->Variable.field_group_index = -1;
array_add(&variables, param);
@@ -2455,8 +2511,17 @@ gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_res
error(name, "Result value cannot be a blank identifer `_`");
}
Entity *param = alloc_entity_param(scope, token, type, false, false);
param->flags |= EntityFlag_Result;
// Entity *param = alloc_entity_param(scope, token, type, false, false);
Entity *param = &entities_to_use[entities_to_use_index++];
INTERNAL_ENTITY_INIT(param, Entity_Variable, scope, token, type);
param->state = EntityState_Resolved;
param->flags |= EntityFlag_Used|EntityFlag_Param|EntityFlag_Result;
if (name->kind == Ast_Ident) {
param->interned_name.store(name->Ident.interned);
param->interned_name_hash.store(name->Ident.hash);
}
param->Variable.param_value = param_value;
param->Variable.field_group_index = field_group_index;
array_add(&variables, param);
@@ -3534,7 +3599,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));
@@ -3615,7 +3680,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
CheckerContext c = *ctx;
TEMPORARY_ALLOCATOR_GUARD();
c.type_path = new_checker_type_path(temporary_allocator());
c.type_path = new_checker_type_path();
defer (destroy_checker_type_path(c.type_path));
Type *elem = t_invalid;
Operand o = {};
@@ -3888,8 +3954,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
gb_internal Type *check_type(CheckerContext *ctx, Ast *e) {
CheckerContext c = *ctx;
TEMPORARY_ALLOCATOR_GUARD();
c.type_path = new_checker_type_path(temporary_allocator());
c.type_path = new_checker_type_path();
defer (destroy_checker_type_path(c.type_path));
return check_type_expr(&c, e, nullptr);
}

View File

@@ -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<bool> 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,8 @@ gb_internal bool check_vet_shadowing(Checker *c, Entity *e, VettedEntity *ve) {
return false;
}
Entity *shadowed = scope_lookup(parent, name);
auto interned = entity_interned_name(e);
Entity *shadowed = scope_lookup(parent, interned, e->interned_name_hash.load());
if (shadowed == nullptr) {
return false;
}
@@ -961,8 +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);
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, n);
Entity *e = scope_lookup(p->scope, key, hash);
GB_ASSERT_MSG(e != nullptr, "%s", name);
GB_ASSERT(c->decl != nullptr);
e->flags |= EntityFlag_Used;
@@ -974,8 +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);
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, n);
Entity *e = scope_lookup(p->scope, key, hash);
if (e == nullptr) {
return;
}
@@ -1373,6 +1366,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 +1377,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;
}
}
@@ -1554,12 +1550,12 @@ gb_internal void init_checker_context(CheckerContext *ctx, Checker *c) {
ctx->scope = builtin_pkg->scope;
ctx->pkg = builtin_pkg;
ctx->type_path = new_checker_type_path(heap_allocator());
ctx->type_path = new_checker_type_path();
ctx->type_level = 0;
}
gb_internal void destroy_checker_context(CheckerContext *ctx) {
destroy_checker_type_path(ctx->type_path, heap_allocator());
destroy_checker_type_path(ctx->type_path);
}
gb_internal bool add_curr_ast_file(CheckerContext *ctx, AstFile *file) {
@@ -2763,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, name);
u32 hash = 0;
auto interned = string_interner_insert(name, 0, &hash);
Entity *e = scope_lookup(scope, interned, hash);
if (e == nullptr) {
return;
}
@@ -2775,7 +2773,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 +3229,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 +3241,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 +3258,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 +3270,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!
@@ -3274,16 +3282,24 @@ gb_internal Type *find_type_in_pkg(CheckerInfo *info, String const &pkg, String
return e->type;
}
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;
gb_internal gb_thread_local std::atomic<AtomicFreelist<CheckerTypePath> *> checker_type_path_free_list;
gb_internal CheckerTypePath *new_checker_type_path() {
// TODO(bill): Cache to reuse `CheckerTypePath
auto *tp = atomic_freelist_get(checker_type_path_free_list);
if (tp == nullptr) {
tp = permanent_alloc_item<AtomicFreelist<CheckerTypePath> >();
array_init(&tp->value, permanent_allocator(), 0, 16);
}
return &tp->value;
}
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) {
auto *tp = cast(AtomicFreelist<CheckerTypePath> *)path;
array_clear(&tp->value);
atomic_freelist_put(checker_type_path_free_list, tp);
}
gb_internal void check_type_path_push(CheckerContext *c, Entity *e) {
@@ -4558,7 +4574,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 +7532,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;

View File

@@ -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<String>(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);
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);
@@ -909,8 +909,8 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &n
gb_internal void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws);
gb_internal void check_delayed_file_import_entity(CheckerContext *c, Ast *decl);
gb_internal CheckerTypePath *new_checker_type_path(gbAllocator allocator);
gb_internal void destroy_checker_type_path(CheckerTypePath *tp, gbAllocator allocator);
gb_internal CheckerTypePath *new_checker_type_path();
gb_internal void destroy_checker_type_path(CheckerTypePath *tp);
gb_internal void check_type_path_push(CheckerContext *c, Entity *e);
gb_internal Entity *check_type_path_pop (CheckerContext *c);

View File

@@ -1050,7 +1050,8 @@ gb_internal OdinDocArray<OdinDocScopeEntry> 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<OdinDocScopeEntry> 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);
}

View File

@@ -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<Ast *> identifier; // Can be nullptr
std::atomic<InternedString> interned_name;
std::atomic<u32> interned_name_hash;
DeclInfo * decl_info;
std::atomic<DeclInfo *> 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,22 +359,23 @@ gb_internal bool entity_has_deferred_procedure(Entity *e) {
gb_global std::atomic<u64> 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); \
} \
} 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;
}
@@ -397,10 +412,9 @@ gb_internal Entity *alloc_entity_type_name(Scope *scope, Token token, Type *type
}
gb_internal Entity *alloc_entity_param(Scope *scope, Token token, Type *type, bool is_using, bool is_value) {
Entity *entity = alloc_entity_variable(scope, token, type);
Entity *entity = alloc_entity_variable(scope, token, type, EntityState_Resolved);
entity->flags |= EntityFlag_Used;
entity->flags |= EntityFlag_Param;
entity->state = EntityState_Resolved;
if (is_using) entity->flags |= EntityFlag_Using;
if (is_value) entity->flags |= EntityFlag_Value;
return entity;

View File

@@ -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));
}

View File

@@ -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]];

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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, "$");

View File

@@ -1,11 +1,14 @@
enum {PTR_SET_INLINE_CAP = 16};
template <typename T>
struct PtrSet {
static_assert(TypeIsPointer<T>::value || TypeIsPtrSizedInteger<T>::value, "PtrSet::T must be a pointer");
static constexpr uintptr TOMBSTONE = ~(uintptr)(0ull);
T * keys;
usize count;
usize capacity;
T * keys;
u32 count;
u32 capacity;
T inline_keys[PTR_SET_INLINE_CAP];
};
template <typename T> gb_internal void ptr_set_init (PtrSet<T> *s, isize capacity = 16);
@@ -27,17 +30,23 @@ template <typename T>
gb_internal void ptr_set_init(PtrSet<T> *s, isize capacity) {
GB_ASSERT(s->keys == nullptr);
if (capacity != 0) {
capacity = next_pow2_isize(gb_max(16, capacity));
s->keys = gb_alloc_array(ptr_set_allocator(), T, capacity);
capacity = next_pow2_isize(gb_max(PTR_SET_INLINE_CAP, capacity));
if (capacity > PTR_SET_INLINE_CAP) {
s->keys = gb_alloc_array(ptr_set_allocator(), T, capacity);
} else {
s->keys = s->inline_keys;
}
// This memory will be zeroed, no need to explicitly zero it
}
s->count = 0;
s->capacity = capacity;
s->capacity = cast(u32)capacity;
}
template <typename T>
gb_internal void ptr_set_destroy(PtrSet<T> *s) {
gb_free(ptr_set_allocator(), s->keys);
if (s->keys != s->inline_keys) {
gb_free(ptr_set_allocator(), s->keys);
}
s->keys = nullptr;
s->count = 0;
s->capacity = 0;
@@ -47,16 +56,10 @@ template <typename T>
gb_internal isize ptr_set__find(PtrSet<T> *s, T ptr) {
GB_ASSERT(ptr != 0);
if (s->count != 0) {
#if 0
for (usize i = 0; i < s->capacity; i++) {
if (s->keys[i] == ptr) {
return i;
}
}
#else
u32 hash = ptr_map_hash_key(ptr);
usize mask = s->capacity-1;
usize hash_index = cast(usize)hash & mask;
for (usize i = 0; i < s->capacity; i++) {
T key = s->keys[hash_index];
if (key == ptr) {
@@ -66,14 +69,14 @@ gb_internal isize ptr_set__find(PtrSet<T> *s, T ptr) {
}
hash_index = (hash_index+1)&mask;
}
#endif
}
return -1;
}
template <typename T>
gb_internal bool ptr_set__full(PtrSet<T> *s) {
return 0.75f * s->capacity <= s->count;
usize grow_at = s->capacity - (s->capacity>>2);
return s->count >= grow_at;
}
template <typename T>
@@ -187,11 +190,36 @@ gb_internal T ptr_set_add(PtrSet<T> *s, T ptr) {
template <typename T>
gb_internal void ptr_set_remove(PtrSet<T> *s, T ptr) {
isize index = ptr_set__find(s, ptr);
if (index >= 0) {
GB_ASSERT(s->count > 0);
s->keys[index] = (T)PtrSet<T>::TOMBSTONE;
s->count--;
if (index < 0) {
return;
}
#if 0
u32 mask = s->capacity-1;
u32 i = cast(u32)index;
s->count -= 1;
for (;;) {
u32 next = (i + 1) & mask;
T key = s->keys[next];
if (key == 0) {
break;
}
u32 natural = ptr_map_hash_key(key) & mask;
if (((next - natural) & mask) == 0) {
break;
}
s->keys[i] = key;
i = next;
}
s->keys[i] = 0;
#else
GB_ASSERT(s->count > 0);
s->keys[index] = (T)PtrSet<T>::TOMBSTONE;
s->count--;
#endif
}
template <typename T>

View File

@@ -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<u64> 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);
}

View File

@@ -1201,3 +1201,41 @@ void futex_wait(Futex *f, Footex val) {
#if defined(GB_SYSTEM_WINDOWS)
#pragma warning(pop)
#endif
template <typename T>
struct AtomicFreelist {
T value;
std::atomic<AtomicFreelist<T> *> next;
};
template <typename T>
AtomicFreelist<T> *atomic_freelist_get(std::atomic<AtomicFreelist<T> *> &head) {
AtomicFreelist<T> *elem = nullptr;
for (;;) {
elem = head.load(std::memory_order_acquire);
if (elem == nullptr) {
return nullptr;
}
if (head.compare_exchange_weak(elem, elem->next.load(std::memory_order_acquire), std::memory_order_acquire, std::memory_order_relaxed)) {
elem->next.store(nullptr, std::memory_order_relaxed);
return elem;
}
}
}
template <typename T>
void atomic_freelist_put(std::atomic<AtomicFreelist<T> *> &head_list, AtomicFreelist<T> *elem) {
for (;;) {
auto *head = head_list.load(std::memory_order_relaxed);
elem->next.store(head, std::memory_order_relaxed);
if (head_list.compare_exchange_weak(head, elem, std::memory_order_release, std::memory_order_relaxed)) {
return;
}
}
}

View File

@@ -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) {