aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHarold Brenes <harold@hbrenes.com>2025-04-27 22:48:16 -0400
committerHarold Brenes <harold@hbrenes.com>2025-04-27 22:55:53 -0400
commitf3923ed66640ea9fd342ca851fdd2bd794405e0c (patch)
tree516f3f79213c9b6b2c70c95385e62d6f7cf408b4 /src
parent6c9c239a5ef14a3365121b4964217a9bda255454 (diff)
Fix indentations
Fix Objective-C wrapper procs not forwarding return value
Diffstat (limited to 'src')
-rw-r--r--src/check_builtin.cpp144
-rw-r--r--src/check_decl.cpp174
-rw-r--r--src/checker.cpp150
-rw-r--r--src/checker.hpp18
-rw-r--r--src/checker_builtin_procs.hpp4
-rw-r--r--src/entity.cpp6
-rw-r--r--src/llvm_backend.cpp1108
-rw-r--r--src/llvm_backend.hpp6
-rw-r--r--src/llvm_backend_general.cpp4
-rw-r--r--src/llvm_backend_proc.cpp2
-rw-r--r--src/llvm_backend_utility.cpp14
11 files changed, 822 insertions, 808 deletions
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index 92942b4db..099f99045 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -389,77 +389,77 @@ gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operan
} break;
case BuiltinProc_objc_ivar_get:
- {
- Type *self_type = nullptr;
- Type *ivar_type = nullptr;
-
- Operand self = {};
- check_expr_or_type(c, &self, ce->args[0]);
-
- if (!is_operand_value(self) || !check_is_assignable_to(c, &self, t_objc_id)) {
- gbString e = expr_to_string(self.expr);
- gbString t = type_to_string(self.type);
- error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got '%s' of type %s", LIT(builtin_name), e, t);
- gb_string_free(t);
- gb_string_free(e);
- return false;
- } else if (!is_type_pointer(self.type)) {
- gbString e = expr_to_string(self.expr);
- gbString t = type_to_string(self.type);
- error(self.expr, "'%.*s' expected a pointer of a value derived from intrinsics.objc_object, got '%s' of type %s", LIT(builtin_name), e, t);
- gb_string_free(t);
- gb_string_free(e);
- return false;
- }
-
- self_type = type_deref(self.type);
-
- if (!(self_type->kind == Type_Named &&
- self_type->Named.type_name != nullptr &&
- self_type->Named.type_name->TypeName.objc_class_name != "")) {
- gbString t = type_to_string(self_type);
- error(self.expr, "'%.*s' expected a named type with the attribute @(obj_class=<string>) , got type %s", LIT(builtin_name), t);
- gb_string_free(t);
- return false;
- }
-
- if (self_type->Named.type_name->TypeName.objc_ivar == nullptr) {
- gbString t = type_to_string(self_type);
- error(self.expr, "'%.*s' requires that type %s have the attribute @(obj_ivar=<ivar_type_name>).", LIT(builtin_name), t);
- gb_string_free(t);
- return false;
- }
-
- Operand ivar = {};
- check_expr_or_type(c, &ivar, ce->args[1]);
- if (ivar.mode == Addressing_Type) {
- ivar_type = ivar.type;
- } else {
- return false;
- }
-
- if (self_type->Named.type_name->TypeName.objc_ivar != ivar_type) {
- gbString name_self = type_to_string(self_type);
- gbString name_expected = type_to_string(self_type->Named.type_name->TypeName.objc_ivar);
- gbString name_given = type_to_string(ivar_type);
- error(self.expr, "'%.*s' ivar type %s does not match @obj_ivar type %s on Objective-C class %s.",
- LIT(builtin_name), name_given, name_expected, name_self);
- gb_string_free(name_self);
- gb_string_free(name_expected);
- gb_string_free(name_given);
- return false;
- }
-
- if (type_hint != nullptr && type_hint->kind == Type_Pointer && type_hint->Pointer.elem == ivar_type) {
- operand->type = type_hint;
- } else {
- operand->type = alloc_type_pointer(ivar_type);
- }
-
- operand->mode = Addressing_Value;
-
- return true;
- } break;
+ {
+ Type *self_type = nullptr;
+ Type *ivar_type = nullptr;
+
+ Operand self = {};
+ check_expr_or_type(c, &self, ce->args[0]);
+
+ if (!is_operand_value(self) || !check_is_assignable_to(c, &self, t_objc_id)) {
+ gbString e = expr_to_string(self.expr);
+ gbString t = type_to_string(self.type);
+ error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got '%s' of type %s", LIT(builtin_name), e, t);
+ gb_string_free(t);
+ gb_string_free(e);
+ return false;
+ } else if (!is_type_pointer(self.type)) {
+ gbString e = expr_to_string(self.expr);
+ gbString t = type_to_string(self.type);
+ error(self.expr, "'%.*s' expected a pointer of a value derived from intrinsics.objc_object, got '%s' of type %s", LIT(builtin_name), e, t);
+ gb_string_free(t);
+ gb_string_free(e);
+ return false;
+ }
+
+ self_type = type_deref(self.type);
+
+ if (!(self_type->kind == Type_Named &&
+ self_type->Named.type_name != nullptr &&
+ self_type->Named.type_name->TypeName.objc_class_name != "")) {
+ gbString t = type_to_string(self_type);
+ error(self.expr, "'%.*s' expected a named type with the attribute @(obj_class=<string>) , got type %s", LIT(builtin_name), t);
+ gb_string_free(t);
+ return false;
+ }
+
+ if (self_type->Named.type_name->TypeName.objc_ivar == nullptr) {
+ gbString t = type_to_string(self_type);
+ error(self.expr, "'%.*s' requires that type %s have the attribute @(obj_ivar=<ivar_type_name>).", LIT(builtin_name), t);
+ gb_string_free(t);
+ return false;
+ }
+
+ Operand ivar = {};
+ check_expr_or_type(c, &ivar, ce->args[1]);
+ if (ivar.mode == Addressing_Type) {
+ ivar_type = ivar.type;
+ } else {
+ return false;
+ }
+
+ if (self_type->Named.type_name->TypeName.objc_ivar != ivar_type) {
+ gbString name_self = type_to_string(self_type);
+ gbString name_expected = type_to_string(self_type->Named.type_name->TypeName.objc_ivar);
+ gbString name_given = type_to_string(ivar_type);
+ error(self.expr, "'%.*s' ivar type %s does not match @obj_ivar type %s on Objective-C class %s.",
+ LIT(builtin_name), name_given, name_expected, name_self);
+ gb_string_free(name_self);
+ gb_string_free(name_expected);
+ gb_string_free(name_given);
+ return false;
+ }
+
+ if (type_hint != nullptr && type_hint->kind == Type_Pointer && type_hint->Pointer.elem == ivar_type) {
+ operand->type = type_hint;
+ } else {
+ operand->type = alloc_type_pointer(ivar_type);
+ }
+
+ operand->mode = Addressing_Value;
+
+ return true;
+ } break;
}
}
@@ -2206,7 +2206,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
case BuiltinProc_objc_find_class:
case BuiltinProc_objc_register_selector:
case BuiltinProc_objc_register_class:
- case BuiltinProc_objc_ivar_get:
+ case BuiltinProc_objc_ivar_get:
return check_builtin_objc_procedure(c, operand, call, id, type_hint);
case BuiltinProc___entry_point:
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index e67241b31..48e5172d6 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -526,68 +526,68 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr,
check_decl_attributes(ctx, decl->attributes, type_decl_attribute, &ac);
if (e->kind == Entity_TypeName && ac.objc_class != "") {
e->TypeName.objc_class_name = ac.objc_class;
- e->TypeName.objc_superclass = ac.objc_superclass;
- e->TypeName.objc_ivar = ac.objc_ivar;
+ e->TypeName.objc_superclass = ac.objc_superclass;
+ e->TypeName.objc_ivar = ac.objc_ivar;
e->TypeName.objc_context_provider = ac.objc_context_provider;
- if (ac.objc_is_implementation) {
- e->TypeName.objc_is_implementation = true;
- mpsc_enqueue(&ctx->info->objc_class_implementations, e); // TODO(harold): Don't need this for anything? See if needed when using explicit @export
-
- GB_ASSERT(e->TypeName.objc_ivar == nullptr || e->TypeName.objc_ivar->kind == Type_Named);
-
- // Enqueue the proc to be checked when resolved
- if (e->TypeName.objc_context_provider != nullptr) {
- mpsc_enqueue(&ctx->checker->procs_with_objc_context_provider_to_check, e);
- }
-
- // @TODO(harold): I think there's a Check elsewhere in the checker for checking cycles.
- // See about moving this to the right location.
- // Ensure superclass hierarchy are all Objective-C classes and does not cycle
- Type *super = ac.objc_superclass;
- if (super != nullptr) {
- TypeSet super_set{};
- type_set_init(&super_set, 8);
- defer (type_set_destroy(&super_set));
-
- type_set_update(&super_set, e->type);
-
- for (;;) {
- if (type_set_update(&super_set, super)) {
- error(e->token, "@(objc_superclass) Superclass hierarchy cycle encountered");
- break;
- }
-
- if (super->kind != Type_Named) {
- error(e->token, "@(objc_superclass) References type must be a named struct.");
- break;
- }
-
- Type* named_type = base_type(super->Named.type_name->type);
- if (!is_type_objc_object(named_type)) {
- error(e->token, "@(objc_superclass) Superclass must be an Objective-C class.");
- break;
- }
-
- super = super->Named.type_name->TypeName.objc_superclass;
- if (super == nullptr) {
- break;
- }
-
- // TODO(harold): Is this the right way to do this??? The referenced entity must be already resolved
- // so that we can access its objc_superclass attribute
- check_single_global_entity(ctx->checker, super->Named.type_name, super->Named.type_name->decl_info);
- }
- }
- } else {
- if (e->TypeName.objc_superclass != nullptr) {
- error(e->token, "@(objc_superclass) can only be applied when the @(obj_implement) attribute is also applied");
- } else if (e->TypeName.objc_ivar != nullptr) {
- error(e->token, "@(objc_ivar) can only be applied when the @(obj_implement) attribute is also applied");
- } else if (e->TypeName.objc_context_provider != nullptr) {
- error(e->token, "@(objc_context_provider) can only be applied when the @(obj_implement) attribute is also applied");
- }
- }
+ if (ac.objc_is_implementation) {
+ e->TypeName.objc_is_implementation = true;
+ mpsc_enqueue(&ctx->info->objc_class_implementations, e); // TODO(harold): Don't need this for anything? See if needed when using explicit @export
+
+ GB_ASSERT(e->TypeName.objc_ivar == nullptr || e->TypeName.objc_ivar->kind == Type_Named);
+
+ // Enqueue the proc to be checked when resolved
+ if (e->TypeName.objc_context_provider != nullptr) {
+ mpsc_enqueue(&ctx->checker->procs_with_objc_context_provider_to_check, e);
+ }
+
+ // @TODO(harold): I think there's a Check elsewhere in the checker for checking cycles.
+ // See about moving this to the right location.
+ // Ensure superclass hierarchy are all Objective-C classes and does not cycle
+ Type *super = ac.objc_superclass;
+ if (super != nullptr) {
+ TypeSet super_set{};
+ type_set_init(&super_set, 8);
+ defer (type_set_destroy(&super_set));
+
+ type_set_update(&super_set, e->type);
+
+ for (;;) {
+ if (type_set_update(&super_set, super)) {
+ error(e->token, "@(objc_superclass) Superclass hierarchy cycle encountered");
+ break;
+ }
+
+ if (super->kind != Type_Named) {
+ error(e->token, "@(objc_superclass) References type must be a named struct.");
+ break;
+ }
+
+ Type* named_type = base_type(super->Named.type_name->type);
+ if (!is_type_objc_object(named_type)) {
+ error(e->token, "@(objc_superclass) Superclass must be an Objective-C class.");
+ break;
+ }
+
+ super = super->Named.type_name->TypeName.objc_superclass;
+ if (super == nullptr) {
+ break;
+ }
+
+ // TODO(harold): Is this the right way to do this??? The referenced entity must be already resolved
+ // so that we can access its objc_superclass attribute
+ check_single_global_entity(ctx->checker, super->Named.type_name, super->Named.type_name->decl_info);
+ }
+ }
+ } else {
+ if (e->TypeName.objc_superclass != nullptr) {
+ error(e->token, "@(objc_superclass) can only be applied when the @(obj_implement) attribute is also applied");
+ } else if (e->TypeName.objc_ivar != nullptr) {
+ error(e->token, "@(objc_ivar) can only be applied when the @(obj_implement) attribute is also applied");
+ } else if (e->TypeName.objc_context_provider != nullptr) {
+ error(e->token, "@(objc_context_provider) can only be applied when the @(obj_implement) attribute is also applied");
+ }
+ }
if (type_size_of(e->type) > 0) {
error(e->token, "@(objc_class) marked type must be of zero size");
@@ -1005,37 +1005,37 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon
error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope");
} else {
- if (ac.objc_is_implementation) {
- GB_ASSERT(e->kind == Entity_Procedure);
+ if (ac.objc_is_implementation) {
+ GB_ASSERT(e->kind == Entity_Procedure);
- Type *proc_type = e->type;
+ Type *proc_type = e->type;
- if (!tn->TypeName.objc_is_implementation) {
- error(e->token, "@(objc_is_implement) attribute may only be applied to procedures whose class also have @(objc_is_implement) applied");
- } else if (proc_type->Proc.calling_convention == ProcCC_Odin && !tn->TypeName.objc_context_provider) {
- error(e->token, "Objective-C methods with Odin calling convention can only be used with classes that have @(objc_context_provider) set");
- } else if (ac.objc_is_class_method && proc_type->Proc.calling_convention != ProcCC_CDecl) {
- error(e->token, "Objective-C class methods (objc_is_class_method=true) that have @objc_is_implementation can only use \"c\" calling convention");
- } else {
+ if (!tn->TypeName.objc_is_implementation) {
+ error(e->token, "@(objc_is_implement) attribute may only be applied to procedures whose class also have @(objc_is_implement) applied");
+ } else if (proc_type->Proc.calling_convention == ProcCC_Odin && !tn->TypeName.objc_context_provider) {
+ error(e->token, "Objective-C methods with Odin calling convention can only be used with classes that have @(objc_context_provider) set");
+ } else if (ac.objc_is_class_method && proc_type->Proc.calling_convention != ProcCC_CDecl) {
+ error(e->token, "Objective-C class methods (objc_is_class_method=true) that have @objc_is_implementation can only use \"c\" calling convention");
+ } else {
auto method = ObjcMethodData{ ac, e };
- method.ac.objc_selector = ac.objc_selector != "" ? ac.objc_selector : ac.objc_name;
-
- CheckerInfo *info = ctx->info;
- mutex_lock(&info->objc_method_mutex);
- defer (mutex_unlock(&info->objc_method_mutex));
-
- Array<ObjcMethodData>* method_list = map_get(&info->objc_method_implementations, t);
- if (method_list) {
- array_add(method_list, method);
- } else {
- auto list = array_make<ObjcMethodData>(permanent_allocator(), 1, 8);
- list[0] = method;
-
- map_set(&info->objc_method_implementations, t, list);
- }
- }
- }
+ method.ac.objc_selector = ac.objc_selector != "" ? ac.objc_selector : ac.objc_name;
+
+ CheckerInfo *info = ctx->info;
+ mutex_lock(&info->objc_method_mutex);
+ defer (mutex_unlock(&info->objc_method_mutex));
+
+ Array<ObjcMethodData>* method_list = map_get(&info->objc_method_implementations, t);
+ if (method_list) {
+ array_add(method_list, method);
+ } else {
+ auto list = array_make<ObjcMethodData>(permanent_allocator(), 1, 8);
+ list[0] = method;
+
+ map_set(&info->objc_method_implementations, t, list);
+ }
+ }
+ }
mutex_lock(&global_type_name_objc_metadata_mutex);
defer (mutex_unlock(&global_type_name_objc_metadata_mutex));
diff --git a/src/checker.cpp b/src/checker.cpp
index 79c773a3c..6563b1c58 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -1351,12 +1351,12 @@ gb_internal void init_universal(void) {
t_objc_object = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_object"), alloc_type_struct_complete());
t_objc_selector = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_selector"), alloc_type_struct_complete());
t_objc_class = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_class"), alloc_type_struct_complete());
- t_objc_ivar = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_ivar"), alloc_type_struct_complete());
+ t_objc_ivar = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_ivar"), alloc_type_struct_complete());
t_objc_id = alloc_type_pointer(t_objc_object);
t_objc_SEL = alloc_type_pointer(t_objc_selector);
t_objc_Class = alloc_type_pointer(t_objc_class);
- t_objc_Ivar = alloc_type_pointer(t_objc_ivar);
+ t_objc_Ivar = alloc_type_pointer(t_objc_ivar);
}
}
@@ -1389,8 +1389,8 @@ gb_internal void init_checker_info(CheckerInfo *i) {
array_init(&i->defineables, a);
map_init(&i->objc_msgSend_types);
- mpsc_init(&i->objc_class_implementations, a);
- map_init(&i->objc_method_implementations);
+ mpsc_init(&i->objc_class_implementations, a);
+ map_init(&i->objc_method_implementations);
string_map_init(&i->load_file_cache);
array_init(&i->all_procedures, heap_allocator());
@@ -3352,10 +3352,10 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
ac->test = true;
return true;
} else if (name == "export") {
- if (ac->objc_is_implementation) {
- error(value, "Setting @(export) explicitly is not allowed when @(objc_implement) is set. It is exported implicitly.");
- return false;
- }
+ if (ac->objc_is_implementation) {
+ error(value, "Setting @(export) explicitly is not allowed when @(objc_implement) is set. It is exported implicitly.");
+ return false;
+ }
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_Invalid) {
@@ -3369,10 +3369,10 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
return true;
} else if (name == "linkage") {
- if (ac->objc_is_implementation) {
- error(value, "Explicit linkage not allowed when @(objc_implement) is set. It is set implicitly");
- return false;
- }
+ if (ac->objc_is_implementation) {
+ error(value, "Explicit linkage not allowed when @(objc_implement) is set. It is set implicitly");
+ return false;
+ }
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind != ExactValue_String) {
@@ -3681,23 +3681,23 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
}
return true;
} else if (name == "objc_implement") {
- ExactValue ev = check_decl_attribute_value(c, value);
- if (ev.kind == ExactValue_Bool) {
- ac->objc_is_implementation = ev.value_bool;
- } else if (ev.kind == ExactValue_Invalid) {
- ac->objc_is_implementation = true;
- } else {
- error(elem, "Expected a boolean value, or no value, for '%.*s'", LIT(name));
- }
-
- // This implies exported, strongly linked
- if (ac->objc_is_implementation) {
- ac->is_export = true;
- ac->linkage = str_lit("strong");
- }
-
- return true;
- } else if (name == "objc_selector") {
+ ExactValue ev = check_decl_attribute_value(c, value);
+ if (ev.kind == ExactValue_Bool) {
+ ac->objc_is_implementation = ev.value_bool;
+ } else if (ev.kind == ExactValue_Invalid) {
+ ac->objc_is_implementation = true;
+ } else {
+ error(elem, "Expected a boolean value, or no value, for '%.*s'", LIT(name));
+ }
+
+ // This implies exported, strongly linked
+ if (ac->objc_is_implementation) {
+ ac->is_export = true;
+ ac->linkage = str_lit("strong");
+ }
+
+ return true;
+ } else if (name == "objc_selector") {
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_String) {
if (string_is_valid_identifier(ev.value_string)) {
@@ -3949,52 +3949,52 @@ gb_internal DECL_ATTRIBUTE_PROC(type_decl_attribute) {
}
return true;
} else if (name == "objc_implement") {
- ExactValue ev = check_decl_attribute_value(c, value);
- if (ev.kind == ExactValue_Bool) {
- ac->objc_is_implementation = ev.value_bool;
- } else if (ev.kind == ExactValue_Invalid) {
- ac->objc_is_implementation = true;
- } else {
- error(elem, "Expected a boolean value, or no value, for '%.*s'", LIT(name));
- }
- return true;
- } else if (name == "objc_superclass") {
- Type *objc_superclass = check_type(c, value);
-
- if (objc_superclass != nullptr) {
- ac->objc_superclass = objc_superclass;
- } else {
- error(value, "'%.*s' expected a named type", LIT(name));
- }
- return true;
- } else if (name == "objc_ivar") {
- Type *objc_ivar = check_type(c, value);
-
- if (objc_ivar != nullptr) {
- ac->objc_ivar = objc_ivar;
- } else {
- error(value, "'%.*s' expected a named type", LIT(name));
- }
- return true;
- } else if (name == "objc_context_provider") {
- Operand o = {};
- check_expr(c, &o, value);
- Entity *e = entity_of_node(o.expr);
-
- if (e != nullptr) {
- if (ac->objc_context_provider != nullptr) {
- error(elem, "Previous usage of a 'objc_context_provider' attribute");
- }
- if (e->kind != Entity_Procedure) {
- error(elem, "'objc_context_provider' must refer to a procedure");
- } else {
- ac->objc_context_provider = e;
- }
-
- return true;
- }
- }
- return false;
+ ExactValue ev = check_decl_attribute_value(c, value);
+ if (ev.kind == ExactValue_Bool) {
+ ac->objc_is_implementation = ev.value_bool;
+ } else if (ev.kind == ExactValue_Invalid) {
+ ac->objc_is_implementation = true;
+ } else {
+ error(elem, "Expected a boolean value, or no value, for '%.*s'", LIT(name));
+ }
+ return true;
+ } else if (name == "objc_superclass") {
+ Type *objc_superclass = check_type(c, value);
+
+ if (objc_superclass != nullptr) {
+ ac->objc_superclass = objc_superclass;
+ } else {
+ error(value, "'%.*s' expected a named type", LIT(name));
+ }
+ return true;
+ } else if (name == "objc_ivar") {
+ Type *objc_ivar = check_type(c, value);
+
+ if (objc_ivar != nullptr) {
+ ac->objc_ivar = objc_ivar;
+ } else {
+ error(value, "'%.*s' expected a named type", LIT(name));
+ }
+ return true;
+ } else if (name == "objc_context_provider") {
+ Operand o = {};
+ check_expr(c, &o, value);
+ Entity *e = entity_of_node(o.expr);
+
+ if (e != nullptr) {
+ if (ac->objc_context_provider != nullptr) {
+ error(elem, "Previous usage of a 'objc_context_provider' attribute");
+ }
+ if (e->kind != Entity_Procedure) {
+ error(elem, "'objc_context_provider' must refer to a procedure");
+ } else {
+ ac->objc_context_provider = e;
+ }
+
+ return true;
+ }
+ }
+ return false;
}
diff --git a/src/checker.hpp b/src/checker.hpp
index 574c71c7f..336f09a7e 100644
--- a/src/checker.hpp
+++ b/src/checker.hpp
@@ -148,13 +148,13 @@ struct AttributeContext {
String objc_class;
String objc_name;
- String objc_selector;
+ String objc_selector;
Type * objc_type;
- Type * objc_superclass;
- Type * objc_ivar;
+ Type * objc_superclass;
+ Type * objc_ivar;
Entity *objc_context_provider;
bool objc_is_class_method : 1;
- bool objc_is_implementation : 1; // This struct or proc provides a class/method implementation, not a binding to an existing type.
+ bool objc_is_implementation : 1; // This struct or proc provides a class/method implementation, not a binding to an existing type.
String require_target_feature; // required by the target micro-architecture
String enable_target_feature; // will be enabled for the procedure only
@@ -371,8 +371,8 @@ struct ObjcMsgData {
};
struct ObjcMethodData {
- AttributeContext ac;
- Entity *proc_entity;
+ AttributeContext ac;
+ Entity *proc_entity;
};
enum LoadFileTier {
@@ -489,10 +489,10 @@ struct CheckerInfo {
BlockingMutex objc_types_mutex;
PtrMap<Ast *, ObjcMsgData> objc_msgSend_types;
- MPSCQueue<Entity *> objc_class_implementations;
+ MPSCQueue<Entity *> objc_class_implementations;
- BlockingMutex objc_method_mutex;
- PtrMap<Type *, Array<ObjcMethodData>> objc_method_implementations;
+ BlockingMutex objc_method_mutex;
+ PtrMap<Type *, Array<ObjcMethodData>> objc_method_implementations;
BlockingMutex load_file_mutex;
diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp
index cb2ce3915..ce7d8349b 100644
--- a/src/checker_builtin_procs.hpp
+++ b/src/checker_builtin_procs.hpp
@@ -331,7 +331,7 @@ BuiltinProc__type_end,
BuiltinProc_objc_find_class,
BuiltinProc_objc_register_selector,
BuiltinProc_objc_register_class,
- BuiltinProc_objc_ivar_get,
+ BuiltinProc_objc_ivar_get,
BuiltinProc_constant_utf16_cstring,
@@ -674,7 +674,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("objc_find_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("objc_register_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
{STR_LIT("objc_register_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
- {STR_LIT("ivar_get"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
+ {STR_LIT("ivar_get"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
{STR_LIT("constant_utf16_cstring"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
diff --git a/src/entity.cpp b/src/entity.cpp
index a5443cf27..cc41b5e59 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -235,9 +235,9 @@ struct Entity {
Type * type_parameter_specialization;
String ir_mangled_name;
bool is_type_alias;
- bool objc_is_implementation;
- Type* objc_superclass;
- Type* objc_ivar;
+ bool objc_is_implementation;
+ Type* objc_superclass;
+ Type* objc_ivar;
Entity*objc_context_provider;
String objc_class_name;
TypeNameObjCMetadata *objc_metadata;
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index fad542d4a..7ffd4ea30 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -1176,327 +1176,327 @@ gb_internal lbProcedure *lb_create_objc_names(lbModule *main_module) {
// TODO(harold): Move this out of here and into a more suitable place.
// TODO(harold): Should not take an allocator, but always use temp, as we return string literals as well.
String lb_get_objc_type_encoding(Type *t, gbAllocator allocator, isize pointer_depth = 0) {
- // NOTE(harold): See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100
-
- // NOTE(harold): Darwin targets are always 64-bit. Should we drop this and assume "q" always?
- #define INT_SIZE_ENCODING (build_context.metrics.ptr_size == 4 ? "i" : "q")
- switch (t->kind) {
- case Type_Basic: {
- switch (t->Basic.kind) {
- case Basic_Invalid:
- return str_lit("?");
-
- case Basic_llvm_bool:
- case Basic_bool:
- case Basic_b8:
- return str_lit("B");
-
- case Basic_b16:
- return str_lit("C");
- case Basic_b32:
- return str_lit("I");
- case Basic_b64:
- return str_lit("q");
- case Basic_i8:
- return str_lit("c");
- case Basic_u8:
- return str_lit("C");
- case Basic_i16:
- case Basic_i16le:
- case Basic_i16be:
- return str_lit("s");
- case Basic_u16:
- case Basic_u16le:
- case Basic_u16be:
- return str_lit("S");
- case Basic_i32:
- case Basic_i32le:
- case Basic_i32be:
- return str_lit("i");
- case Basic_u32le:
- case Basic_u32:
- case Basic_u32be:
- return str_lit("I");
- case Basic_i64:
- case Basic_i64le:
- case Basic_i64be:
- return str_lit("q");
- case Basic_u64:
- case Basic_u64le:
- case Basic_u64be:
- return str_lit("Q");
- case Basic_i128:
- case Basic_i128le:
- case Basic_i128be:
- return str_lit("t");
- case Basic_u128:
- case Basic_u128le:
- case Basic_u128be:
- return str_lit("T");
- case Basic_rune:
- return str_lit("I");
- case Basic_f16:
- case Basic_f16le:
- case Basic_f16be:
- return str_lit("s"); // @harold: Closest we've got?
- case Basic_f32:
- case Basic_f32le:
- case Basic_f32be:
- return str_lit("f");
- case Basic_f64:
- case Basic_f64le:
- case Basic_f64be:
- return str_lit("d");
-
- // TODO(harold) These:
- case Basic_complex32:
- case Basic_complex64:
- case Basic_complex128:
- case Basic_quaternion64:
- case Basic_quaternion128:
- case Basic_quaternion256:
- return str_lit("?");
-
- case Basic_int:
- return str_lit(INT_SIZE_ENCODING);
- case Basic_uint:
- return build_context.metrics.ptr_size == 4 ? str_lit("I") : str_lit("Q");
- case Basic_uintptr:
- case Basic_rawptr:
- return str_lit("^v");
-
- case Basic_string:
- return build_context.metrics.ptr_size == 4 ? str_lit("{string=*i}") : str_lit("{string=*q}");
-
- case Basic_cstring: return str_lit("*");
- case Basic_any: return str_lit("{any=^v^v"); // rawptr + ^Type_Info
-
- case Basic_typeid:
- GB_ASSERT(t->Basic.size == 8);
- return str_lit("q");
-
- // Untyped types
- case Basic_UntypedBool:
- case Basic_UntypedInteger:
- case Basic_UntypedFloat:
- case Basic_UntypedComplex:
- case Basic_UntypedQuaternion:
- case Basic_UntypedString:
- case Basic_UntypedRune:
- case Basic_UntypedNil:
- case Basic_UntypedUninit:
- GB_PANIC("Untyped types cannot be @encoded()");
- return str_lit("?");
- }
- break;
- }
-
- case Type_Named:
- case Type_Struct:
- case Type_Union: {
- Type* base = t;
- if (base->kind == Type_Named) {
- base = base_type(base);
- if(base->kind != Type_Struct && base->kind != Type_Union) {
- return lb_get_objc_type_encoding(base, allocator, pointer_depth);
- }
- }
-
- const bool is_union = base->kind == Type_Union;
- if (!is_union) {
- // Check for objc_SEL
- if (internal_check_is_assignable_to(base, t_objc_SEL)) {
- return str_lit(":");
- }
-
- // Check for objc_Class
- if (internal_check_is_assignable_to(base, t_objc_SEL)) {
- return str_lit("#");
- }
-
- // Treat struct as an Objective-C Class?
- if (has_type_got_objc_class_attribute(base) && pointer_depth == 0) {
- return str_lit("#");
- }
- }
-
- if (is_type_objc_object(base)) {
- return str_lit("@");
- }
-
-
- gbString s = gb_string_make_reserve(allocator, 16);
- s = gb_string_append_length(s, is_union ? "(" :"{", 1);
- if (t->kind == Type_Named) {
- s = gb_string_append_length(s, t->Named.name.text, t->Named.name.len);
- }
-
- // Write fields
- if (pointer_depth < 2) {
- s = gb_string_append_length(s, "=", 1);
-
- if (!is_union) {
- for( auto& f : base->Struct.fields ) {
- String field_type = lb_get_objc_type_encoding(f->type, allocator, pointer_depth);
- s = gb_string_append_length(s, field_type.text, field_type.len);
- }
- } else {
- // #TODO(harold): Encode fields
- }
- }
-
- s = gb_string_append_length(s, is_union ? ")" :"}", 1);
-
- return make_string_c(s);
- }
-
- case Type_Generic:
- GB_PANIC("Generic types cannot be @encoded()");
- return str_lit("?");
-
- case Type_Pointer: {
- String pointee = lb_get_objc_type_encoding(t->Pointer.elem, allocator, pointer_depth +1);
- // Special case for Objective-C Objects
- if (pointer_depth == 0 && pointee == "@") {
- return pointee;
- }
-
- return concatenate_strings(allocator, str_lit("^"), pointee);
- }
-
- case Type_MultiPointer:
- return concatenate_strings(allocator, str_lit("^"), lb_get_objc_type_encoding(t->Pointer.elem, allocator, pointer_depth +1));
-
- case Type_Array: {
- String type_str = lb_get_objc_type_encoding(t->Array.elem, allocator, pointer_depth);
-
- gbString s = gb_string_make_reserve(allocator, type_str.len + 8);
- s = gb_string_append_fmt(s, "[%lld%s]", t->Array.count, type_str.text);
- return make_string_c(s);
- }
-
- case Type_EnumeratedArray: {
- String type_str = lb_get_objc_type_encoding(t->EnumeratedArray.elem, allocator, pointer_depth);
-
- gbString s = gb_string_make_reserve(allocator, type_str.len + 8);
- s = gb_string_append_fmt(s, "[%lld%s]", t->EnumeratedArray.count, type_str.text);
- return make_string_c(s);
- }
-
- case Type_Slice: {
- String type_str = lb_get_objc_type_encoding(t->Slice.elem, allocator, pointer_depth);
- gbString s = gb_string_make_reserve(allocator, type_str.len + 8);
- s = gb_string_append_fmt(s, "{slice=^%s%s}", type_str, INT_SIZE_ENCODING);
- return make_string_c(s);
- }
-
- case Type_DynamicArray: {
- String type_str = lb_get_objc_type_encoding(t->DynamicArray.elem, allocator, pointer_depth);
- gbString s = gb_string_make_reserve(allocator, type_str.len + 8);
- s = gb_string_append_fmt(s, "{dynamic=^%s%s%sAllocator={?^v}}", type_str, INT_SIZE_ENCODING, INT_SIZE_ENCODING);
- return make_string_c(s);
- }
-
- case Type_Map:
- return str_lit("{^v^v{Allocator=?^v}}");
- case Type_Enum:
- return lb_get_objc_type_encoding(t->Enum.base_type, allocator, pointer_depth);
- case Type_Tuple:
- // NOTE(harold): Is this allowed here?
- return str_lit("?");
- case Type_Proc:
- return str_lit("?");
- case Type_BitSet:
- return lb_get_objc_type_encoding(t->BitSet.underlying, allocator, pointer_depth);
- case Type_SimdVector:
- break;
- case Type_Matrix:
- break;
- case Type_BitField:
- return lb_get_objc_type_encoding(t->BitField.backing_type, allocator, pointer_depth);
- case Type_SoaPointer: {
- gbString s = gb_string_make_reserve(allocator, 8);
- s = gb_string_append_fmt(s, "{=^v%s}", INT_SIZE_ENCODING);
- return make_string_c(s);
- }
-
- } // End switch t->kind
- #undef INT_SIZE_ENCODING
-
- GB_PANIC("Unreachable");
+ // NOTE(harold): See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100
+
+ // NOTE(harold): Darwin targets are always 64-bit. Should we drop this and assume "q" always?
+ #define INT_SIZE_ENCODING (build_context.metrics.ptr_size == 4 ? "i" : "q")
+ switch (t->kind) {
+ case Type_Basic: {
+ switch (t->Basic.kind) {
+ case Basic_Invalid:
+ return str_lit("?");
+
+ case Basic_llvm_bool:
+ case Basic_bool:
+ case Basic_b8:
+ return str_lit("B");
+
+ case Basic_b16:
+ return str_lit("C");
+ case Basic_b32:
+ return str_lit("I");
+ case Basic_b64:
+ return str_lit("q");
+ case Basic_i8:
+ return str_lit("c");
+ case Basic_u8:
+ return str_lit("C");
+ case Basic_i16:
+ case Basic_i16le:
+ case Basic_i16be:
+ return str_lit("s");
+ case Basic_u16:
+ case Basic_u16le:
+ case Basic_u16be:
+ return str_lit("S");
+ case Basic_i32:
+ case Basic_i32le:
+ case Basic_i32be:
+ return str_lit("i");
+ case Basic_u32le:
+ case Basic_u32:
+ case Basic_u32be:
+ return str_lit("I");
+ case Basic_i64:
+ case Basic_i64le:
+ case Basic_i64be:
+ return str_lit("q");
+ case Basic_u64:
+ case Basic_u64le:
+ case Basic_u64be:
+ return str_lit("Q");
+ case Basic_i128:
+ case Basic_i128le:
+ case Basic_i128be:
+ return str_lit("t");
+ case Basic_u128:
+ case Basic_u128le:
+ case Basic_u128be:
+ return str_lit("T");
+ case Basic_rune:
+ return str_lit("I");
+ case Basic_f16:
+ case Basic_f16le:
+ case Basic_f16be:
+ return str_lit("s"); // @harold: Closest we've got?
+ case Basic_f32:
+ case Basic_f32le:
+ case Basic_f32be:
+ return str_lit("f");
+ case Basic_f64:
+ case Basic_f64le:
+ case Basic_f64be:
+ return str_lit("d");
+
+ // TODO(harold) These:
+ case Basic_complex32:
+ case Basic_complex64:
+ case Basic_complex128:
+ case Basic_quaternion64:
+ case Basic_quaternion128:
+ case Basic_quaternion256:
+ return str_lit("?");
+
+ case Basic_int:
+ return str_lit(INT_SIZE_ENCODING);
+ case Basic_uint:
+ return build_context.metrics.ptr_size == 4 ? str_lit("I") : str_lit("Q");
+ case Basic_uintptr:
+ case Basic_rawptr:
+ return str_lit("^v");
+
+ case Basic_string:
+ return build_context.metrics.ptr_size == 4 ? str_lit("{string=*i}") : str_lit("{string=*q}");
+
+ case Basic_cstring: return str_lit("*");
+ case Basic_any: return str_lit("{any=^v^v"); // rawptr + ^Type_Info
+
+ case Basic_typeid:
+ GB_ASSERT(t->Basic.size == 8);
+ return str_lit("q");
+
+ // Untyped types
+ case Basic_UntypedBool:
+ case Basic_UntypedInteger:
+ case Basic_UntypedFloat:
+ case Basic_UntypedComplex:
+ case Basic_UntypedQuaternion:
+ case Basic_UntypedString:
+ case Basic_UntypedRune:
+ case Basic_UntypedNil:
+ case Basic_UntypedUninit:
+ GB_PANIC("Untyped types cannot be @encoded()");
+ return str_lit("?");
+ }
+ break;
+ }
+
+ case Type_Named:
+ case Type_Struct:
+ case Type_Union: {
+ Type* base = t;
+ if (base->kind == Type_Named) {
+ base = base_type(base);
+ if(base->kind != Type_Struct && base->kind != Type_Union) {
+ return lb_get_objc_type_encoding(base, allocator, pointer_depth);
+ }
+ }
+
+ const bool is_union = base->kind == Type_Union;
+ if (!is_union) {
+ // Check for objc_SEL
+ if (internal_check_is_assignable_to(base, t_objc_SEL)) {
+ return str_lit(":");
+ }
+
+ // Check for objc_Class
+ if (internal_check_is_assignable_to(base, t_objc_SEL)) {
+ return str_lit("#");
+ }
+
+ // Treat struct as an Objective-C Class?
+ if (has_type_got_objc_class_attribute(base) && pointer_depth == 0) {
+ return str_lit("#");
+ }
+ }
+
+ if (is_type_objc_object(base)) {
+ return str_lit("@");
+ }
+
+
+ gbString s = gb_string_make_reserve(allocator, 16);
+ s = gb_string_append_length(s, is_union ? "(" :"{", 1);
+ if (t->kind == Type_Named) {
+ s = gb_string_append_length(s, t->Named.name.text, t->Named.name.len);
+ }
+
+ // Write fields
+ if (pointer_depth < 2) {
+ s = gb_string_append_length(s, "=", 1);
+
+ if (!is_union) {
+ for( auto& f : base->Struct.fields ) {
+ String field_type = lb_get_objc_type_encoding(f->type, allocator, pointer_depth);
+ s = gb_string_append_length(s, field_type.text, field_type.len);
+ }
+ } else {
+ // #TODO(harold): Encode fields
+ }
+ }
+
+ s = gb_string_append_length(s, is_union ? ")" :"}", 1);
+
+ return make_string_c(s);
+ }
+
+ case Type_Generic:
+ GB_PANIC("Generic types cannot be @encoded()");
+ return str_lit("?");
+
+ case Type_Pointer: {
+ String pointee = lb_get_objc_type_encoding(t->Pointer.elem, allocator, pointer_depth +1);
+ // Special case for Objective-C Objects
+ if (pointer_depth == 0 && pointee == "@") {
+ return pointee;
+ }
+
+ return concatenate_strings(allocator, str_lit("^"), pointee);
+ }
+
+ case Type_MultiPointer:
+ return concatenate_strings(allocator, str_lit("^"), lb_get_objc_type_encoding(t->Pointer.elem, allocator, pointer_depth +1));
+
+ case Type_Array: {
+ String type_str = lb_get_objc_type_encoding(t->Array.elem, allocator, pointer_depth);
+
+ gbString s = gb_string_make_reserve(allocator, type_str.len + 8);
+ s = gb_string_append_fmt(s, "[%lld%s]", t->Array.count, type_str.text);
+ return make_string_c(s);
+ }
+
+ case Type_EnumeratedArray: {
+ String type_str = lb_get_objc_type_encoding(t->EnumeratedArray.elem, allocator, pointer_depth);
+
+ gbString s = gb_string_make_reserve(allocator, type_str.len + 8);
+ s = gb_string_append_fmt(s, "[%lld%s]", t->EnumeratedArray.count, type_str.text);
+ return make_string_c(s);
+ }
+
+ case Type_Slice: {
+ String type_str = lb_get_objc_type_encoding(t->Slice.elem, allocator, pointer_depth);
+ gbString s = gb_string_make_reserve(allocator, type_str.len + 8);
+ s = gb_string_append_fmt(s, "{slice=^%s%s}", type_str, INT_SIZE_ENCODING);
+ return make_string_c(s);
+ }
+
+ case Type_DynamicArray: {
+ String type_str = lb_get_objc_type_encoding(t->DynamicArray.elem, allocator, pointer_depth);
+ gbString s = gb_string_make_reserve(allocator, type_str.len + 8);
+ s = gb_string_append_fmt(s, "{dynamic=^%s%s%sAllocator={?^v}}", type_str, INT_SIZE_ENCODING, INT_SIZE_ENCODING);
+ return make_string_c(s);
+ }
+
+ case Type_Map:
+ return str_lit("{^v^v{Allocator=?^v}}");
+ case Type_Enum:
+ return lb_get_objc_type_encoding(t->Enum.base_type, allocator, pointer_depth);
+ case Type_Tuple:
+ // NOTE(harold): Is this allowed here?
+ return str_lit("?");
+ case Type_Proc:
+ return str_lit("?");
+ case Type_BitSet:
+ return lb_get_objc_type_encoding(t->BitSet.underlying, allocator, pointer_depth);
+ case Type_SimdVector:
+ break;
+ case Type_Matrix:
+ break;
+ case Type_BitField:
+ return lb_get_objc_type_encoding(t->BitField.backing_type, allocator, pointer_depth);
+ case Type_SoaPointer: {
+ gbString s = gb_string_make_reserve(allocator, 8);
+ s = gb_string_append_fmt(s, "{=^v%s}", INT_SIZE_ENCODING);
+ return make_string_c(s);
+ }
+
+ } // End switch t->kind
+ #undef INT_SIZE_ENCODING
+
+ GB_PANIC("Unreachable");
}
struct lbObjCGlobalClass {
- lbObjCGlobal g;
- lbValue class_value; // Local registered class value
+ lbObjCGlobal g;
+ lbValue class_value; // Local registered class value
};
gb_internal void lb_register_objc_thing(
- StringSet &handled,
- lbModule *m,
- Array<lbValue> &args,
- Array<lbObjCGlobalClass> &class_impls,
- StringMap<lbObjCGlobalClass> &class_map,
- lbProcedure *p,
- lbObjCGlobal const &g,
- char const *call
+ StringSet &handled,
+ lbModule *m,
+ Array<lbValue> &args,
+ Array<lbObjCGlobalClass> &class_impls,
+ StringMap<lbObjCGlobalClass> &class_map,
+ lbProcedure *p,
+ lbObjCGlobal const &g,
+ char const *call
) {
- if (string_set_update(&handled, g.name)) {
- return;
- }
-
- lbAddr addr = {};
- lbValue *found = string_map_get(&m->members, g.global_name);
- if (found) {
- addr = lb_addr(*found);
- } else {
- lbValue v = {};
- LLVMTypeRef t = lb_type(m, g.type);
- v.value = LLVMAddGlobal(m->mod, t, g.global_name);
- v.type = alloc_type_pointer(g.type);
- addr = lb_addr(v);
- LLVMSetInitializer(v.value, LLVMConstNull(t));
- }
-
- lbValue class_ptr{};
- lbValue class_name = lb_const_value(m, t_cstring, exact_value_string(g.name));
-
- // If this class requires an implementation, save it for registration below.
- if (g.class_impl_type != nullptr) {
-
- // Make sure the superclass has been initialized before us
- lbValue superclass_value{};
-
- auto& tn = g.class_impl_type->Named.type_name->TypeName;
- Type *superclass = tn.objc_superclass;
- if (superclass != nullptr) {
- auto& superclass_global = string_map_must_get(&class_map, superclass->Named.type_name->TypeName.objc_class_name);
- lb_register_objc_thing(handled, m, args, class_impls, class_map, p, superclass_global.g, call);
- GB_ASSERT(superclass_global.class_value.value);
-
- superclass_value = superclass_global.class_value;
- }
-
- args.count = 3;
- args[0] = superclass == nullptr ? lb_const_nil(m, t_objc_Class) : superclass_value;
- args[1] = class_name;
- args[2] = lb_const_int(m, t_uint, 0);
- class_ptr = lb_emit_runtime_call(p, "objc_allocateClassPair", args);
-
- array_add(&class_impls, lbObjCGlobalClass{g, class_ptr});
- }
- else {
- args.count = 1;
- args[0] = class_name;
- class_ptr = lb_emit_runtime_call(p, call, args);
- }
-
- lb_addr_store(p, addr, class_ptr);
-
- lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name);
- if (class_global != nullptr) {
- class_global->class_value = class_ptr;
- }
+ if (string_set_update(&handled, g.name)) {
+ return;
+ }
+
+ lbAddr addr = {};
+ lbValue *found = string_map_get(&m->members, g.global_name);
+ if (found) {
+ addr = lb_addr(*found);
+ } else {
+ lbValue v = {};
+ LLVMTypeRef t = lb_type(m, g.type);
+ v.value = LLVMAddGlobal(m->mod, t, g.global_name);
+ v.type = alloc_type_pointer(g.type);
+ addr = lb_addr(v);
+ LLVMSetInitializer(v.value, LLVMConstNull(t));
+ }
+
+ lbValue class_ptr{};
+ lbValue class_name = lb_const_value(m, t_cstring, exact_value_string(g.name));
+
+ // If this class requires an implementation, save it for registration below.
+ if (g.class_impl_type != nullptr) {
+
+ // Make sure the superclass has been initialized before us
+ lbValue superclass_value{};
+
+ auto& tn = g.class_impl_type->Named.type_name->TypeName;
+ Type *superclass = tn.objc_superclass;
+ if (superclass != nullptr) {
+ auto& superclass_global = string_map_must_get(&class_map, superclass->Named.type_name->TypeName.objc_class_name);
+ lb_register_objc_thing(handled, m, args, class_impls, class_map, p, superclass_global.g, call);
+ GB_ASSERT(superclass_global.class_value.value);
+
+ superclass_value = superclass_global.class_value;
+ }
+
+ args.count = 3;
+ args[0] = superclass == nullptr ? lb_const_nil(m, t_objc_Class) : superclass_value;
+ args[1] = class_name;
+ args[2] = lb_const_int(m, t_uint, 0);
+ class_ptr = lb_emit_runtime_call(p, "objc_allocateClassPair", args);
+
+ array_add(&class_impls, lbObjCGlobalClass{g, class_ptr});
+ }
+ else {
+ args.count = 1;
+ args[0] = class_name;
+ class_ptr = lb_emit_runtime_call(p, call, args);
+ }
+
+ lb_addr_store(p, addr, class_ptr);
+
+ lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name);
+ if (class_global != nullptr) {
+ class_global->class_value = class_ptr;
+ }
}
gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
@@ -1513,80 +1513,80 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
defer (string_set_destroy(&handled));
auto args = array_make<lbValue>(temporary_allocator(), 3, 8);
- auto class_impls = array_make<lbObjCGlobalClass>(temporary_allocator(), 0, 16);
-
- // Ensure classes that have been implicitly referenced through
- // the objc_superclass attribute have a global variable available for them.
- TypeSet class_set{};
- type_set_init(&class_set, gen->objc_classes.count+16);
- defer (type_set_destroy(&class_set));
-
- auto referenced_classes = array_make<lbObjCGlobal>(temporary_allocator());
- for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_classes, &g); /**/) {
- array_add( &referenced_classes, g);
-
- Type *cls = g.class_impl_type;
- while (cls) {
- if (type_set_update(&class_set, cls)) {
- break;
- }
- GB_ASSERT(cls->kind == Type_Named);
-
- cls = cls->Named.type_name->TypeName.objc_superclass;
- }
- }
-
- for (auto pair : class_set) {
- auto& tn = pair.type->Named.type_name->TypeName;
- Type *class_impl = !tn.objc_is_implementation ? nullptr : pair.type;
- lb_handle_objc_find_or_register_class(p, tn.objc_class_name, class_impl);
- }
- for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_classes, &g); /**/) {
- array_add( &referenced_classes, g );
- }
-
- // Add all class globals to a map so that we can look them up dynamically
- // in order to resolve out-of-order because classes that are being implemented
- // need their superclasses to have been registered before them.
- StringMap<lbObjCGlobalClass> global_class_map{};
- string_map_init(&global_class_map, (usize)gen->objc_classes.count);
- defer (string_map_destroy(&global_class_map));
-
- for (lbObjCGlobal g :referenced_classes) {
- string_map_set(&global_class_map, g.name, lbObjCGlobalClass{g});
- }
-
- LLVMSetLinkage(p->value, LLVMInternalLinkage);
- lb_begin_procedure_body(p);
-
- // Register class globals, gathering classes that must be implemented
- for (auto& kv : global_class_map) {
- lb_register_objc_thing(handled, m, args, class_impls, global_class_map, p, kv.value.g, "objc_lookUpClass");
- }
-
- // Prefetch selectors for implemented methods so that they can also be registered.
- for (const auto& cd : class_impls) {
- auto& g = cd.g;
- Type *class_type = g.class_impl_type;
-
- Array<ObjcMethodData>* methods = map_get(&m->info->objc_method_implementations, class_type);
- if (!methods) {
- continue;
- }
-
- for (const ObjcMethodData& md : *methods) {
- lb_handle_objc_find_or_register_selector(p, md.ac.objc_selector);
- }
- }
-
- // Now we can register all referenced selectors
- for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_selectors, &g); /**/) {
- lb_register_objc_thing(handled, m, args, class_impls, global_class_map, p, g, "sel_registerName");
- }
-
-
- // Emit method wrapper implementations and registration
- auto wrapper_args = array_make<Type *>(temporary_allocator(), 2, 8);
+ auto class_impls = array_make<lbObjCGlobalClass>(temporary_allocator(), 0, 16);
+
+ // Ensure classes that have been implicitly referenced through
+ // the objc_superclass attribute have a global variable available for them.
+ TypeSet class_set{};
+ type_set_init(&class_set, gen->objc_classes.count+16);
+ defer (type_set_destroy(&class_set));
+
+ auto referenced_classes = array_make<lbObjCGlobal>(temporary_allocator());
+ for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_classes, &g); /**/) {
+ array_add( &referenced_classes, g);
+
+ Type *cls = g.class_impl_type;
+ while (cls) {
+ if (type_set_update(&class_set, cls)) {
+ break;
+ }
+ GB_ASSERT(cls->kind == Type_Named);
+
+ cls = cls->Named.type_name->TypeName.objc_superclass;
+ }
+ }
+
+ for (auto pair : class_set) {
+ auto& tn = pair.type->Named.type_name->TypeName;
+ Type *class_impl = !tn.objc_is_implementation ? nullptr : pair.type;
+ lb_handle_objc_find_or_register_class(p, tn.objc_class_name, class_impl);
+ }
+ for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_classes, &g); /**/) {
+ array_add( &referenced_classes, g );
+ }
+
+ // Add all class globals to a map so that we can look them up dynamically
+ // in order to resolve out-of-order because classes that are being implemented
+ // need their superclasses to have been registered before them.
+ StringMap<lbObjCGlobalClass> global_class_map{};
+ string_map_init(&global_class_map, (usize)gen->objc_classes.count);
+ defer (string_map_destroy(&global_class_map));
+
+ for (lbObjCGlobal g :referenced_classes) {
+ string_map_set(&global_class_map, g.name, lbObjCGlobalClass{g});
+ }
+
+ LLVMSetLinkage(p->value, LLVMInternalLinkage);
+ lb_begin_procedure_body(p);
+
+ // Register class globals, gathering classes that must be implemented
+ for (auto& kv : global_class_map) {
+ lb_register_objc_thing(handled, m, args, class_impls, global_class_map, p, kv.value.g, "objc_lookUpClass");
+ }
+
+ // Prefetch selectors for implemented methods so that they can also be registered.
+ for (const auto& cd : class_impls) {
+ auto& g = cd.g;
+ Type *class_type = g.class_impl_type;
+
+ Array<ObjcMethodData>* methods = map_get(&m->info->objc_method_implementations, class_type);
+ if (!methods) {
+ continue;
+ }
+
+ for (const ObjcMethodData& md : *methods) {
+ lb_handle_objc_find_or_register_selector(p, md.ac.objc_selector);
+ }
+ }
+
+ // Now we can register all referenced selectors
+ for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_selectors, &g); /**/) {
+ lb_register_objc_thing(handled, m, args, class_impls, global_class_map, p, g, "sel_registerName");
+ }
+
+
+ // Emit method wrapper implementations and registration
+ auto wrapper_args = array_make<Type *>(temporary_allocator(), 2, 8);
auto get_context_args = array_make<lbValue>(temporary_allocator(), 1);
@@ -1597,186 +1597,200 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
map_set(&ivar_map, g.class_impl_type, g);
}
- for (const auto& cd : class_impls) {
- auto& g = cd.g;
- Type *class_type = g.class_impl_type;
- Type *class_ptr_type = alloc_type_pointer(class_type);
- lbValue class_value = cd.class_value;
+ for (const auto& cd : class_impls) {
+ auto& g = cd.g;
+ Type *class_type = g.class_impl_type;
+ Type *class_ptr_type = alloc_type_pointer(class_type);
+ lbValue class_value = cd.class_value;
- Type *ivar_type = class_type->Named.type_name->TypeName.objc_ivar;
+ Type *ivar_type = class_type->Named.type_name->TypeName.objc_ivar;
- Entity *context_provider = class_type->Named.type_name->TypeName.objc_context_provider;
- Type *contex_provider_self_ptr_type = nullptr;
- Type *contex_provider_self_named_type = nullptr;
- bool is_context_provider_ivar = false;
- lbValue context_provider_proc_value{};
+ Entity *context_provider = class_type->Named.type_name->TypeName.objc_context_provider;
+ Type *contex_provider_self_ptr_type = nullptr;
+ Type *contex_provider_self_named_type = nullptr;
+ bool is_context_provider_ivar = false;
+ lbValue context_provider_proc_value{};
- if (context_provider) {
- context_provider_proc_value = lb_find_procedure_value_from_entity(m, context_provider);
+ if (context_provider) {
+ context_provider_proc_value = lb_find_procedure_value_from_entity(m, context_provider);
- contex_provider_self_ptr_type = base_type(context_provider->type->Proc.params->Tuple.variables[0]->type);
- GB_ASSERT(contex_provider_self_ptr_type->kind == Type_Pointer);
- contex_provider_self_named_type = base_named_type(type_deref(contex_provider_self_ptr_type));
+ contex_provider_self_ptr_type = base_type(context_provider->type->Proc.params->Tuple.variables[0]->type);
+ GB_ASSERT(contex_provider_self_ptr_type->kind == Type_Pointer);
+ contex_provider_self_named_type = base_named_type(type_deref(contex_provider_self_ptr_type));
- is_context_provider_ivar = ivar_type != nullptr && internal_check_is_assignable_to(contex_provider_self_named_type, ivar_type);
- }
+ is_context_provider_ivar = ivar_type != nullptr && internal_check_is_assignable_to(contex_provider_self_named_type, ivar_type);
+ }
- Array<ObjcMethodData>* methods = map_get(&m->info->objc_method_implementations, class_type);
- if (!methods) {
- continue;
- }
+ Array<ObjcMethodData>* methods = map_get(&m->info->objc_method_implementations, class_type);
+ if (!methods) {
+ continue;
+ }
- for (const ObjcMethodData& md : *methods) {
- GB_ASSERT( md.proc_entity->kind == Entity_Procedure);
- Type *method_type = md.proc_entity->type;
+ for (const ObjcMethodData& md : *methods) {
+ GB_ASSERT( md.proc_entity->kind == Entity_Procedure);
+ Type *method_type = md.proc_entity->type;
- String proc_name = make_string_c("__$objc_method::");
- proc_name = concatenate_strings(temporary_allocator(), proc_name, g.name);
- proc_name = concatenate_strings(temporary_allocator(), proc_name, str_lit("::"));
- proc_name = concatenate_strings( permanent_allocator(), proc_name, md.ac.objc_name);
+ String proc_name = make_string_c("__$objc_method::");
+ proc_name = concatenate_strings(temporary_allocator(), proc_name, g.name);
+ proc_name = concatenate_strings(temporary_allocator(), proc_name, str_lit("::"));
+ proc_name = concatenate_strings( permanent_allocator(), proc_name, md.ac.objc_name);
- wrapper_args.count = 2;
- wrapper_args[0] = md.ac.objc_is_class_method ? t_objc_Class : class_ptr_type;
- wrapper_args[1] = t_objc_SEL;
+ wrapper_args.count = 2;
+ wrapper_args[0] = md.ac.objc_is_class_method ? t_objc_Class : class_ptr_type;
+ wrapper_args[1] = t_objc_SEL;
- auto method_param_count = (isize)method_type->Proc.param_count;
- i32 method_param_offset = 0;
+ auto method_param_count = (isize)method_type->Proc.param_count;
+ i32 method_param_offset = 0;
- // TODO(harold): Need to make sure (at checker stage) that the non-class method has the self parameter already.
- // (Maybe this is already accounted for?.)
- if (!md.ac.objc_is_class_method) {
- GB_ASSERT(method_param_count >= 1);
- method_param_count -= 1;
- method_param_offset = 1;
- }
+ // TODO(harold): Need to make sure (at checker stage) that the non-class method has the self parameter already.
+ // (Maybe this is already accounted for?.)
+ if (!md.ac.objc_is_class_method) {
+ GB_ASSERT(method_param_count >= 1);
+ method_param_count -= 1;
+ method_param_offset = 1;
+ }
- for (i32 i = 0; i < method_param_count; i++) {
- array_add(&wrapper_args, method_type->Proc.params->Tuple.variables[method_param_offset+i]->type);
- }
+ for (i32 i = 0; i < method_param_count; i++) {
+ array_add(&wrapper_args, method_type->Proc.params->Tuple.variables[method_param_offset+i]->type);
+ }
- Type *wrapper_args_tuple = alloc_type_tuple_from_field_types(wrapper_args.data, wrapper_args.count, false, true);
- Type *wrapper_proc_type = alloc_type_proc(nullptr, wrapper_args_tuple, (isize)wrapper_args_tuple->Tuple.variables.count, nullptr, 0, false, ProcCC_CDecl);
+ Type *wrapper_args_tuple = alloc_type_tuple_from_field_types(wrapper_args.data, wrapper_args.count, false, true);
+ Type *wrapper_results_tuple = nullptr;
- lbProcedure *wrapper_proc = lb_create_dummy_procedure(m, proc_name, wrapper_proc_type);
- lb_add_attribute_to_proc(wrapper_proc->module, wrapper_proc->value, "nounwind");
+ if (method_type->Proc.result_count > 0) {
+ GB_ASSERT(method_type->Proc.result_count == 1);
+ wrapper_results_tuple = alloc_type_tuple_from_field_types(&method_type->Proc.results->Tuple.variables[0]->type, 1, false, true);
+ }
+
+ Type *wrapper_proc_type = alloc_type_proc(nullptr, wrapper_args_tuple, wrapper_args_tuple->Tuple.variables.count,
+ wrapper_results_tuple, method_type->Proc.result_count, false, ProcCC_CDecl);
- // Emit the wrapper
- LLVMSetLinkage(wrapper_proc->value, LLVMExternalLinkage);
- lb_begin_procedure_body(wrapper_proc);
- {
- if (method_type->Proc.calling_convention == ProcCC_Odin) {
- GB_ASSERT(context_provider);
+ lbProcedure *wrapper_proc = lb_create_dummy_procedure(m, proc_name, wrapper_proc_type);
+ lb_add_attribute_to_proc(wrapper_proc->module, wrapper_proc->value, "nounwind");
- // Emit the get odin context call
+ // Emit the wrapper
+ LLVMSetLinkage(wrapper_proc->value, LLVMExternalLinkage);
+ lb_begin_procedure_body(wrapper_proc);
+ {
+ if (method_type->Proc.calling_convention == ProcCC_Odin) {
+ GB_ASSERT(context_provider);
- get_context_args[0] = lbValue {
- wrapper_proc->raw_input_parameters[0],
+ // Emit the get odin context call
+
+ get_context_args[0] = lbValue {
+ wrapper_proc->raw_input_parameters[0],
contex_provider_self_ptr_type,
};
- if (is_context_provider_ivar) {
- // The context provider takes the ivar's type.
- // Emit an obj_ivar_get call and use that pointer for 'self' instead.
- lbValue real_self {
- wrapper_proc->raw_input_parameters[0],
- class_ptr_type
- };
- get_context_args[0] = lb_handle_objc_ivar_for_objc_object_pointer(wrapper_proc, real_self);
- }
-
- lbValue context = lb_emit_call(wrapper_proc, context_provider_proc_value, get_context_args);
- lbAddr context_addr = lb_addr(lb_address_from_load_or_generate_local(wrapper_proc, context));
- lb_push_context_onto_stack(wrapper_proc, context_addr);
- }
-
-
- auto method_call_args = array_make<lbValue>(temporary_allocator(), method_param_count + (isize)method_param_offset);
-
- if (!md.ac.objc_is_class_method) {
- method_call_args[0] = lbValue {
- wrapper_proc->raw_input_parameters[0],
- class_ptr_type,
- };
- }
-
- for (isize i = 0; i < method_param_count; i++) {
- method_call_args[i+method_param_offset] = lbValue {
- wrapper_proc->raw_input_parameters[i+2],
- method_type->Proc.params->Tuple.variables[i+method_param_offset]->type,
- };
- }
- lbValue method_proc_value = lb_find_procedure_value_from_entity(m, md.proc_entity);
-
- // Call real procedure for method from here, passing the parameters expected, if any.
- lb_emit_call(wrapper_proc, method_proc_value, method_call_args);
- }
- lb_end_procedure_body(wrapper_proc);
-
-
- // Add the method to the class
- String method_encoding = str_lit("v");
- // TODO (harold): Checker must ensure that objc_methods have a single return value or none!
- GB_ASSERT(method_type->Proc.result_count <= 1);
- if (method_type->Proc.result_count != 0) {
- method_encoding = lb_get_objc_type_encoding(method_type->Proc.results->Tuple.variables[0]->type, temporary_allocator());
- }
-
- if (!md.ac.objc_is_class_method) {
- method_encoding = concatenate_strings(temporary_allocator(), method_encoding, str_lit("@:"));
- } else {
- method_encoding = concatenate_strings(temporary_allocator(), method_encoding, str_lit("#:"));
- }
-
- for (i32 i = method_param_offset; i < method_param_count; i++) {
- Type *param_type = method_type->Proc.params->Tuple.variables[i]->type;
- String param_encoding = lb_get_objc_type_encoding(param_type, temporary_allocator());
-
- method_encoding = concatenate_strings(temporary_allocator(), method_encoding, param_encoding);
- }
-
- // Emit method registration
- lbAddr* sel_address = string_map_get(&m->objc_selectors, md.ac.objc_selector);
- GB_ASSERT(sel_address);
- lbValue selector_value = lb_addr_load(p, *sel_address);
-
- args.count = 4;
- args[0] = class_value; // Class
- args[1] = selector_value; // SEL
- args[2] = lbValue { wrapper_proc->value, wrapper_proc->type };
- args[3] = lb_const_value(m, t_cstring, exact_value_string(method_encoding));
-
- // TODO(harold): Emit check BOOL result and panic if false.
- lb_emit_runtime_call(p, "class_addMethod", args);
-
- } // End methods
-
- // Add ivar if we have one
- if (ivar_type != nullptr) {
- // Register a single ivar for this class
- Type *ivar_base = ivar_type->Named.base;
-
- const i64 size = type_size_of(ivar_base);
- const i64 alignment = type_align_of(ivar_base);
- // TODO(harold): Checker: Alignment must be compatible with ivar rules. Or we should increase the alignment if needed.
-
- // TODO(harold): Should we pass the actual type encoding? Might not be ideal for obfuscation.
- String ivar_name = str_lit("__$ivar");
- String ivar_types = str_lit("{= }"); //lb_get_objc_type_encoding(ivar_type, temporary_allocator());// str_lit("{= }");
- args.count = 5;
- args[0] = class_value;
- args[1] = lb_const_value(m, t_cstring, exact_value_string(ivar_name));
- args[2] = lb_const_value(m, t_uint, exact_value_u64((u64)size));
- args[3] = lb_const_value(m, t_u8, exact_value_u64((u64)alignment));
- args[4] = lb_const_value(m, t_cstring, exact_value_string(ivar_types));
- lb_emit_runtime_call(p, "class_addIvar", args);
- }
-
- // Complete the class registration
- args.count = 1;
- args[0] = class_value;
- lb_emit_runtime_call(p, "objc_registerClassPair", args);
- }
+ if (is_context_provider_ivar) {
+ // The context provider takes the ivar's type.
+ // Emit an obj_ivar_get call and use that pointer for 'self' instead.
+ lbValue real_self {
+ wrapper_proc->raw_input_parameters[0],
+ class_ptr_type
+ };
+ get_context_args[0] = lb_handle_objc_ivar_for_objc_object_pointer(wrapper_proc, real_self);
+ }
+
+ lbValue context = lb_emit_call(wrapper_proc, context_provider_proc_value, get_context_args);
+ lbAddr context_addr = lb_addr(lb_address_from_load_or_generate_local(wrapper_proc, context));
+ lb_push_context_onto_stack(wrapper_proc, context_addr);
+ }
+
+
+ auto method_call_args = array_make<lbValue>(temporary_allocator(), method_param_count + (isize)method_param_offset);
+
+ if (!md.ac.objc_is_class_method) {
+ method_call_args[0] = lbValue {
+ wrapper_proc->raw_input_parameters[0],
+ class_ptr_type,
+ };
+ }
+
+ for (isize i = 0; i < method_param_count; i++) {
+ method_call_args[i+method_param_offset] = lbValue {
+ wrapper_proc->raw_input_parameters[i+2],
+ method_type->Proc.params->Tuple.variables[i+method_param_offset]->type,
+ };
+ }
+ lbValue method_proc_value = lb_find_procedure_value_from_entity(m, md.proc_entity);
+
+ // Call real procedure for method from here, passing the parameters expected, if any.
+ lbValue return_value = lb_emit_call(wrapper_proc, method_proc_value, method_call_args);
+
+ if (wrapper_results_tuple != nullptr) {
+ auto &result_var = method_type->Proc.results->Tuple.variables[0];
+ return_value = lb_emit_conv(wrapper_proc, return_value, result_var->type);
+ lb_build_return_stmt_internal(wrapper_proc, return_value, result_var->token.pos);
+ }
+ }
+ lb_end_procedure_body(wrapper_proc);
+
+
+ // Add the method to the class
+ String method_encoding = str_lit("v");
+ // TODO (harold): Checker must ensure that objc_methods have a single return value or none!
+ GB_ASSERT(method_type->Proc.result_count <= 1);
+ if (method_type->Proc.result_count != 0) {
+ method_encoding = lb_get_objc_type_encoding(method_type->Proc.results->Tuple.variables[0]->type, temporary_allocator());
+ }
+
+ if (!md.ac.objc_is_class_method) {
+ method_encoding = concatenate_strings(temporary_allocator(), method_encoding, str_lit("@:"));
+ } else {
+ method_encoding = concatenate_strings(temporary_allocator(), method_encoding, str_lit("#:"));
+ }
+
+ for (i32 i = method_param_offset; i < method_param_count; i++) {
+ Type *param_type = method_type->Proc.params->Tuple.variables[i]->type;
+ String param_encoding = lb_get_objc_type_encoding(param_type, temporary_allocator());
+
+ method_encoding = concatenate_strings(temporary_allocator(), method_encoding, param_encoding);
+ }
+
+ // Emit method registration
+ lbAddr* sel_address = string_map_get(&m->objc_selectors, md.ac.objc_selector);
+ GB_ASSERT(sel_address);
+ lbValue selector_value = lb_addr_load(p, *sel_address);
+
+ args.count = 4;
+ args[0] = class_value; // Class
+ args[1] = selector_value; // SEL
+ args[2] = lbValue { wrapper_proc->value, wrapper_proc->type };
+ args[3] = lb_const_value(m, t_cstring, exact_value_string(method_encoding));
+
+ // TODO(harold): Emit check BOOL result and panic if false.
+ lb_emit_runtime_call(p, "class_addMethod", args);
+
+ } // End methods
+
+ // Add ivar if we have one
+ if (ivar_type != nullptr) {
+ // Register a single ivar for this class
+ Type *ivar_base = ivar_type->Named.base;
+
+ const i64 size = type_size_of(ivar_base);
+ const i64 alignment = type_align_of(ivar_base);
+ // TODO(harold): Checker: Alignment must be compatible with ivar rules. Or we should increase the alignment if needed.
+
+ // TODO(harold): Should we pass the actual type encoding? Might not be ideal for obfuscation.
+ String ivar_name = str_lit("__$ivar");
+ String ivar_types = str_lit("{= }"); //lb_get_objc_type_encoding(ivar_type, temporary_allocator());// str_lit("{= }");
+ args.count = 5;
+ args[0] = class_value;
+ args[1] = lb_const_value(m, t_cstring, exact_value_string(ivar_name));
+ args[2] = lb_const_value(m, t_uint, exact_value_u64((u64)size));
+ args[3] = lb_const_value(m, t_u8, exact_value_u64((u64)alignment));
+ args[4] = lb_const_value(m, t_cstring, exact_value_string(ivar_types));
+ lb_emit_runtime_call(p, "class_addIvar", args);
+ }
+
+ // Complete the class registration
+ args.count = 1;
+ args[0] = class_value;
+ lb_emit_runtime_call(p, "objc_registerClassPair", args);
+ }
// Register ivar offsets for any `objc_ivar_get` expressions emitted.
Type *ptr_u32 = alloc_type_pointer(t_u32);
diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp
index 7694c65c3..99ee2b2ff 100644
--- a/src/llvm_backend.hpp
+++ b/src/llvm_backend.hpp
@@ -196,7 +196,7 @@ struct lbModule {
StringMap<lbAddr> objc_classes;
StringMap<lbAddr> objc_selectors;
- StringMap<lbAddr> objc_ivars;
+ StringMap<lbAddr> objc_ivars;
PtrMap<u64/*type hash*/, lbAddr> map_cell_info_map; // address of runtime.Map_Info
PtrMap<u64/*type hash*/, lbAddr> map_info_map; // address of runtime.Map_Cell_Info
@@ -220,7 +220,7 @@ struct lbObjCGlobal {
gbString global_name;
String name;
Type * type;
- Type * class_impl_type; // This is set when the class has the objc_implement attribute set to true.
+ Type * class_impl_type; // This is set when the class has the objc_implement attribute set to true.
};
struct lbGenerator : LinkerData {
@@ -242,7 +242,7 @@ struct lbGenerator : LinkerData {
MPSCQueue<lbEntityCorrection> entities_to_correct_linkage;
MPSCQueue<lbObjCGlobal> objc_selectors;
MPSCQueue<lbObjCGlobal> objc_classes;
- MPSCQueue<lbObjCGlobal> objc_ivars;
+ MPSCQueue<lbObjCGlobal> objc_ivars;
};
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index 7f012e006..bb683465b 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -101,7 +101,7 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
string_map_init(&m->objc_classes);
string_map_init(&m->objc_selectors);
- string_map_init(&m->objc_ivars);
+ string_map_init(&m->objc_ivars);
map_init(&m->map_info_map, 0);
map_init(&m->map_cell_info_map, 0);
@@ -174,7 +174,7 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
mpsc_init(&gen->entities_to_correct_linkage, heap_allocator());
mpsc_init(&gen->objc_selectors, heap_allocator());
mpsc_init(&gen->objc_classes, heap_allocator());
- mpsc_init(&gen->objc_ivars, heap_allocator());
+ mpsc_init(&gen->objc_ivars, heap_allocator());
return true;
}
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index bf4ebf377..ba375283e 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -3290,7 +3290,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
case BuiltinProc_objc_find_class: return lb_handle_objc_find_class(p, expr);
case BuiltinProc_objc_register_selector: return lb_handle_objc_register_selector(p, expr);
case BuiltinProc_objc_register_class: return lb_handle_objc_register_class(p, expr);
- case BuiltinProc_objc_ivar_get: return lb_handle_objc_ivar_get(p, expr);
+ case BuiltinProc_objc_ivar_get: return lb_handle_objc_ivar_get(p, expr);
case BuiltinProc_constant_utf16_cstring:
diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp
index 33211395a..264364162 100644
--- a/src/llvm_backend_utility.cpp
+++ b/src/llvm_backend_utility.cpp
@@ -2157,8 +2157,8 @@ gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String
gb_internal lbAddr lb_handle_objc_find_or_register_ivar(lbModule *m, Type *self_type) {
- String name = self_type->Named.type_name->TypeName.objc_class_name;
- GB_ASSERT(name != "");
+ String name = self_type->Named.type_name->TypeName.objc_class_name;
+ GB_ASSERT(name != "");
lbAddr *found = string_map_get(&m->objc_ivars, name);
if (found) {
@@ -2170,7 +2170,7 @@ gb_internal lbAddr lb_handle_objc_find_or_register_ivar(lbModule *m, Type *self_
gbString global_name = gb_string_make(permanent_allocator(), "__$objc_ivar::");
global_name = gb_string_append_length(global_name, name.text, name.len);
- // Create a global variable to store offset of the ivar in an instance of an object
+ // Create a global variable to store offset of the ivar in an instance of an object
LLVMTypeRef t = lb_type(m, t_u32);
lbValue g = {};
@@ -2209,10 +2209,10 @@ gb_internal lbValue lb_handle_objc_ivar_for_objc_object_pointer(lbProcedure *p,
}
gb_internal lbValue lb_handle_objc_ivar_get(lbProcedure *p, Ast *expr) {
- ast_node(ce, CallExpr, expr);
+ ast_node(ce, CallExpr, expr);
- GB_ASSERT(ce->args[0]->tav.type->kind == Type_Pointer);
- lbValue self = lb_build_expr(p, ce->args[0]);
+ GB_ASSERT(ce->args[0]->tav.type->kind == Type_Pointer);
+ lbValue self = lb_build_expr(p, ce->args[0]);
return lb_handle_objc_ivar_for_objc_object_pointer(p, self);
}
@@ -2282,7 +2282,7 @@ gb_internal lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) {
GB_ASSERT(e->kind == Entity_TypeName);
String name = e->TypeName.objc_class_name;
- Type *class_impl_type = e->TypeName.objc_is_implementation ? type : nullptr;
+ Type *class_impl_type = e->TypeName.objc_is_implementation ? type : nullptr;
return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name, class_impl_type));
}