Browse Source

Fix ivar in multi-module mode.

Harold Brenes 5 tháng trước cách đây
mục cha
commit
b3b4d501ca
2 tập tin đã thay đổi với 54 bổ sung29 xóa
  1. 48 21
      src/llvm_backend.cpp
  2. 6 8
      src/llvm_backend_utility.cpp

+ 48 - 21
src/llvm_backend.cpp

@@ -1588,6 +1588,13 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
     // Emit method wrapper implementations and registration
     auto wrapper_args = array_make<Type *>(temporary_allocator(), 2, 8);
 
+	PtrMap<Type *, lbObjCGlobal> ivar_map{};
+	map_init(&ivar_map, gen->objc_ivars.count);
+
+	for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_ivars, &g); /**/) {
+		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;
@@ -1700,7 +1707,9 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
 
         // Add ivar if we have one
         Type *ivar_type = class_type->Named.type_name->TypeName.objc_ivar;
-        if (ivar_type != nullptr) {
+    	lbObjCGlobal *g_ivar = map_get(&ivar_map, class_type);
+
+        if (ivar_type != nullptr && g_ivar != nullptr) {
             // Register a single ivar for this class
             Type *ivar_base = ivar_type->Named.base;
             // TODO(harold): No idea if I can use this, but I assume so?
@@ -1723,28 +1732,46 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
         args.count = 1;
         args[0] = class_value;
         lb_emit_runtime_call(p, "objc_registerClassPair", args);
-
-        // If we have an ivar, store its offset globally for an intrinsic
-        // TODO(harold): Only do this for types that had ivar_get calls registered!
-        if (ivar_type != nullptr) {
-            args.count = 2;
-            args[0] = class_value;
-            args[1] = lb_const_value(m, t_cstring, exact_value_string(str_lit("__$ivar")));
-            lbValue ivar = lb_emit_runtime_call(p, "class_getInstanceVariable", args);
-
-            args.count = 1;
-            args[0] = ivar;
-            lbValue ivar_offset     = lb_emit_runtime_call(p, "ivar_getOffset", args);
-            lbValue ivar_offset_u32 = lb_emit_conv(p, ivar_offset, t_u32);
-
-            String class_name = class_type->Named.type_name->TypeName.objc_class_name;
-            // TODO(harold): Oops! This is wrong, that map is there to prevent re-entry.
-            //               Simply emit from referred ivars. For now use a single module only.
-            lbAddr ivar_addr = string_map_must_get(&m->objc_ivars, class_name);
-            lb_addr_store(p, ivar_addr, ivar_offset_u32);
-        }
     }
 
+	// Register ivars
+	Type *ptr_u32 = alloc_type_pointer(t_u32);
+	for (auto const& kv : ivar_map) {
+		lbObjCGlobal const& g = kv.value;
+		lbAddr ivar_addr = {};
+		lbValue *found = string_map_get(&m->members, g.global_name);
+
+		if (found) {
+			ivar_addr = lb_addr(*found);
+		} else {
+			// Defined in an external package, must define now
+			LLVMTypeRef t = lb_type(m, t_u32);
+
+			lbValue global{};
+			global.value = LLVMAddGlobal(m->mod, t, g.global_name);
+			global.type  = ptr_u32;
+
+			LLVMSetInitializer(global.value, LLVMConstInt(t, 0, true));
+
+			ivar_addr = lb_addr(global);
+		}
+
+		String class_name = g.class_impl_type->Named.type_name->TypeName.objc_class_name;
+		lbValue class_value = string_map_must_get(&global_class_map, class_name).class_value;
+
+		args.count = 2;
+		args[0] = class_value;
+		args[1] = lb_const_value(m, t_cstring, exact_value_string(str_lit("__$ivar")));
+		lbValue ivar = lb_emit_runtime_call(p, "class_getInstanceVariable", args);
+
+		args.count = 1;
+		args[0] = ivar;
+		lbValue ivar_offset     = lb_emit_runtime_call(p, "ivar_getOffset", args);
+		lbValue ivar_offset_u32 = lb_emit_conv(p, ivar_offset, t_u32);
+
+		lb_addr_store(p, ivar_addr, ivar_offset_u32);
+	}
+
 	lb_end_procedure_body(p);
 }
 

+ 6 - 8
src/llvm_backend_utility.cpp

@@ -2165,28 +2165,26 @@ gb_internal lbAddr lb_handle_objc_find_or_register_ivar(lbModule *m, Type *self_
 		return *found;
 	}
 
-
 	lbModule *default_module = &m->gen->default_module;
 
 	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
-    Type *p_ivar_offset = alloc_type_pointer(t_u32);
+	LLVMTypeRef t = lb_type(m, t_u32);
 
-	LLVMTypeRef t = lb_type(m, p_ivar_offset);
 	lbValue g = {};
 	g.value = LLVMAddGlobal(m->mod, t, global_name);
-	g.type  = p_ivar_offset;
+	g.type  = alloc_type_pointer(t_u32);
 
 	if (default_module == m) {
-		LLVMSetInitializer(g.value, LLVMConstNull(t));
+		LLVMSetInitializer(g.value, LLVMConstInt(t, 0, true));
 		lb_add_member(m, make_string_c(global_name), g);
 	} else {
 		LLVMSetLinkage(g.value, LLVMExternalLinkage);
 	}
 
-	mpsc_enqueue(&m->gen->objc_ivars, lbObjCGlobal{m, global_name, name, self_type});
+	mpsc_enqueue(&m->gen->objc_ivars, lbObjCGlobal{m, global_name, name, t_u32, self_type});
 
 	lbAddr addr = lb_addr(g);
 	string_map_set(&m->objc_ivars, name, addr);
@@ -2206,8 +2204,8 @@ gb_internal lbValue lb_handle_objc_ivar_get(lbProcedure *p, Ast *expr) {
     lbValue ivar_offset      = lb_addr_load(p, lb_handle_objc_find_or_register_ivar(m, self_type));
     lbValue ivar_offset_uptr = lb_emit_conv(p, ivar_offset, t_uintptr);
 
-    lbValue self        = lb_build_expr(p, ce->args[0]);
-    lbValue self_uptr   = lb_emit_conv(p, self, t_uintptr);
+    lbValue self      = lb_build_expr(p, ce->args[0]);
+    lbValue self_uptr = lb_emit_conv(p, self, t_uintptr);
 
     lbValue ivar_uptr = lb_emit_arith(p, Token_Add, self_uptr, ivar_offset_uptr, t_uintptr);