Objective-C, Darwin : Update message call codegen.
authorIain Sandoe <iain@sandoe.co.uk>
Tue, 29 Sep 2020 18:16:12 +0000 (19:16 +0100)
committerIain Sandoe <iain@sandoe.co.uk>
Sun, 11 Oct 2020 12:38:29 +0000 (13:38 +0100)
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

index 92ede0325e94404c91e951395859a79be11de3ed..0c7a600c5974b5b507221adc9eff079814063152 100644 (file)
@@ -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<tree, va_gc> **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<tree, va_gc> *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<constructor_elt, va_gc> *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 --- */