Fix a race condition when produced anonymous procedure literals with -use-separate-modules

This commit is contained in:
gingerBill
2023-06-13 13:14:59 +01:00
parent 296674e18b
commit 581eebb197
5 changed files with 99 additions and 55 deletions

View File

@@ -334,10 +334,35 @@ gb_internal bool lb_is_instr_terminating(LLVMValueRef instr) {
return false;
}
gb_internal lbModule *lb_module_of_expr(lbGenerator *gen, Ast *expr) {
GB_ASSERT(expr != nullptr);
lbModule **found = nullptr;
AstFile *file = expr->file();
if (file) {
found = map_get(&gen->modules, cast(void *)file);
if (found) {
return *found;
}
if (file->pkg) {
found = map_get(&gen->modules, cast(void *)file->pkg);
if (found) {
return *found;
}
}
}
return &gen->default_module;
}
gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e) {
GB_ASSERT(e != nullptr);
lbModule **found = nullptr;
if (e->kind == Entity_Procedure &&
e->decl_info &&
e->decl_info->code_gen_module) {
return e->decl_info->code_gen_module;
}
if (e->file) {
found = map_get(&gen->modules, cast(void *)e->file);
if (found) {
@@ -2661,9 +2686,12 @@ gb_internal lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *e
gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) {
lbGenerator *gen = m->gen;
GB_ASSERT(is_type_proc(e->type));
e = strip_entity_wrapping(e);
GB_ASSERT(e != nullptr);
GB_ASSERT(e->kind == Entity_Procedure);
lbValue *found = nullptr;
rw_mutex_shared_lock(&m->values_mutex);
@@ -2677,20 +2705,24 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e)
lbModule *other_module = m;
if (USE_SEPARATE_MODULES) {
other_module = lb_module_of_entity(m->gen, e);
other_module = lb_module_of_entity(gen, e);
}
if (other_module == m) {
debugf("Missing Procedure (lb_find_procedure_value_from_entity): %.*s\n", LIT(e->token.string));
debugf("Missing Procedure (lb_find_procedure_value_from_entity): %.*s module %p\n", LIT(e->token.string), m);
}
ignore_body = other_module != m;
lbProcedure *missing_proc = lb_create_procedure(m, e, ignore_body);
if (ignore_body) {
mutex_lock(&gen->anonymous_proc_lits_mutex);
defer (mutex_unlock(&gen->anonymous_proc_lits_mutex));
GB_ASSERT(other_module != nullptr);
rw_mutex_shared_lock(&other_module->values_mutex);
auto *found = map_get(&other_module->values, e);
rw_mutex_shared_unlock(&other_module->values_mutex);
if (found == nullptr) {
// THIS IS THE RACE CONDITION
lbProcedure *missing_proc_in_other_module = lb_create_procedure(other_module, e, false);
array_add(&other_module->missing_procedures_to_check, missing_proc_in_other_module);
}
@@ -2707,6 +2739,63 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e)
}
gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent) {
lbGenerator *gen = m->gen;
mutex_lock(&gen->anonymous_proc_lits_mutex);
defer (mutex_unlock(&gen->anonymous_proc_lits_mutex));
TokenPos pos = ast_token(expr).pos;
lbProcedure **found = map_get(&gen->anonymous_proc_lits, expr);
if (found) {
return lb_find_procedure_value_from_entity(m, (*found)->entity);
}
ast_node(pl, ProcLit, expr);
// NOTE(bill): Generate a new name
// parent$count
isize name_len = prefix_name.len + 6 + 11;
char *name_text = gb_alloc_array(permanent_allocator(), char, name_len);
static std::atomic<i32> name_id;
name_len = gb_snprintf(name_text, name_len, "%.*s$anon-%d", LIT(prefix_name), 1+name_id.fetch_add(1));
String name = make_string((u8 *)name_text, name_len-1);
Type *type = type_of_expr(expr);
GB_ASSERT(pl->decl->entity == nullptr);
Token token = {};
token.pos = ast_token(expr).pos;
token.kind = Token_Ident;
token.string = name;
Entity *e = alloc_entity_procedure(nullptr, token, type, pl->tags);
e->file = expr->file();
// NOTE(bill): this is to prevent a race condition since these procedure literals can be created anywhere at any time
pl->decl->code_gen_module = m;
e->decl_info = pl->decl;
pl->decl->entity = e;
e->flags |= EntityFlag_ProcBodyChecked;
lbProcedure *p = lb_create_procedure(m, e);
GB_ASSERT(e->code_gen_module == m);
lbValue value = {};
value.value = p->value;
value.type = p->type;
map_set(&gen->anonymous_proc_lits, expr, p);
array_add(&m->procedures_to_generate, p);
if (parent != nullptr) {
array_add(&parent->children, p);
} else {
string_map_set(&m->members, name, value);
}
return value;
}
gb_internal lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value, Entity **entity_) {
GB_ASSERT(type != nullptr);
type = default_type(type);