From 3ba0afac60e80851c01541364d8991667809cec0 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Tue, 29 Sep 2020 19:16:12 +0100 Subject: [PATCH] Objective-C, Darwin : Update message call codegen. Platform compilers based on LLVM do not use the objc_sendMsg_fixit and friends for newer editions of the OS (runtimes for Arm64 do not even have those entries). We need to arrange to allow for this codegen on modern Darwin. The _fixit versions are needed for some OS versions (at least, up to 10.6) since the super2 call is not implemented there. It does not seem worth making the codegen more fine-grained at present. Other parts of the codegen need to be made conditional on either the runtime version or the linker capabilities. gcc/objc/ChangeLog: * objc-next-runtime-abi-02.c (TAG_MSGSENDSUPER): Revised spelling. (TAG_MSGSENDID): Likewise. (TAG_MSGSENDSUPER_STRET): Likewise. (TAG_MSGSENDID_STRET): Likewise. (FIXUP_NEEDED): Likewise. (TAG_FIXUP): New. (next_runtime_02_initialize): Adjust message calls to use fixup variants only when required. (next_runtime_abi_02_get_arg_type_list_base): Correct indent. (build_v2_build_objc_method_call): New. (build_v2_objc_method_fixup_call): Split out from ... (next_runtime_abi_02_build_objc_method_call): ... here. Arrange to adjust the call on the basis of the target runtime. --- gcc/objc/objc-next-runtime-abi-02.c | 233 ++++++++++++++++++++++------ 1 file changed, 187 insertions(+), 46 deletions(-) diff --git a/gcc/objc/objc-next-runtime-abi-02.c b/gcc/objc/objc-next-runtime-abi-02.c index 92ede0325e9..0c7a600c597 100644 --- a/gcc/objc/objc-next-runtime-abi-02.c +++ b/gcc/objc/objc-next-runtime-abi-02.c @@ -63,9 +63,15 @@ along with GCC; see the file COPYING3. If not see #define TAG_GETMETACLASS "objc_getMetaClass" #define TAG_MSGSEND "objc_msgSend" -#define TAG_MSGSENDSUPER "objc_msgSendSuper" +#define TAG_MSGSENDID "objc_msgSendId" +#define TAG_MSGSENDSUPER "objc_msgSendSuper2" #define TAG_MSGSEND_STRET "objc_msgSend_stret" -#define TAG_MSGSENDSUPER_STRET "objc_msgSendSuper_stret" +#define TAG_MSGSENDID_STRET "objc_msgSendId_stret" +#define TAG_MSGSENDSUPER_STRET "objc_msgSendSuper2_stret" + +#define FIXUP_NEEDED 100600 +#define TAG_FIXUP "_fixup" + #define TAG_NEXT_EHVTABLE_NAME "objc_ehtype_vtable" #define TAG_V2_EH_TYPE "objc_ehtype_t" @@ -386,32 +392,43 @@ static void next_runtime_02_initialize (void) build_v2_protocol_template (); build_v2_category_template (); - /* id objc_msgSend_fixup_rtp (id, struct message_ref_t*, ...); */ - type = build_varargs_function_type_list (objc_object_type, - objc_object_type, - objc_v2_selector_type, - NULL_TREE); - umsg_fixup_decl = add_builtin_function ("objc_msgSend_fixup", - type, 0, NOT_BUILT_IN, + bool fixup_p = flag_next_runtime < FIXUP_NEEDED; + if (fixup_p) + { + /* id objc_msgSend_fixup_rtp (id, struct message_ref_t*, ...); */ + type = build_varargs_function_type_list (objc_object_type, + objc_object_type, + objc_v2_selector_type, + NULL_TREE); + } + else + { + /* id objc_msgSendXXXX (id, SEL, ...); */ + type = build_varargs_function_type_list (objc_object_type, + objc_object_type, + objc_selector_type, + NULL_TREE); + } + const char *fnam = fixup_p ? TAG_MSGSEND TAG_FIXUP : TAG_MSGSEND; + umsg_fixup_decl = add_builtin_function (fnam, type, 0, NOT_BUILT_IN, NULL, NULL_TREE); TREE_NOTHROW (umsg_fixup_decl) = 0; /* id objc_msgSend_stret_fixup_rtp (id, struct message_ref_t*, ...); */ - umsg_stret_fixup_decl = add_builtin_function ("objc_msgSend_stret_fixup", - type, 0, NOT_BUILT_IN, + fnam = fixup_p ? TAG_MSGSEND_STRET TAG_FIXUP : TAG_MSGSEND_STRET; + umsg_stret_fixup_decl = add_builtin_function (fnam, type, 0, NOT_BUILT_IN, NULL, NULL_TREE); TREE_NOTHROW (umsg_stret_fixup_decl) = 0; /* id objc_msgSendId_fixup_rtp (id, struct message_ref_t*, ...); */ - umsg_id_fixup_decl = add_builtin_function ("objc_msgSendId_fixup", - type, 0, NOT_BUILT_IN, + fnam = fixup_p ? TAG_MSGSENDID TAG_FIXUP : TAG_MSGSENDID; + umsg_id_fixup_decl = add_builtin_function (fnam, type, 0, NOT_BUILT_IN, NULL, NULL_TREE); TREE_NOTHROW (umsg_id_fixup_decl) = 0; - /* id objc_msgSendId_stret_fixup_rtp - (id, struct message_ref_t*, ...); */ - umsg_id_stret_fixup_decl = add_builtin_function ("objc_msgSendId_stret_fixup", - type, 0, NOT_BUILT_IN, + /* id objc_msgSendId_stret_fixup_rtp (id, struct message_ref_t*, ...); */ + fnam = fixup_p ? TAG_MSGSENDID_STRET TAG_FIXUP : TAG_MSGSENDID_STRET; + umsg_id_stret_fixup_decl = add_builtin_function (fnam, type, 0, NOT_BUILT_IN, NULL, NULL_TREE); TREE_NOTHROW (umsg_id_stret_fixup_decl) = 0; @@ -421,17 +438,17 @@ static void next_runtime_02_initialize (void) objc_super_type, objc_v2_super_selector_type, NULL_TREE); - umsg_id_super2_fixup_decl = add_builtin_function ("objc_msgSendSuper2_fixup", - type, 0, NOT_BUILT_IN, + fnam = fixup_p ? TAG_MSGSENDSUPER TAG_FIXUP : TAG_MSGSENDSUPER; + umsg_id_super2_fixup_decl = add_builtin_function (fnam, type, 0, NOT_BUILT_IN, NULL, NULL_TREE); TREE_NOTHROW (umsg_id_super2_fixup_decl) = 0; /* id objc_msgSendSuper2_stret_fixup_rtp (struct objc_super *, struct message_ref_t*, ...); */ - umsg_id_super2_stret_fixup_decl = - add_builtin_function ("objc_msgSendSuper2_stret_fixup", - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); + fnam = fixup_p ? TAG_MSGSENDSUPER_STRET TAG_FIXUP : TAG_MSGSENDSUPER_STRET; + umsg_id_super2_stret_fixup_decl = add_builtin_function (fnam, type, 0, + NOT_BUILT_IN, NULL, + NULL_TREE); TREE_NOTHROW (umsg_id_super2_stret_fixup_decl) = 0; /* Present in the library, but unused by the FE. */ @@ -1134,10 +1151,12 @@ next_runtime_abi_02_get_arg_type_list_base (vec **argtypes, receiver_type = objc_object_type; vec_safe_push (*argtypes, receiver_type); - /* Selector type - will eventually change to `int'. */ - vec_safe_push (*argtypes, - superflag ? objc_v2_super_selector_type - : objc_v2_selector_type); + if (flag_next_runtime < FIXUP_NEEDED) + /* Selector type - will eventually change to `int'. */ + vec_safe_push (*argtypes, superflag ? objc_v2_super_selector_type + : objc_v2_selector_type); + else + vec_safe_push (*argtypes, objc_selector_type); } /* TODO: Merge this with the message refs. */ @@ -1589,10 +1608,9 @@ objc_copy_to_temp_side_effect_params (tree fntype, tree values) (*_msg.messenger) (receiver, &_msg, ...) */ static tree -build_v2_build_objc_method_call (int super_flag, tree method_prototype, - tree lookup_object, tree selector, - tree method_params, - bool check_for_nil) +build_v2_objc_method_fixup_call (int super_flag, tree method_prototype, + tree lookup_object, tree selector, + tree method_params, bool check_for_nil) { tree ret_val; tree sender, rcv_p, t; @@ -1672,6 +1690,118 @@ build_v2_build_objc_method_call (int super_flag, tree method_prototype, return ret_val; } +static tree +build_v2_build_objc_method_call (int super, tree method_prototype, + tree lookup_object, tree selector, + tree method_params, location_t loc, + bool check_for_nil, bool rx_is_id) +{ + tree sender, sender_cast, method, t; + tree rcv_p = (super ? objc_super_type : objc_object_type); + vec *parms; + unsigned nparm = (method_params ? list_length (method_params) : 0); + + /* If a prototype for the method to be called exists, then cast + the sender's return type and arguments to match that of the method. + Otherwise, leave sender as is. */ + tree ret_type + = (method_prototype + ? TREE_VALUE (TREE_TYPE (method_prototype)) + : objc_object_type); + tree ftype = build_function_type_for_method (ret_type, method_prototype, + METHOD_REF, super); + + if (method_prototype && METHOD_TYPE_ATTRIBUTES (method_prototype)) + ftype = build_type_attribute_variant (ftype, + METHOD_TYPE_ATTRIBUTES + (method_prototype)); + + sender_cast = build_pointer_type (ftype); + + lookup_object = build_c_cast (loc, rcv_p, lookup_object); + + /* Use SAVE_EXPR to avoid evaluating the receiver twice. */ + lookup_object = save_expr (lookup_object); + + /* Param list + 2 slots for object and selector. */ + vec_alloc (parms, nparm + 2); + + /* If we are returning a struct in memory, and the address + of that memory location is passed as a hidden first + argument, then change which messenger entry point this + expr will call. NB: Note that sender_cast remains + unchanged (it already has a struct return type). */ + if (!targetm.calls.struct_value_rtx (0, 0) + && (TREE_CODE (ret_type) == RECORD_TYPE + || TREE_CODE (ret_type) == UNION_TYPE) + && targetm.calls.return_in_memory (ret_type, 0)) + { + if (super) + sender = umsg_id_super2_stret_fixup_decl; + else + sender = rx_is_id ? umsg_id_stret_fixup_decl + : umsg_stret_fixup_decl; + } + else + { + if (super) + sender = umsg_id_super2_fixup_decl; + else + sender = rx_is_id ? umsg_id_fixup_decl + : umsg_fixup_decl; + } + + method = build_fold_addr_expr_loc (loc, sender); + + /* Pass the object to the method. */ + parms->quick_push (lookup_object); + /* Pass the selector to the method. */ + parms->quick_push (selector); + /* Now append the remainder of the parms. */ + if (nparm) + for (; method_params; method_params = TREE_CHAIN (method_params)) + parms->quick_push (TREE_VALUE (method_params)); + + /* Build an obj_type_ref, with the correct cast for the method call. */ + t = build3 (OBJ_TYPE_REF, sender_cast, method, + lookup_object, size_zero_node); + tree ret_val = build_function_call_vec (loc, vNULL, t, parms, NULL); + vec_free (parms); + if (check_for_nil) + { + /* receiver != nil ? ret_val : 0 */ + tree ftree; + tree ifexp; + + if (TREE_CODE (ret_type) == RECORD_TYPE + || TREE_CODE (ret_type) == UNION_TYPE) + { + vec *rtt = NULL; + /* ??? CHECKME. hmmm..... think we need something more + here. */ + CONSTRUCTOR_APPEND_ELT (rtt, NULL_TREE, NULL_TREE); + ftree = objc_build_constructor (ret_type, rtt); + } + else + ftree = fold_convert (ret_type, integer_zero_node); + + ifexp = build_binary_op (loc, NE_EXPR, + lookup_object, + fold_convert (rcv_p, integer_zero_node), 1); + +#ifdef OBJCPLUS + ret_val = build_conditional_expr (loc, ifexp, ret_val, ftree, + tf_warning_or_error); +#else + /* ??? CHECKME. */ + ret_val = build_conditional_expr (loc, ifexp, 1, + ret_val, NULL_TREE, loc, + ftree, NULL_TREE, loc); +#endif + } + return ret_val; +} + static tree next_runtime_abi_02_build_objc_method_call (location_t loc, tree method_prototype, @@ -1681,27 +1811,38 @@ next_runtime_abi_02_build_objc_method_call (location_t loc, tree method_params, int super) { - tree ret_type, selector; - tree message_func_decl; - bool check_for_nil = flag_objc_nilcheck; - - ret_type = method_prototype - ? TREE_VALUE (TREE_TYPE (method_prototype)) - : objc_object_type; - /* Do we need to check for nil receivers ? */ /* For now, message sent to classes need no nil check. In the future, class declaration marked as weak_import must be nil checked. */ + bool check_for_nil = flag_objc_nilcheck; if (super || (TREE_CODE (receiver) == VAR_DECL && TREE_TYPE (receiver) == objc_class_type)) check_for_nil = false; + if (flag_next_runtime >= FIXUP_NEEDED) + { + tree selector + = next_runtime_abi_02_build_selector_reference (loc, sel_name, + method_prototype); + return build_v2_build_objc_method_call (super, method_prototype, + receiver, selector, + method_params, loc, + check_for_nil, + objc_is_id (rtype)); + } + + /* else we have to build a pair of the function and selector. */ + tree message_func_decl; + tree ret_type = method_prototype + ? TREE_VALUE (TREE_TYPE (method_prototype)) + : objc_object_type; + if (!targetm.calls.struct_value_rtx (0, 0) - && (TREE_CODE (ret_type) == RECORD_TYPE - || TREE_CODE (ret_type) == UNION_TYPE) - && targetm.calls.return_in_memory (ret_type, 0)) + && (TREE_CODE (ret_type) == RECORD_TYPE + || TREE_CODE (ret_type) == UNION_TYPE) + && targetm.calls.return_in_memory (ret_type, 0)) { if (super) message_func_decl = umsg_id_super2_stret_fixup_decl; @@ -1720,7 +1861,7 @@ next_runtime_abi_02_build_objc_method_call (location_t loc, : umsg_fixup_decl; } - selector = build_v2_selector_messenger_reference (sel_name, + tree selector = build_v2_selector_messenger_reference (sel_name, message_func_decl); /* selector = &_msg; */ @@ -1731,9 +1872,9 @@ next_runtime_abi_02_build_objc_method_call (location_t loc, selector); /* (*_msg.messenger) (receiver, &_msg, ...); */ - return build_v2_build_objc_method_call (super, method_prototype, - receiver, selector, - method_params, check_for_nil); + return build_v2_objc_method_fixup_call (super, method_prototype, receiver, + selector, method_params, + check_for_nil); } /* NOTE --- Constant String Class Stuff --- */ -- 2.30.2