Merge pull request #7701 from odin-lang/bill/multithread-global-decls

Multithread The Entire Semantic Checker
This commit is contained in:
gingerBill authored and GitHub committed 2026-10-02 14:17:23 +01:00
commit 161f6e30e6
36 files changed
+4142 -1430

No files matched your search

+53 -19
View File
@@ -155,6 +155,7 @@ struct TypeStruct {
i32 soa_count;
StructSoaKind soa_kind;
Wait_Signal fields_wait_signal;
Futex checking_thread; // 1 + the index of the thread in `check_struct_type` for it, else 0
BlockingMutex soa_mutex;
BlockingMutex offset_mutex; // for settings offsets
@@ -181,6 +182,7 @@ struct TypeUnion {
Type * polymorphic_parent;
Wait_Signal polymorphic_wait_signal;
Wait_Signal variants_wait_signal; // signalled once `variants` is populated (mirrors TypeStruct.fields_wait_signal)
Futex checking_thread; // 1 + the index of the thread in `check_union_type` for it, else 0
std::atomic<i16> tag_size;
bool is_polymorphic;
@@ -338,7 +340,6 @@ gb_global String const type_strings[] = {
enum TypeFlag : u32 {
TypeFlag_Polymorphic = 1<<1,
TypeFlag_PolySpecialized = 1<<2,
TypeFlag_InProcessOfCheckingPolymorphic = 1<<3,
};
struct Type {
@@ -354,7 +355,7 @@ struct Type {
std::atomic<i64> cached_align;
std::atomic<u64> canonical_hash;
std::atomic<u32> flags; // TypeFlag
bool failure;
std::atomic<bool> failure;
};
// IMPORTANT NOTE(bill): This must match the same as the in core.odin
@@ -414,6 +415,7 @@ gb_internal bool is_type_simple_compare(Type *t);
gb_internal Type *type_deref(Type *t, bool allow_multi_pointer=false);
gb_internal Type *base_type(Type *t);
gb_internal Type *alloc_type_multi_pointer(Type *elem);
gb_internal void wait_for_record_signal(Wait_Signal *signal, Futex *checking_thread);
gb_internal u32 type_info_flags_of_type(Type *type) {
if (type == nullptr) {
@@ -2495,13 +2497,13 @@ gb_internal TypeTuple *get_record_polymorphic_params(Type *t) {
t = base_type(t);
switch (t->kind) {
case Type_Struct:
wait_signal_until_available(&t->Struct.polymorphic_wait_signal);
wait_for_record_signal(&t->Struct.polymorphic_wait_signal, &t->Struct.checking_thread);
if (t->Struct.polymorphic_params) {
return &t->Struct.polymorphic_params->Tuple;
}
break;
case Type_Union:
wait_signal_until_available(&t->Union.polymorphic_wait_signal);
wait_for_record_signal(&t->Union.polymorphic_wait_signal, &t->Union.checking_thread);
if (t->Union.polymorphic_params) {
return &t->Union.polymorphic_params->Tuple;
}
@@ -2511,13 +2513,24 @@ gb_internal TypeTuple *get_record_polymorphic_params(Type *t) {
}
gb_internal TypeNameObjCMetadata *entity_objc_metadata(Entity *e) {
GB_ASSERT(e->kind == Entity_TypeName);
mutex_lock(&global_type_name_objc_metadata_mutex);
TypeNameObjCMetadata *md = e->TypeName.objc_metadata;
Type *original = e->TypeName.original_type_for_parapoly;
if (md == nullptr && original != nullptr && original->kind == Type_Named && original->Named.type_name != nullptr) {
md = original->Named.type_name->TypeName.objc_metadata;
}
mutex_unlock(&global_type_name_objc_metadata_mutex);
return md;
}
gb_internal gb_thread_local Array<Type *> is_type_polymorphic_named_stack;
gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) {
if (t == nullptr) {
return false;
}
if (t->flags & TypeFlag_InProcessOfCheckingPolymorphic) {
return false;
}
switch (t->kind) {
case Type_Generic:
@@ -2525,10 +2538,18 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) {
case Type_Named:
{
u32 flags = t->flags;
t->flags |= TypeFlag_InProcessOfCheckingPolymorphic;
Array<Type *> &stack = is_type_polymorphic_named_stack;
for (Type *named : stack) {
if (named == t) {
return false;
}
}
if (stack.allocator.proc == nullptr) {
array_init(&stack, heap_allocator());
}
array_add(&stack, t);
bool ok = is_type_polymorphic(t->Named.base, or_specialized);
t->flags = flags;
array_pop(&stack);
return ok;
}
@@ -3559,7 +3580,7 @@ gb_internal bool union_variant_index_types_equal(Type *v, Type *vt) {
gb_internal i64 union_variant_index_checked(Type *u, Type *v) {
u = base_type(u);
GB_ASSERT(u->kind == Type_Union);
wait_signal_until_available(&u->Union.variants_wait_signal);
wait_for_record_signal(&u->Union.variants_wait_signal, &u->Union.checking_thread);
for_array(i, u->Union.variants) {
Type *vt = u->Union.variants[i];
@@ -3578,7 +3599,7 @@ gb_internal i64 union_variant_index_checked(Type *u, Type *v) {
gb_internal bool union_is_variant_of(Type *u, Type *v) {
u = base_type(u);
GB_ASSERT(u->kind == Type_Union);
wait_signal_until_available(&u->Union.variants_wait_signal);
wait_for_record_signal(&u->Union.variants_wait_signal, &u->Union.checking_thread);
for_array(i, u->Union.variants) {
Type *vt = u->Union.variants[i];
@@ -3769,7 +3790,7 @@ gb_internal Selection lookup_field_from_index(Type *type, i64 index) {
isize max_count = 0;
switch (type->kind) {
case Type_Struct:
wait_signal_until_available(&type->Struct.fields_wait_signal);
wait_for_record_signal(&type->Struct.fields_wait_signal, &type->Struct.checking_thread);
max_count = type->Struct.fields.count;
break;
case Type_Tuple: max_count = type->Tuple.variables.count; break;
@@ -3781,7 +3802,7 @@ gb_internal Selection lookup_field_from_index(Type *type, i64 index) {
switch (type->kind) {
case Type_Struct: {
wait_signal_until_available(&type->Struct.fields_wait_signal);
wait_for_record_signal(&type->Struct.fields_wait_signal, &type->Struct.checking_thread);
for (isize i = 0; i < max_count; i++) {
Entity *f = type->Struct.fields[i];
if (f->kind == Entity_Variable) {
@@ -3832,8 +3853,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, InternedString fi
if (has_type_got_objc_class_attribute(original_type) && original_type->kind == Type_Named) {
Entity *e = original_type->Named.type_name;
GB_ASSERT(e->kind == Entity_TypeName);
if (e->TypeName.objc_metadata) {
auto *md = e->TypeName.objc_metadata;
if (auto *md = entity_objc_metadata(e)) {
mutex_lock(md->mutex);
defer (mutex_unlock(md->mutex));
for (TypeNameObjCMetadataEntry const &entry : md->type_entries) {
@@ -3924,8 +3944,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, InternedString fi
if (has_type_got_objc_class_attribute(original_type) && original_type->kind == Type_Named) {
Entity *e = original_type->Named.type_name;
GB_ASSERT(e->kind == Entity_TypeName);
if (e->TypeName.objc_metadata) {
auto *md = e->TypeName.objc_metadata;
if (auto *md = entity_objc_metadata(e)) {
mutex_lock(md->mutex);
defer (mutex_unlock(md->mutex));
for (TypeNameObjCMetadataEntry const &entry : md->value_entries) {
@@ -3952,7 +3971,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, InternedString fi
// NOTE(bill): A polymorphic struct has no fields, this only hits in the case of an error
return sel;
}
wait_signal_until_available(&type->Struct.fields_wait_signal);
wait_for_record_signal(&type->Struct.fields_wait_signal, &type->Struct.checking_thread);
isize field_count = type->Struct.fields.count;
if (field_count != 0) for_array(i, type->Struct.fields) {
Entity *f = type->Struct.fields[i];
@@ -4422,6 +4441,18 @@ gb_internal i64 type_target_max_align(void) {
return max_align;
}
gb_internal void wait_for_record_signal(Wait_Signal *signal, Futex *checking_thread) {
if (signal->futex.load() == 0) {
thread_wait_for_owner(&signal->futex, 0, checking_thread->load());
}
}
gb_internal void wait_for_struct_fields(Type *t) {
if (t->Struct.polymorphic_parent != nullptr) {
wait_for_record_signal(&t->Struct.fields_wait_signal, &t->Struct.checking_thread);
}
}
gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
GB_ASSERT(path != nullptr);
if (t->failure) {
@@ -4546,6 +4577,7 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
} break;
case Type_Struct: {
wait_for_struct_fields(t);
if (t->Struct.custom_align > 0) {
return gb_max(t->Struct.custom_align, 1);
}
@@ -4660,6 +4692,7 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
gb_internal bool type_set_offsets(Type *t) {
t = base_type(t);
if (t->kind == Type_Struct) {
wait_for_struct_fields(t);
// if (t->Struct.are_offsets_being_processed.load()) {
// return true;
// }
@@ -4864,6 +4897,7 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
case Type_Struct: {
wait_for_struct_fields(t);
if (t->Struct.is_raw_union) {
i64 count = t->Struct.fields.count;
i64 align = type_align_of_internal(t, path);