mirror of
https://github.com/odin-lang/Odin.git
synced 2026-10-14 16:28:44 -04:00
Merge pull request #7701 from odin-lang/bill/multithread-global-decls
Multithread The Entire Semantic Checker
This commit is contained in:
36 files changed
+4142
-1430
No files matched your search
+53
-19
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user