From patchwork Mon Sep 27 03:45:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Jacobson X-Patchwork-Id: 45458 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4AD93385802B for ; Mon, 27 Sep 2021 03:45:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4AD93385802B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1632714348; bh=cbTNil7EKcoO37jGWI3bVE8CUAGW6VMNMyhso4joc9M=; h=Subject:Date:To:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=iwCo8+gG1kZEi30POc/B8ZmQ/F8JSpp3vC7MeAqYA+dNNHVR3Ry85EkkUDNIJVBhP nY4MvFq5igtJtZ2UJYIrhvO9FJHJOHadvXibXLcf1G3lalBk3QVWcimYPt4+NwwqMa eAxKYjq79UlMH3RLiLnhv0Cy4M6JMmaFu87B7uR4= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from pv34p98im-ztdg02172101.me.com (pv34p98im-ztdg02172101.me.com [17.143.234.142]) by sourceware.org (Postfix) with ESMTPS id DC980385840E for ; Mon, 27 Sep 2021 03:45:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org DC980385840E Received: from [10.0.1.20] (cpe-98-26-0-177.nc.res.rr.com [98.26.0.177]) by pv34p98im-ztdg02172101.me.com (Postfix) with ESMTPSA id 33621540017 for ; Mon, 27 Sep 2021 03:45:13 +0000 (UTC) Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.120.23.2.7\)) Subject: [PATCH] Objective-C: fix protocol list count type (pertinent to non-LP64) Message-Id: <3FA161CB-9D8F-4576-8607-292CE21B2BF3@me.com> Date: Sun, 26 Sep 2021 23:45:10 -0400 To: gcc-patches@gcc.gnu.org X-Mailer: Apple Mail (2.3608.120.23.2.7) X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.391, 18.0.790 definitions=2021-09-27_01:2021-09-24, 2021-09-27 signatures=0 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=0 malwarescore=0 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 mlxscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-2009150000 definitions=main-2109270024 X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Matt Jacobson via Gcc-patches From: Matt Jacobson Reply-To: Matt Jacobson Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "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. gcc/objc/ChangeLog: 2021-09-26 Matt Jacobson * 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 *initlist = NULL; + vec *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