OSDN Git Service

2008-06-10 Kai Tietz <kai.tietz@onevision.com>
[pf3gnuchains/gcc-fork.git] / libobjc / sendmsg.c
index 61fa288..b132a15 100644 (file)
@@ -1,23 +1,23 @@
 /* GNU Objective C Runtime message lookup 
    Copyright (C) 1993, 1995, 1996, 1997, 1998,
-   2001 Free Software Foundation, Inc.
+   2001, 2002, 2004 Free Software Foundation, Inc.
    Contributed by Kresten Krab Thorup
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify it under the
+GCC is free software; you can redistribute it and/or modify it under the
 terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2, or (at your option) any later version.
 
-GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 details.
 
 You should have received a copy of the GNU General Public License along with
-GNU CC; see the file COPYING.  If not, write to the Free Software
-Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+GCC; see the file COPYING.  If not, write to the Free Software
+Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 /* As a special exception, if you link this library with files compiled with
    GCC to produce an executable, this does not cause the resulting executable
@@ -25,77 +25,100 @@ Boston, MA 02111-1307, USA.  */
    however invalidate any other reasons why the executable file might be
    covered by the GNU General Public License.  */
 
+/* FIXME: This file has no business including tm.h.  */
+/* FIXME: This should be using libffi instead of __builtin_apply
+   and friends.  */
+
 #include "tconfig.h"
-#include "runtime.h"
-#include "sarray.h"
-#include "encoding.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "objc/runtime.h"
+#include "objc/sarray.h"
+#include "objc/encoding.h"
 #include "runtime-info.h"
 
-/* this is how we hack STRUCT_VALUE to be 1 or 0 */
+/* This is how we hack STRUCT_VALUE to be 1 or 0.   */
 #define gen_rtx(args...) 1
 #define gen_rtx_MEM(args...) 1
 #define gen_rtx_REG(args...) 1
+/* Alread defined in gcc/coretypes.h. So prevent double definition warning.  */
+#undef rtx
 #define rtx int
 
-#if !defined(STRUCT_VALUE) || STRUCT_VALUE == 0
+#if ! defined (STRUCT_VALUE) || STRUCT_VALUE == 0
 #define INVISIBLE_STRUCT_RETURN 1
 #else
 #define INVISIBLE_STRUCT_RETURN 0
 #endif
 
 /* The uninstalled dispatch table */
-struct sarray* __objc_uninstalled_dtable = 0;   /* !T:MUTEX */
-
-/* Hook for method forwarding. If it is set, is invoked to return a
-   function that performs the real forwarding. Otherwise the libgcc
-   based functions (__builtin_apply and friends) are used. */
-IMP (*__objc_msg_forward)(SEL) = NULL;
+struct sarray *__objc_uninstalled_dtable = 0;   /* !T:MUTEX */
+
+/* Two hooks for method forwarding. If either is set, it is invoked
+ * to return a function that performs the real forwarding.  If both
+ * are set, the result of __objc_msg_forward2 will be preferred over
+ * that of __objc_msg_forward.  If both return NULL or are unset,
+ * the libgcc based functions (__builtin_apply and friends) are
+ * used.
+ */
+IMP (*__objc_msg_forward) (SEL) = NULL;
+IMP (*__objc_msg_forward2) (id, SEL) = NULL;
 
 /* Send +initialize to class */
-static void __objc_send_initialize(Class);
+static void __objc_send_initialize (Class);
 
 static void __objc_install_dispatch_table_for_class (Class);
 
 /* Forward declare some functions */
-static void __objc_init_install_dtable(id, SEL);
+static void __objc_init_install_dtable (id, SEL);
 
 /* Various forwarding functions that are used based upon the
    return type for the selector.
    __objc_block_forward for structures.
    __objc_double_forward for floats/doubles.
-   __objc_word_forward for pointers or types that fit in registers.
-   */
-static double __objc_double_forward(id, SEL, ...);
-static id __objc_word_forward(id, SEL, ...);
+   __objc_word_forward for pointers or types that fit in registers. */
+static double __objc_double_forward (id, SEL, ...);
+static id __objc_word_forward (id, SEL, ...);
 typedef struct { id many[8]; } __big;
 #if INVISIBLE_STRUCT_RETURN 
 static __big 
 #else
 static id
 #endif
-__objc_block_forward(id, SEL, ...);
+__objc_block_forward (id, SEL, ...);
 static Method_t search_for_method_in_hierarchy (Class class, SEL sel);
-Method_t search_for_method_in_list(MethodList_t list, SEL op);
-id nil_method(id, SEL, ...);
+Method_t search_for_method_in_list (MethodList_t list, SEL op);
+id nil_method (id, SEL);
 
 /* Given a selector, return the proper forwarding implementation. */
-__inline__
+inline
 IMP
-__objc_get_forward_imp (SEL sel)
+__objc_get_forward_imp (id rcv, SEL sel)
 {
+  /* If a custom forwarding hook was registered, try getting a forwarding
+     function from it. There are two forward routine hooks, one that
+     takes the receiver as an argument and one that does not. */
+  if (__objc_msg_forward2)
+    {
+      IMP result;
+      if ((result = __objc_msg_forward2 (rcv, sel)) != NULL)
+       return result;
+    }
   if (__objc_msg_forward)
     {
       IMP result;
-      if ((result = __objc_msg_forward (sel)))
+      if ((result = __objc_msg_forward (sel)) != NULL) 
         return result;
     }
-  else
+
+  /* In all other cases, use the default forwarding functions built using
+     __builtin_apply and friends.  */
     {
       const char *t = sel->sel_types;
 
       if (t && (*t == '[' || *t == '(' || *t == '{')
 #ifdef OBJC_MAX_STRUCT_BY_VALUE
-          && objc_sizeof_type(t) > OBJC_MAX_STRUCT_BY_VALUE
+          && objc_sizeof_type (t) > OBJC_MAX_STRUCT_BY_VALUE
 #endif
           )
         return (IMP)__objc_block_forward;
@@ -107,30 +130,59 @@ __objc_get_forward_imp (SEL sel)
 }
 
 /* Given a class and selector, return the selector's implementation.  */
-__inline__
+inline
 IMP
 get_imp (Class class, SEL sel)
 {
-  void* res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
+  /* In a vanilla implementation we would first check if the dispatch
+     table is installed.  Here instead, to get more speed in the
+     standard case (that the dispatch table is installed) we first try
+     to get the imp using brute force.  Only if that fails, we do what
+     we should have been doing from the very beginning, that is, check
+     if the dispatch table needs to be installed, install it if it's
+     not installed, and retrieve the imp from the table if it's
+     installed.  */
+  void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
   if (res == 0)
     {
       /* Not a valid method */
-      if(class->dtable == __objc_uninstalled_dtable)
+      if (class->dtable == __objc_uninstalled_dtable)
        {
          /* The dispatch table needs to be installed. */
-         objc_mutex_lock(__objc_runtime_mutex);
-         __objc_install_dispatch_table_for_class (class);
-         objc_mutex_unlock(__objc_runtime_mutex);
+         objc_mutex_lock (__objc_runtime_mutex);
+
+          /* Double-checked locking pattern: Check
+             __objc_uninstalled_dtable again in case another thread
+             installed the dtable while we were waiting for the lock
+             to be released.  */
+         if (class->dtable == __objc_uninstalled_dtable)
+           {
+             __objc_install_dispatch_table_for_class (class);
+           }
+
+         objc_mutex_unlock (__objc_runtime_mutex);
          /* Call ourselves with the installed dispatch table
             and get the real method */
-         res = get_imp(class, sel);
+         res = get_imp (class, sel);
        }
       else
        {
-         /* The dispatch table has been installed so the
-            method just doesn't exist for the class.
-            Return the forwarding implementation. */
-         res = __objc_get_forward_imp(sel);
+         /* The dispatch table has been installed.  */
+
+         /* Get the method from the dispatch table (we try to get it
+           again in case another thread has installed the dtable just
+           after we invoked sarray_get_safe, but before we checked
+           class->dtable == __objc_uninstalled_dtable).
+         */
+         res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
+         if (res == 0)
+           {
+             /* The dispatch table has been installed, and the method
+                is not in the dispatch table.  So the method just
+                doesn't exist for the class.  Return the forwarding
+                implementation. */
+             res = __objc_get_forward_imp ((id)class, sel);
+           }
        }
     }
   return res;
@@ -139,18 +191,21 @@ get_imp (Class class, SEL sel)
 /* Query if an object can respond to a selector, returns YES if the
 object implements the selector otherwise NO.  Does not check if the
 method can be forwarded. */
-__inline__
+inline
 BOOL
 __objc_responds_to (id object, SEL sel)
 {
-  voidres;
+  void *res;
 
   /* Install dispatch table if need be */
   if (object->class_pointer->dtable == __objc_uninstalled_dtable)
     {
-      objc_mutex_lock(__objc_runtime_mutex);
-      __objc_install_dispatch_table_for_class (object->class_pointer);
-      objc_mutex_unlock(__objc_runtime_mutex);
+      objc_mutex_lock (__objc_runtime_mutex);
+      if (object->class_pointer->dtable == __objc_uninstalled_dtable)
+       {
+         __objc_install_dispatch_table_for_class (object->class_pointer);
+       }
+      objc_mutex_unlock (__objc_runtime_mutex);
     }
 
   /* Get the method from the dispatch table */
@@ -161,39 +216,48 @@ __objc_responds_to (id object, SEL sel)
 /* This is the lookup function.  All entries in the table are either a 
    valid method *or* zero.  If zero then either the dispatch table
    needs to be installed or it doesn't exist and forwarding is attempted. */
-__inline__
+inline
 IMP
-objc_msg_lookup(id receiver, SEL op)
+objc_msg_lookup (id receiver, SEL op)
 {
   IMP result;
-  if(receiver)
+  if (receiver)
     {
       result = sarray_get_safe (receiver->class_pointer->dtable, 
                                (sidx)op->sel_id);
       if (result == 0)
        {
          /* Not a valid method */
-         if(receiver->class_pointer->dtable == __objc_uninstalled_dtable)
+         if (receiver->class_pointer->dtable == __objc_uninstalled_dtable)
            {
              /* The dispatch table needs to be installed.
                 This happens on the very first method call to the class. */
-             __objc_init_install_dtable(receiver, op);
+             __objc_init_install_dtable (receiver, op);
 
              /* Get real method for this in newly installed dtable */
-             result = get_imp(receiver->class_pointer, op);
+             result = get_imp (receiver->class_pointer, op);
            }
          else
            {
-             /* The dispatch table has been installed so the
-                method just doesn't exist for the class.
-                Attempt to forward the method. */
-             result = __objc_get_forward_imp(op);
+             /* The dispatch table has been installed.  Check again
+                if the method exists (just in case the dispatch table
+                has been installed by another thread after we did the
+                previous check that the method exists).
+             */
+             result = sarray_get_safe (receiver->class_pointer->dtable,
+                                       (sidx)op->sel_id);
+             if (result == 0)
+               {
+                 /* If the method still just doesn't exist for the
+                    class, attempt to forward the method. */
+                 result = __objc_get_forward_imp (receiver, op);
+               }
            }
        }
       return result;
     }
   else
-    return nil_method;
+    return (IMP)nil_method;
 }
 
 IMP
@@ -202,96 +266,98 @@ objc_msg_lookup_super (Super_t super, SEL sel)
   if (super->self)
     return get_imp (super->class, sel);
   else
-    return nil_method;
+    return (IMP)nil_method;
 }
 
-int method_get_sizeof_arguments (Method*);
+int method_get_sizeof_arguments (Method *);
 
 retval_t
-objc_msg_sendv(id object, SEL op, arglist_t arg_frame)
+objc_msg_sendv (id object, SEL op, arglist_t arg_frame)
 {
-  Method* m = class_get_instance_method(object->class_pointer, op);
+  Method *m = class_get_instance_method (object->class_pointer, op);
   const char *type;
-  *((id*)method_get_first_argument (m, arg_frame, &type)) = object;
-  *((SEL*)method_get_next_argument (arg_frame, &type)) = op;
-  return __builtin_apply((apply_t)m->method_imp, 
-                        arg_frame,
-                        method_get_sizeof_arguments (m));
+  *((id *) method_get_first_argument (m, arg_frame, &type)) = object;
+  *((SEL *) method_get_next_argument (arg_frame, &type)) = op;
+  return __builtin_apply ((apply_t) m->method_imp, 
+                         arg_frame,
+                         method_get_sizeof_arguments (m));
 }
 
 void
-__objc_init_dispatch_tables()
+__objc_init_dispatch_tables ()
 {
-  __objc_uninstalled_dtable
-    = sarray_new(200, 0);
+  __objc_uninstalled_dtable = sarray_new (200, 0);
 }
 
 /* This function is called by objc_msg_lookup when the
    dispatch table needs to be installed; thus it is called once
    for each class, namely when the very first message is sent to it. */
 static void
-__objc_init_install_dtable(id receiver, SEL op)
+__objc_init_install_dtable (id receiver, SEL op __attribute__ ((__unused__)))
 {
+  objc_mutex_lock (__objc_runtime_mutex);
+  
   /* This may happen, if the programmer has taken the address of a 
      method before the dtable was initialized... too bad for him! */
-  if(receiver->class_pointer->dtable != __objc_uninstalled_dtable)
-    return;
-
-  objc_mutex_lock(__objc_runtime_mutex);
-
-  if(CLS_ISCLASS(receiver->class_pointer))
+  if (receiver->class_pointer->dtable != __objc_uninstalled_dtable)
+    {
+      objc_mutex_unlock (__objc_runtime_mutex);
+      return;
+    }
+  
+  if (CLS_ISCLASS (receiver->class_pointer))
     {
       /* receiver is an ordinary object */
-      assert(CLS_ISCLASS(receiver->class_pointer));
+      assert (CLS_ISCLASS (receiver->class_pointer));
 
       /* install instance methods table */
       __objc_install_dispatch_table_for_class (receiver->class_pointer);
 
       /* call +initialize -- this will in turn install the factory 
         dispatch table if not already done :-) */
-      __objc_send_initialize(receiver->class_pointer);
+      __objc_send_initialize (receiver->class_pointer);
     }
   else
     {
       /* receiver is a class object */
-      assert(CLS_ISCLASS((Class)receiver));
-      assert(CLS_ISMETA(receiver->class_pointer));
+      assert (CLS_ISCLASS ((Class)receiver));
+      assert (CLS_ISMETA (receiver->class_pointer));
 
       /* Install real dtable for factory methods */
       __objc_install_dispatch_table_for_class (receiver->class_pointer);
 
-      __objc_send_initialize((Class)receiver);
+      __objc_send_initialize ((Class)receiver);
     }
-  objc_mutex_unlock(__objc_runtime_mutex);
+  objc_mutex_unlock (__objc_runtime_mutex);
 }
 
 /* Install dummy table for class which causes the first message to
    that class (or instances hereof) to be initialized properly */
 void
-__objc_install_premature_dtable(Class class)
+__objc_install_premature_dtable (Class class)
 {
-  assert(__objc_uninstalled_dtable);
+  assert (__objc_uninstalled_dtable);
   class->dtable = __objc_uninstalled_dtable;
 }   
 
 /* Send +initialize to class if not already done */
 static void
-__objc_send_initialize(Class class)
+__objc_send_initialize (Class class)
 {
   /* This *must* be a class object */
-  assert(CLS_ISCLASS(class));
-  assert(!CLS_ISMETA(class));
+  assert (CLS_ISCLASS (class));
+  assert (! CLS_ISMETA (class));
 
-  if (!CLS_ISINITIALIZED(class))
+  if (! CLS_ISINITIALIZED (class))
     {
-      CLS_SETINITIALIZED(class);
-      CLS_SETINITIALIZED(class->class_pointer);
+      CLS_SETINITIALIZED (class);
+      CLS_SETINITIALIZED (class->class_pointer);
 
       /* Create the garbage collector type memory description */
       __objc_generate_gc_type_description (class);
 
-      if(class->super_class)
-       __objc_send_initialize(class->super_class);
+      if (class->super_class)
+       __objc_send_initialize (class->super_class);
 
       {
        SEL          op = sel_register_name ("initialize");
@@ -302,7 +368,7 @@ __objc_send_initialize(Class class)
          int i;
           Method_t method;
 
-          for (i = 0; i< method_list->method_count; i++) {
+          for (i = 0; i < method_list->method_count; i++) {
            method = &(method_list->method_list[i]);
             if (method->method_name
                 && method->method_name->sel_id == op->sel_id) {
@@ -318,7 +384,7 @@ __objc_send_initialize(Class class)
 
        }
        if (imp)
-           (*imp)((id)class, op);
+           (*imp) ((id) class, op);
                
       }
     }
@@ -335,7 +401,7 @@ __objc_install_methods_in_dtable (Class class, MethodList_t method_list)
 {
   int i;
 
-  if (!method_list)
+  if (! method_list)
     return;
 
   if (method_list->method_next)
@@ -358,8 +424,8 @@ __objc_install_dispatch_table_for_class (Class class)
 
   /* If the class has not yet had its class links resolved, we must 
      re-compute all class links */
-  if(!CLS_ISRESOLV(class))
-    __objc_resolve_class_links();
+  if (! CLS_ISRESOLV (class))
+    __objc_resolve_class_links ();
 
   super = class->super_class;
 
@@ -369,9 +435,9 @@ __objc_install_dispatch_table_for_class (Class class)
   /* Allocate dtable if necessary */
   if (super == 0)
     {
-      objc_mutex_lock(__objc_runtime_mutex);
+      objc_mutex_lock (__objc_runtime_mutex);
       class->dtable = sarray_new (__objc_selector_max_index, 0);
-      objc_mutex_unlock(__objc_runtime_mutex);
+      objc_mutex_unlock (__objc_runtime_mutex);
     }
   else
     class->dtable = sarray_lazy_copy (super->dtable);
@@ -389,7 +455,7 @@ __objc_update_dispatch_table_for_class (Class class)
   if (class->dtable == __objc_uninstalled_dtable) 
     return;
 
-  objc_mutex_lock(__objc_runtime_mutex);
+  objc_mutex_lock (__objc_runtime_mutex);
 
   arr = class->dtable;
   __objc_install_premature_dtable (class); /* someone might require it... */
@@ -402,7 +468,7 @@ __objc_update_dispatch_table_for_class (Class class)
     for (next = class->subclass_list; next; next = next->sibling_class)
       __objc_update_dispatch_table_for_class (next);
 
-  objc_mutex_unlock(__objc_runtime_mutex);
+  objc_mutex_unlock (__objc_runtime_mutex);
 }
 
 
@@ -412,28 +478,14 @@ __objc_update_dispatch_table_for_class (Class class)
 
    This one is only called for categories. Class objects have their
    methods installed right away, and their selectors are made into
-   SEL's by the function __objc_register_selectors_from_class. */ 
+   SEL's by the function __objc_register_selectors_from_class. */
 void
 class_add_method_list (Class class, MethodList_t list)
 {
-  int i;
-
   /* Passing of a linked list is not allowed.  Do multiple calls.  */
-  assert (!list->method_next);
+  assert (! list->method_next);
 
-  /* Check for duplicates.  */
-  for (i = 0; i < list->method_count; ++i)
-    {
-      Method_t method = &list->method_list[i];
-
-      if (method->method_name)  /* Sometimes these are NULL */
-       {
-         /* This is where selector names are transmogrified to SEL's */
-         method->method_name = 
-           sel_register_typed_name ((const char*)method->method_name,
-                                    method->method_types);
-       }
-    }
+  __objc_register_selectors_from_list(list);
 
   /* Add the methods to the class's method list.  */
   list->method_next = class->methods;
@@ -444,15 +496,15 @@ class_add_method_list (Class class, MethodList_t list)
 }
 
 Method_t
-class_get_instance_method(Class class, SEL op)
+class_get_instance_method (Class class, SEL op)
 {
-  return search_for_method_in_hierarchy(class, op);
+  return search_for_method_in_hierarchy (class, op);
 }
 
 Method_t
-class_get_class_method(MetaClass class, SEL op)
+class_get_class_method (MetaClass class, SEL op)
 {
-  return search_for_method_in_hierarchy(class, op);
+  return search_for_method_in_hierarchy (class, op);
 }
 
 
@@ -576,13 +628,13 @@ __objc_forward (id object, SEL sel, arglist_t args)
   SEL err_sel;
 
   /* first try if the object understands forward:: */
-  if (!frwd_sel)
-    frwd_sel = sel_get_any_uid("forward::");
+  if (! frwd_sel)
+    frwd_sel = sel_get_any_uid ("forward::");
 
   if (__objc_responds_to (object, frwd_sel))
     {
-      imp = get_imp(object->class_pointer, frwd_sel);
-      return (*imp)(object, frwd_sel, sel, args);
+      imp = get_imp (object->class_pointer, frwd_sel);
+      return (*imp) (object, frwd_sel, sel, args);
     }
 
   /* If the object recognizes the doesNotRecognize: method then we're going
@@ -597,11 +649,11 @@ __objc_forward (id object, SEL sel, arglist_t args)
   /* The object doesn't recognize the method.  Check for responding to
      error:.  If it does then sent it. */
   {
-    char msg[256 + strlen ((const char*)sel_get_name (sel))
-             + strlen ((const char*)object->class_pointer->name)];
+    char msg[256 + strlen ((const char *) sel_get_name (sel))
+             + strlen ((const char *) object->class_pointer->name)];
 
     sprintf (msg, "(%s) %s does not recognize %s",
-            (CLS_ISMETA(object->class_pointer)
+            (CLS_ISMETA (object->class_pointer)
              ? "class"
              : "instance" ),
              object->class_pointer->name, sel_get_name (sel));
@@ -622,40 +674,41 @@ __objc_forward (id object, SEL sel, arglist_t args)
 }
 
 void
-__objc_print_dtable_stats()
+__objc_print_dtable_stats ()
 {
   int total = 0;
 
-  objc_mutex_lock(__objc_runtime_mutex);
+  objc_mutex_lock (__objc_runtime_mutex);
 
 #ifdef OBJC_SPARSE2
-  printf("memory usage: (%s)\n", "2-level sparse arrays");
+  printf ("memory usage: (%s)\n", "2-level sparse arrays");
 #else
-  printf("memory usage: (%s)\n", "3-level sparse arrays");
+  printf ("memory usage: (%s)\n", "3-level sparse arrays");
 #endif
 
-  printf("arrays: %d = %ld bytes\n", narrays, 
-        (long)narrays*sizeof(struct sarray));
-  total += narrays*sizeof(struct sarray);
-  printf("buckets: %d = %ld bytes\n", nbuckets, 
-        (long)nbuckets*sizeof(struct sbucket));
-  total += nbuckets*sizeof(struct sbucket);
-
-  printf("idxtables: %d = %ld bytes\n", idxsize, (long)idxsize*sizeof(void*));
-  total += idxsize*sizeof(void*);
-  printf("-----------------------------------\n");
-  printf("total: %d bytes\n", total);
-  printf("===================================\n");
-
-  objc_mutex_unlock(__objc_runtime_mutex);
+  printf ("arrays: %d = %ld bytes\n", narrays, 
+         (long) (narrays * sizeof (struct sarray)));
+  total += narrays * sizeof (struct sarray);
+  printf ("buckets: %d = %ld bytes\n", nbuckets, 
+         (long) (nbuckets * sizeof (struct sbucket)));
+  total += nbuckets * sizeof (struct sbucket);
+
+  printf ("idxtables: %d = %ld bytes\n",
+         idxsize, (long) (idxsize * sizeof (void *)));
+  total += idxsize * sizeof (void *);
+  printf ("-----------------------------------\n");
+  printf ("total: %d bytes\n", total);
+  printf ("===================================\n");
+
+  objc_mutex_unlock (__objc_runtime_mutex);
 }
 
 /* Returns the uninstalled dispatch table indicator.
  If a class' dispatch table points to __objc_uninstalled_dtable
  then that means it needs its dispatch table to be installed. */
-__inline__
-struct sarray
-objc_get_uninstalled_dtable()
+inline
+struct sarray *
+objc_get_uninstalled_dtable ()
 {
   return __objc_uninstalled_dtable;
 }