public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Objective-C: fix protocol list count type (pertinent to non-LP64)
@ 2021-09-27  3:45 Matt Jacobson
  2021-10-20  3:51 ` Matt Jacobson
  0 siblings, 1 reply; 6+ messages in thread
From: Matt Jacobson @ 2021-09-27  3:45 UTC (permalink / raw)
  To: gcc-patches

Fix protocol list layout for non-LP64.  clang and objc4 both give the `count` 
field as `long`, not `intptr_t`.  Those are the same on LP64, but not 
everywhere.  For non-LP64, this fixes binary compatibility with clang-built 
classes.

This was more complicated than I anticipated, because the relevant frontend 
code in fact had no AST type for `protocol_list_t`, instead emitting protocol 
lists as `protocol_t[]`, with the zeroth element actually being the integer 
count.  That made it nontrivial to change the count to `long`.  With this 
change, there is now a true `protocol_list_t` type in the AST.

Tested multiple ways.  On x86_64/Darwin, I confirmed with a test program that 
protocol conformances by classes, categories, and protocols works.  On AVR, I 
manually inspected the generated assembly to confirm that protocol lists gain 
an extra two bytes of `count`, matching clang.

Thank you for your time.

<https://github.com/mhjacobson/gcc/commit/5ebc95dc726f0745ebdf003093f1b8d7720ce32f>


gcc/objc/ChangeLog:

2021-09-26  Matt Jacobson  <mhjacobson@me.com>

	* objc-next-runtime-abi-02.c (enum objc_v2_tree_index): Add new global tree.
	(static void next_runtime_02_initialize): Initialize protocol list type tree.
	(struct class_ro_t): Fix type misspelling.
	(build_v2_class_templates): Correct type in field declaration.
	(build_v2_protocol_templates): Create actual protocol list type tree.
	(build_v2_category_template): Correct type in field declaration.
	(generate_v2_protocol_list): Emit protocol list count as `long`.
	(generate_v2_protocols): Use correct type.
	(build_v2_category_initializer): Use correct type.
	(build_v2_class_ro_t_initializer): Use correct type.


diff --git a/gcc/objc/objc-next-runtime-abi-02.c b/gcc/objc/objc-next-runtime-abi-02.c
index c3af369ff0d..aadf1741676 100644
--- a/gcc/objc/objc-next-runtime-abi-02.c
+++ b/gcc/objc/objc-next-runtime-abi-02.c
@@ -92,6 +92,7 @@ enum objc_v2_tree_index
   OCTI_V2_CAT_TEMPL,
   OCTI_V2_CLS_RO_TEMPL,
   OCTI_V2_PROTO_TEMPL,
+  OCTI_V2_PROTO_LIST_TEMPL,
   OCTI_V2_IVAR_TEMPL,
   OCTI_V2_IVAR_LIST_TEMPL,
   OCTI_V2_MESSAGE_REF_TEMPL,
@@ -130,6 +131,8 @@ enum objc_v2_tree_index
 				objc_v2_global_trees[OCTI_V2_CAT_TEMPL]
 #define objc_v2_protocol_template \
 				objc_v2_global_trees[OCTI_V2_PROTO_TEMPL]
+#define objc_v2_protocol_list_template \
+				objc_v2_global_trees[OCTI_V2_PROTO_LIST_TEMPL]
 
 /* struct message_ref_t */
 #define objc_v2_message_ref_template \
@@ -196,7 +199,7 @@ static void build_v2_message_ref_templates (void);
 static void build_v2_class_templates (void);
 static void build_v2_super_template (void);
 static void build_v2_category_template (void);
-static void build_v2_protocol_template (void);
+static void build_v2_protocol_templates (void);
 
 static tree next_runtime_abi_02_super_superclassfield_id (void);
 
@@ -394,9 +397,9 @@ static void next_runtime_02_initialize (void)
 		build_pointer_type (xref_tag (RECORD_TYPE,
 				    get_identifier ("_prop_list_t")));
 
+  build_v2_protocol_templates ();
   build_v2_class_templates ();
   build_v2_super_template ();
-  build_v2_protocol_template ();
   build_v2_category_template ();
 
   bool fixup_p = flag_next_runtime < USE_FIXUP_BEFORE;
@@ -636,7 +639,7 @@ struct class_ro_t
     const uint8_t * const ivarLayout;
     const char *const name;
     const struct method_list_t * const baseMethods;
-    const struct objc_protocol_list *const baseProtocols;
+    const struct protocol_list_t *const baseProtocols;
     const struct ivar_list_t *const ivars;
     const uint8_t * const weakIvarLayout;
     const struct _prop_list_t * const properties;
@@ -685,11 +688,9 @@ build_v2_class_templates (void)
   /* const struct method_list_t * const baseMethods; */
   add_field_decl (objc_method_list_ptr, "baseMethods", &chain);
 
-  /* const struct objc_protocol_list *const baseProtocols; */
-  add_field_decl (build_pointer_type
-			(xref_tag (RECORD_TYPE,
-				   get_identifier (UTAG_V2_PROTOCOL_LIST))),
-				  "baseProtocols", &chain);
+  /* const struct protocol_list_t *const baseProtocols; */
+  add_field_decl (build_pointer_type (objc_v2_protocol_list_template),
+		  "baseProtocols", &chain);
 
   /* const struct ivar_list_t *const ivars; */
   add_field_decl (objc_v2_ivar_list_ptr, "ivars", &chain);
@@ -763,25 +764,33 @@ build_v2_super_template (void)
      const char ** extended_method_types;
      const char * demangled_name;
      const struct _prop_list_t * class_properties;
-   }
+  };
+
+  struct protocol_list_t
+  {
+    long count;
+    struct protocol_t protocols[];
+  };
 */
 static void
-build_v2_protocol_template (void)
+build_v2_protocol_templates (void)
 {
-  tree decls, *chain = NULL;
+  tree decls, protolist_pointer_type, protocol_pointer_type, *chain;
 
   objc_v2_protocol_template =
 	objc_start_struct (get_identifier (UTAG_V2_PROTOCOL));
 
   /* Class isa; */
+  chain = NULL;
   decls = add_field_decl (objc_object_type, "isa", &chain);
 
   /* char *protocol_name; */
   add_field_decl (string_type_node, "protocol_name", &chain);
 
   /* const struct protocol_list_t * const protocol_list; */
-  add_field_decl (build_pointer_type (objc_v2_protocol_template),
-		  "protocol_list", &chain);
+  protolist_pointer_type = build_pointer_type (xref_tag (RECORD_TYPE,
+				get_identifier (UTAG_V2_PROTOCOL_LIST)));
+  add_field_decl (protolist_pointer_type, "protocol_list", &chain);
 
   /* const struct method_list_t * const instance_methods; */
   add_field_decl (objc_method_proto_list_ptr,  "instance_methods", &chain);
@@ -815,6 +824,24 @@ build_v2_protocol_template (void)
   add_field_decl (objc_prop_list_ptr, "class_properties", &chain);
 
   objc_finish_struct (objc_v2_protocol_template, decls);
+
+  /* --- */
+
+  objc_v2_protocol_list_template =
+		objc_start_struct (get_identifier (UTAG_V2_PROTOCOL_LIST));
+  gcc_assert (TREE_TYPE (protolist_pointer_type)
+		== objc_v2_protocol_list_template);
+
+  /* long count; */
+  chain = NULL;
+  decls = add_field_decl (long_integer_type_node, "count", &chain);
+
+  /* struct protocol_t *protocols[]; */
+  protocol_pointer_type = build_pointer_type (objc_v2_protocol_template);
+  add_field_decl (build_array_type (protocol_pointer_type, 0), "protocols",
+		  &chain);
+
+  objc_finish_struct (objc_v2_protocol_list_template, decls);
 }
 
 /* Build type for a category:
@@ -850,7 +877,7 @@ build_v2_category_template (void)
   add_field_decl (objc_method_list_ptr, "class_methods", &chain);
 
   /* struct protocol_list_t *protocol_list; */
-  add_field_decl (build_pointer_type (objc_v2_protocol_template),
+  add_field_decl (build_pointer_type (objc_v2_protocol_list_template),
                   "protocol_list", &chain );
 
   /* struct _prop_list_t * properties; */
@@ -2323,9 +2350,9 @@ build_v2_protocol_list_address_table (void)
 static tree
 generate_v2_protocol_list (tree i_or_p, tree klass_ctxt)
 {
-  tree refs_decl, lproto, e, plist, ptempl_p_t;
+  tree refs_decl, lproto, plist, protocol_pointer_type, array_ctor, ctor;
   int size = 0;
-  vec<constructor_elt, va_gc> *initlist = NULL;
+  vec<constructor_elt, va_gc> *initlist = NULL, *subinitlist = NULL;
   char buf[BUFSIZE];
 
   if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE
@@ -2336,18 +2363,7 @@ generate_v2_protocol_list (tree i_or_p, tree klass_ctxt)
   else
     gcc_unreachable ();
 
-  /* Compute size.  */
-  for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
-    if (TREE_CODE (TREE_VALUE (lproto)) == PROTOCOL_INTERFACE_TYPE
-	&& PROTOCOL_FORWARD_DECL (TREE_VALUE (lproto)))
-      size++;
-
-  /* Build initializer.  */
-
-  ptempl_p_t = build_pointer_type (objc_v2_protocol_template);
-  e = build_int_cst (ptempl_p_t, size);
-  CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, e);
-
+  /* Compute size, and build array initializer.  */
   for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
     {
       tree pval = TREE_VALUE (lproto);
@@ -2356,14 +2372,24 @@ generate_v2_protocol_list (tree i_or_p, tree klass_ctxt)
 	  && PROTOCOL_FORWARD_DECL (pval))
 	{
 	  tree fwref = PROTOCOL_FORWARD_DECL (pval);
-	  location_t loc = DECL_SOURCE_LOCATION (fwref) ;
-	  e = build_unary_op (loc, ADDR_EXPR, fwref, 0);
-	  CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, e);
+	  location_t loc = DECL_SOURCE_LOCATION (fwref);
+	  tree e = build_unary_op (loc, ADDR_EXPR, fwref, 0);
+	  CONSTRUCTOR_APPEND_ELT (subinitlist,
+				  build_int_cst (NULL_TREE, size), e);
+
+	  size++;
 	}
     }
 
-  /* static struct protocol_list_t *list[size]; */
+  /* Build struct initializer.  */
+  CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE,
+			  build_int_cst (long_integer_type_node, size));
+  protocol_pointer_type = build_pointer_type (objc_v2_protocol_template);
+  array_ctor = objc_build_constructor (
+		build_array_type (protocol_pointer_type, 0), subinitlist);
+  CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, array_ctor);
 
+  /* Build declaration name.  */
   switch (TREE_CODE (i_or_p))
     {
     case PROTOCOL_INTERFACE_TYPE:
@@ -2383,13 +2409,13 @@ generate_v2_protocol_list (tree i_or_p, tree klass_ctxt)
 	gcc_unreachable ();
     }
 
-  refs_decl = start_var_decl (build_sized_array_type (ptempl_p_t, size+1),
-			      buf);
+  /* Build declaration.  */
+  refs_decl = start_var_decl (objc_v2_protocol_list_template, buf);
   /* ObjC2 puts all these in the base section.  */
   OBJCMETA (refs_decl, objc_meta, meta_base);
   DECL_PRESERVE_P (refs_decl) = 1;
-  finish_var_decl (refs_decl,
-		   objc_build_constructor (TREE_TYPE (refs_decl),initlist));
+  ctor = objc_build_constructor (objc_v2_protocol_list_template, initlist);
+  finish_var_decl (refs_decl, ctor);
   return refs_decl;
 }
 
@@ -2794,8 +2820,9 @@ generate_v2_protocols (void)
       protocol_name_expr = add_objc_string (PROTOCOL_NAME (p), class_names);
 
       if (refs_decl)
-	refs_expr = convert (build_pointer_type (objc_v2_protocol_template),
-			     build_unary_op (loc, ADDR_EXPR, refs_decl, 0));
+	refs_expr = convert (
+		build_pointer_type (objc_v2_protocol_list_template),
+		build_unary_op (loc, ADDR_EXPR, refs_decl, 0));
       else
 	refs_expr = build_int_cst (NULL_TREE, 0);
 
@@ -2885,8 +2912,7 @@ build_v2_category_initializer (tree type, tree cat_name, tree class_name,
     expr = convert (ltyp, null_pointer_node);
   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr);
 
-  /* protocol_list = */
-  ltyp = build_pointer_type (objc_v2_protocol_template);
+  ltyp = build_pointer_type (objc_v2_protocol_list_template);
   if (protocol_list)
     expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, protocol_list, 0));
   else
@@ -3238,8 +3264,7 @@ build_v2_class_ro_t_initializer (tree type, tree name,
   CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, expr);
 
   /* baseProtocols */
-  ltyp = build_pointer_type (xref_tag (RECORD_TYPE,
-			               get_identifier (UTAG_V2_PROTOCOL_LIST)));
+  ltyp = build_pointer_type (objc_v2_protocol_list_template);
   if (baseProtocols)
     expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, baseProtocols, 0));
   else


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-11-08 13:41 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-27  3:45 [PATCH] Objective-C: fix protocol list count type (pertinent to non-LP64) Matt Jacobson
2021-10-20  3:51 ` Matt Jacobson
2021-10-23  8:46   ` Iain Sandoe
2021-10-25  9:43     ` Iain Sandoe
2021-11-07 22:50       ` Matt Jacobson
2021-11-08 13:41         ` Iain Sandoe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).