Home | History | Annotate | Line # | Download | only in libobjc
sendmsg.c revision 1.1.1.11
      1 /* GNU Objective C Runtime message lookup
      2    Copyright (C) 1993-2022 Free Software Foundation, Inc.
      3    Contributed by Kresten Krab Thorup
      4 
      5 This file is part of GCC.
      6 
      7 GCC is free software; you can redistribute it and/or modify it under the
      8 terms of the GNU General Public License as published by the Free Software
      9 Foundation; either version 3, or (at your option) any later version.
     10 
     11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     13 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
     14 details.
     15 
     16 Under Section 7 of GPL version 3, you are granted additional
     17 permissions described in the GCC Runtime Library Exception, version
     18 3.1, as published by the Free Software Foundation.
     19 
     20 You should have received a copy of the GNU General Public License and
     21 a copy of the GCC Runtime Library Exception along with this program;
     22 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23 <http://www.gnu.org/licenses/>.  */
     24 
     25 /* Uncommented the following line to enable debug logging.  Use this
     26    only while debugging the runtime.  */
     27 /* #define DEBUG 1 */
     28 
     29 /* FIXME: This should be using libffi instead of __builtin_apply
     30    and friends.  */
     31 
     32 #include "objc-private/common.h"
     33 #include "objc-private/error.h"
     34 #include "tconfig.h"
     35 #include "coretypes.h"
     36 #include "objc/runtime.h"
     37 #include "objc/message.h"          /* For objc_msg_lookup(), objc_msg_lookup_super().  */
     38 #include "objc/thr.h"
     39 #include "objc-private/module-abi-8.h"
     40 #include "objc-private/runtime.h"
     41 #include "objc-private/hash.h"
     42 #include "objc-private/sarray.h"
     43 #include "objc-private/selector.h" /* For sel_is_mapped() */
     44 #include "runtime-info.h"
     45 #include <assert.h> /* For assert */
     46 #include <string.h> /* For strlen */
     47 
     48 #define INVISIBLE_STRUCT_RETURN 1
     49 
     50 /* The uninstalled dispatch table.  If a class' dispatch table points
     51    to __objc_uninstalled_dtable then that means it needs its dispatch
     52    table to be installed.  */
     53 struct sarray *__objc_uninstalled_dtable = 0;   /* !T:MUTEX */
     54 
     55 /* Two hooks for method forwarding. If either is set, it is invoked to
     56  * return a function that performs the real forwarding.  If both are
     57  * set, the result of __objc_msg_forward2 will be preferred over that
     58  * of __objc_msg_forward.  If both return NULL or are unset, the
     59  * libgcc based functions (__builtin_apply and friends) are used.  */
     60 IMP (*__objc_msg_forward) (SEL) = NULL;
     61 IMP (*__objc_msg_forward2) (id, SEL) = NULL;
     62 
     63 /* Send +initialize to class.  */
     64 static void __objc_send_initialize (Class);
     65 
     66 /* Forward declare some functions */
     67 static void __objc_install_dtable_for_class (Class cls);
     68 static void __objc_prepare_dtable_for_class (Class cls);
     69 static void __objc_install_prepared_dtable_for_class (Class cls);
     70 
     71 static struct sarray *__objc_prepared_dtable_for_class (Class cls);
     72 static IMP __objc_get_prepared_imp (Class cls,SEL sel);
     73 
     74 
     75 /* Various forwarding functions that are used based upon the
     76    return type for the selector.
     77    __objc_block_forward for structures.
     78    __objc_double_forward for floats/doubles.
     79    __objc_word_forward for pointers or types that fit in registers.  */
     80 static double __objc_double_forward (id, SEL, ...);
     81 static id __objc_word_forward (id, SEL, ...);
     82 typedef struct { id many[8]; } __big;
     83 #if INVISIBLE_STRUCT_RETURN
     84 static __big
     85 #else
     86 static id
     87 #endif
     88 __objc_block_forward (id, SEL, ...);
     89 static struct objc_method * search_for_method_in_hierarchy (Class class, SEL sel);
     90 struct objc_method * search_for_method_in_list (struct objc_method_list * list, SEL op);
     91 id nil_method (id, SEL);
     92 
     93 /* Make sure this inline function is exported regardless of GNU89 or C99
     94    inlining semantics as it is part of the libobjc ABI.  */
     95 extern IMP __objc_get_forward_imp (id, SEL);
     96 
     97 /* Given a selector, return the proper forwarding implementation.  */
     98 inline
     99 IMP
    100 __objc_get_forward_imp (id rcv, SEL sel)
    101 {
    102   /* If a custom forwarding hook was registered, try getting a
    103      forwarding function from it. There are two forward routine hooks,
    104      one that takes the receiver as an argument and one that does
    105      not.  */
    106   if (__objc_msg_forward2)
    107     {
    108       IMP result;
    109       if ((result = __objc_msg_forward2 (rcv, sel)) != NULL)
    110        return result;
    111     }
    112   if (__objc_msg_forward)
    113     {
    114       IMP result;
    115       if ((result = __objc_msg_forward (sel)) != NULL)
    116 	return result;
    117     }
    118 
    119   /* In all other cases, use the default forwarding functions built
    120      using __builtin_apply and friends.  */
    121     {
    122       const char *t = sel->sel_types;
    123 
    124       if (t && (*t == '[' || *t == '(' || *t == '{')
    125 #ifdef OBJC_MAX_STRUCT_BY_VALUE
    126           && objc_sizeof_type (t) > OBJC_MAX_STRUCT_BY_VALUE
    127 #endif
    128           )
    129         return (IMP)__objc_block_forward;
    130       else if (t && (*t == 'f' || *t == 'd'))
    131         return (IMP)__objc_double_forward;
    132       else
    133         return (IMP)__objc_word_forward;
    134     }
    135 }
    136 
    137 /* Selectors for +resolveClassMethod: and +resolveInstanceMethod:.
    138    These are set up at startup.  */
    139 static SEL selector_resolveClassMethod = NULL;
    140 static SEL selector_resolveInstanceMethod = NULL;
    141 
    142 /* Internal routines use to resolve a class method using
    143    +resolveClassMethod:.  'class' is always a non-Nil class (*not* a
    144    meta-class), and 'sel' is the selector that we are trying to
    145    resolve.  This must be called when class is not Nil, and the
    146    dispatch table for class methods has already been installed.
    147 
    148    This routine tries to call +resolveClassMethod: to give an
    149    opportunity to resolve the method.  If +resolveClassMethod: returns
    150    YES, it tries looking up the method again, and if found, it returns
    151    it.  Else, it returns NULL.  */
    152 static inline
    153 IMP
    154 __objc_resolve_class_method (Class class, SEL sel)
    155 {
    156   /* We need to lookup +resolveClassMethod:.  */
    157   BOOL (*resolveMethodIMP) (id, SEL, SEL);
    158 
    159   /* The dispatch table for class methods is already installed and we
    160      don't want any forwarding to happen when looking up this method,
    161      so we just look it up directly.  Note that if 'sel' is precisely
    162      +resolveClassMethod:, this would look it up yet again and find
    163      nothing.  That's no problem and there's no recursion.  */
    164   resolveMethodIMP = (BOOL (*) (id, SEL, SEL))sarray_get_safe
    165     (class->class_pointer->dtable, (size_t) selector_resolveClassMethod->sel_id);
    166 
    167   if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveClassMethod, sel))
    168     {
    169       /* +resolveClassMethod: returned YES.  Look the method up again.
    170 	 We already know the dtable is installed.  */
    171 
    172       /* TODO: There is the case where +resolveClassMethod: is buggy
    173 	 and returned YES without actually adding the method.  We
    174 	 could maybe print an error message.  */
    175       return sarray_get_safe (class->class_pointer->dtable, (size_t) sel->sel_id);
    176     }
    177 
    178   return NULL;
    179 }
    180 
    181 /* Internal routines use to resolve a instance method using
    182    +resolveInstanceMethod:.  'class' is always a non-Nil class, and
    183    'sel' is the selector that we are trying to resolve.  This must be
    184    called when class is not Nil, and the dispatch table for instance
    185    methods has already been installed.
    186 
    187    This routine tries to call +resolveInstanceMethod: to give an
    188    opportunity to resolve the method.  If +resolveInstanceMethod:
    189    returns YES, it tries looking up the method again, and if found, it
    190    returns it.  Else, it returns NULL.  */
    191 static inline
    192 IMP
    193 __objc_resolve_instance_method (Class class, SEL sel)
    194 {
    195   /* We need to lookup +resolveInstanceMethod:.  */
    196   BOOL (*resolveMethodIMP) (id, SEL, SEL);
    197 
    198   /* The dispatch table for class methods may not be already installed
    199      so we have to install it if needed.  */
    200   resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
    201 				      (size_t) selector_resolveInstanceMethod->sel_id);
    202   if (resolveMethodIMP == 0)
    203     {
    204       /* Try again after installing the dtable.  */
    205       if (class->class_pointer->dtable == __objc_uninstalled_dtable)
    206 	{
    207 	  objc_mutex_lock (__objc_runtime_mutex);
    208 	  if (class->class_pointer->dtable == __objc_uninstalled_dtable)
    209 	    __objc_install_dtable_for_class (class->class_pointer);
    210 	  objc_mutex_unlock (__objc_runtime_mutex);
    211 	}
    212       resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
    213 					  (size_t) selector_resolveInstanceMethod->sel_id);
    214     }
    215 
    216   if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveInstanceMethod, sel))
    217     {
    218       /* +resolveInstanceMethod: returned YES.  Look the method up
    219 	 again.  We already know the dtable is installed.  */
    220 
    221       /* TODO: There is the case where +resolveInstanceMethod: is
    222 	 buggy and returned YES without actually adding the method.
    223 	 We could maybe print an error message.  */
    224       return sarray_get_safe (class->dtable, (size_t) sel->sel_id);
    225     }
    226 
    227   return NULL;
    228 }
    229 
    230 /* Given a CLASS and selector, return the implementation corresponding
    231    to the method of the selector.
    232 
    233    If CLASS is a class, the instance method is returned.
    234    If CLASS is a meta class, the class method is returned.
    235 
    236    Since this requires the dispatch table to be installed, this function
    237    will implicitly invoke +initialize for CLASS if it hasn't been
    238    invoked yet.  This also insures that +initialize has been invoked
    239    when the returned implementation is called directly.
    240 
    241    The forwarding hooks require the receiver as an argument (if they are to
    242    perform dynamic lookup in proxy objects etc), so this function has a
    243    receiver argument to be used with those hooks.  */
    244 static inline
    245 IMP
    246 get_implementation (id receiver, Class class, SEL sel)
    247 {
    248   void *res;
    249 
    250   if (class->dtable == __objc_uninstalled_dtable)
    251     {
    252       /* The dispatch table needs to be installed.  */
    253       objc_mutex_lock (__objc_runtime_mutex);
    254 
    255       /* Double-checked locking pattern: Check
    256 	 __objc_uninstalled_dtable again in case another thread
    257 	 installed the dtable while we were waiting for the lock to be
    258 	 released.  */
    259       if (class->dtable == __objc_uninstalled_dtable)
    260 	__objc_install_dtable_for_class (class);
    261 
    262       /* If the dispatch table is not yet installed, we are still in
    263 	 the process of executing +initialize.  But the implementation
    264 	 pointer should be available in the prepared ispatch table if
    265 	 it exists at all.  */
    266       if (class->dtable == __objc_uninstalled_dtable)
    267 	{
    268 	  assert (__objc_prepared_dtable_for_class (class) != 0);
    269 	  res = __objc_get_prepared_imp (class, sel);
    270 	}
    271       else
    272 	res = 0;
    273 
    274       objc_mutex_unlock (__objc_runtime_mutex);
    275       /* Call ourselves with the installed dispatch table and get the
    276 	 real method.  */
    277       if (!res)
    278 	res = get_implementation (receiver, class, sel);
    279     }
    280   else
    281     {
    282       /* The dispatch table has been installed.  */
    283       res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
    284       if (res == 0)
    285 	{
    286 	  /* The dispatch table has been installed, and the method is
    287 	     not in the dispatch table.  So the method just doesn't
    288 	     exist for the class.  */
    289 
    290 	  /* Try going through the +resolveClassMethod: or
    291 	     +resolveInstanceMethod: process.  */
    292 	  if (CLS_ISMETA (class))
    293 	    {
    294 	      /* We have the meta class, but we need to invoke the
    295 		 +resolveClassMethod: method on the class.  So, we
    296 		 need to obtain the class from the meta class, which
    297 		 we do using the fact that both the class and the
    298 		 meta-class have the same name.  */
    299 	      Class realClass = objc_lookUpClass (class->name);
    300 	      if (realClass)
    301 		res = __objc_resolve_class_method (realClass, sel);
    302 	    }
    303 	  else
    304 	    res = __objc_resolve_instance_method (class, sel);
    305 
    306 	  if (res == 0)
    307 	    res = __objc_get_forward_imp (receiver, sel);
    308 	}
    309     }
    310   return res;
    311 }
    312 
    313 /* Make sure this inline function is exported regardless of GNU89 or C99
    314    inlining semantics as it is part of the libobjc ABI.  */
    315 extern IMP get_imp (Class, SEL);
    316 
    317 inline
    318 IMP
    319 get_imp (Class class, SEL sel)
    320 {
    321   /* In a vanilla implementation we would first check if the dispatch
    322      table is installed.  Here instead, to get more speed in the
    323      standard case (that the dispatch table is installed) we first try
    324      to get the imp using brute force.  Only if that fails, we do what
    325      we should have been doing from the very beginning, that is, check
    326      if the dispatch table needs to be installed, install it if it's
    327      not installed, and retrieve the imp from the table if it's
    328      installed.  */
    329   void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
    330   if (res == 0)
    331     {
    332       res = get_implementation(nil, class, sel);
    333     }
    334   return res;
    335 }
    336 
    337 /* The new name of get_imp().  */
    338 IMP
    339 class_getMethodImplementation (Class class_, SEL selector)
    340 {
    341   if (class_ == Nil  ||  selector == NULL)
    342     return NULL;
    343 
    344   /* get_imp is inlined, so we're good.  */
    345   return get_imp (class_, selector);
    346 }
    347 
    348 /* Given a method, return its implementation.  This has been replaced
    349    by method_getImplementation() in the modern API.  */
    350 IMP
    351 method_get_imp (struct objc_method * method)
    352 {
    353   return (method != (struct objc_method *)0) ? method->method_imp : (IMP)0;
    354 }
    355 
    356 /* Query if an object can respond to a selector, returns YES if the
    357    object implements the selector otherwise NO.  Does not check if the
    358    method can be forwarded.  Since this requires the dispatch table to
    359    installed, this function will implicitly invoke +initialize for the
    360    class of OBJECT if it hasn't been invoked yet.  */
    361 inline
    362 BOOL
    363 __objc_responds_to (id object, SEL sel)
    364 {
    365   void *res;
    366   struct sarray *dtable;
    367 
    368   /* Install dispatch table if need be */
    369   dtable = object->class_pointer->dtable;
    370   if (dtable == __objc_uninstalled_dtable)
    371     {
    372       objc_mutex_lock (__objc_runtime_mutex);
    373       if (object->class_pointer->dtable == __objc_uninstalled_dtable)
    374         __objc_install_dtable_for_class (object->class_pointer);
    375 
    376       /* If the dispatch table is not yet installed, we are still in
    377          the process of executing +initialize.  Yet the dispatch table
    378          should be available.  */
    379       if (object->class_pointer->dtable == __objc_uninstalled_dtable)
    380         {
    381           dtable = __objc_prepared_dtable_for_class (object->class_pointer);
    382           assert (dtable);
    383         }
    384       else
    385         dtable = object->class_pointer->dtable;
    386 
    387       objc_mutex_unlock (__objc_runtime_mutex);
    388     }
    389 
    390   /* Get the method from the dispatch table.  */
    391   res = sarray_get_safe (dtable, (size_t) sel->sel_id);
    392   return (res != 0) ? YES : NO;
    393 }
    394 
    395 BOOL
    396 class_respondsToSelector (Class class_, SEL selector)
    397 {
    398   struct sarray *dtable;
    399   void *res;
    400 
    401   if (class_ == Nil  ||  selector == NULL)
    402     return NO;
    403 
    404   /* Install dispatch table if need be.  */
    405   dtable = class_->dtable;
    406   if (dtable == __objc_uninstalled_dtable)
    407     {
    408       objc_mutex_lock (__objc_runtime_mutex);
    409       if (class_->dtable == __objc_uninstalled_dtable)
    410 	__objc_install_dtable_for_class (class_);
    411 
    412       /* If the dispatch table is not yet installed,
    413          we are still in the process of executing +initialize.
    414          Yet the dispatch table should be available.  */
    415       if (class_->dtable == __objc_uninstalled_dtable)
    416         {
    417           dtable = __objc_prepared_dtable_for_class (class_);
    418           assert (dtable);
    419         }
    420       else
    421         dtable = class_->dtable;
    422 
    423       objc_mutex_unlock (__objc_runtime_mutex);
    424     }
    425 
    426   /* Get the method from the dispatch table.  */
    427   res = sarray_get_safe (dtable, (size_t) selector->sel_id);
    428   return (res != 0) ? YES : NO;
    429 }
    430 
    431 /* This is the lookup function.  All entries in the table are either a
    432    valid method *or* zero.  If zero then either the dispatch table
    433    needs to be installed or it doesn't exist and forwarding is
    434    attempted.  */
    435 IMP
    436 objc_msg_lookup (id receiver, SEL op)
    437 {
    438   IMP result;
    439   if (receiver)
    440     {
    441       /* First try a quick lookup assuming the dispatch table exists.  */
    442       result = sarray_get_safe (receiver->class_pointer->dtable,
    443 				(sidx)op->sel_id);
    444       if (result == 0)
    445 	{
    446 	  /* Not found ... call get_implementation () to install the
    447              dispatch table and call +initialize as required,
    448              providing the method implementation or a forwarding
    449              function.  */
    450 	  result = get_implementation (receiver, receiver->class_pointer, op);
    451 	}
    452       return result;
    453     }
    454   else
    455     return (IMP)nil_method;
    456 }
    457 
    458 IMP
    459 objc_msg_lookup_super (struct objc_super *super, SEL sel)
    460 {
    461   if (super->self)
    462     return get_imp (super->super_class, sel);
    463   else
    464     return (IMP)nil_method;
    465 }
    466 
    467 void
    468 __objc_init_dispatch_tables ()
    469 {
    470   __objc_uninstalled_dtable = sarray_new (200, 0);
    471 
    472   /* TODO: It would be cool to register typed selectors here.  */
    473   selector_resolveClassMethod = sel_registerName ("resolveClassMethod:");
    474   selector_resolveInstanceMethod = sel_registerName ("resolveInstanceMethod:");
    475 }
    476 
    477 
    478 /* Install dummy table for class which causes the first message to
    479    that class (or instances hereof) to be initialized properly.  */
    480 void
    481 __objc_install_premature_dtable (Class class)
    482 {
    483   assert (__objc_uninstalled_dtable);
    484   class->dtable = __objc_uninstalled_dtable;
    485 }
    486 
    487 /* Send +initialize to class if not already done.  */
    488 static void
    489 __objc_send_initialize (Class class)
    490 {
    491   /* This *must* be a class object.  */
    492   assert (CLS_ISCLASS (class));
    493   assert (! CLS_ISMETA (class));
    494 
    495   /* class_add_method_list/__objc_update_dispatch_table_for_class may
    496      have reset the dispatch table.  The canonical way to insure that
    497      we send +initialize just once, is this flag.  */
    498   if (! CLS_ISINITIALIZED (class))
    499     {
    500       DEBUG_PRINTF ("+initialize: need to initialize class '%s'\n", class->name);
    501       CLS_SETINITIALIZED (class);
    502       CLS_SETINITIALIZED (class->class_pointer);
    503 
    504       /* Create the garbage collector type memory description.  */
    505       __objc_generate_gc_type_description (class);
    506 
    507       if (class->super_class)
    508 	__objc_send_initialize (class->super_class);
    509 
    510       {
    511 	SEL op = sel_registerName ("initialize");
    512         struct objc_method *method = search_for_method_in_hierarchy (class->class_pointer,
    513 								     op);
    514 
    515 	if (method)
    516 	  {
    517 	    DEBUG_PRINTF (" begin of [%s +initialize]\n", class->name);
    518 	    (*method->method_imp) ((id)class, op);
    519 	    DEBUG_PRINTF (" end of [%s +initialize]\n", class->name);
    520 	  }
    521 #ifdef DEBUG
    522 	else
    523 	  {
    524 	    DEBUG_PRINTF (" class '%s' has no +initialize method\n", class->name);
    525 	  }
    526 #endif
    527       }
    528     }
    529 }
    530 
    531 /* Walk on the methods list of class and install the methods in the
    532    reverse order of the lists.  Since methods added by categories are
    533    before the methods of class in the methods list, this allows
    534    categories to substitute methods declared in class.  However if
    535    more than one category replaces the same method nothing is
    536    guaranteed about what method will be used.  Assumes that
    537    __objc_runtime_mutex is locked down.  */
    538 static void
    539 __objc_install_methods_in_dtable (struct sarray *dtable, struct objc_method_list * method_list)
    540 {
    541   int i;
    542 
    543   if (! method_list)
    544     return;
    545 
    546   if (method_list->method_next)
    547     __objc_install_methods_in_dtable (dtable, method_list->method_next);
    548 
    549   for (i = 0; i < method_list->method_count; i++)
    550     {
    551       struct objc_method * method = &(method_list->method_list[i]);
    552       sarray_at_put_safe (dtable,
    553 			  (sidx) method->method_name->sel_id,
    554 			  method->method_imp);
    555     }
    556 }
    557 
    558 void
    559 __objc_update_dispatch_table_for_class (Class class)
    560 {
    561   Class next;
    562   struct sarray *arr;
    563 
    564   DEBUG_PRINTF (" _objc_update_dtable_for_class (%s)\n", class->name);
    565 
    566   objc_mutex_lock (__objc_runtime_mutex);
    567 
    568   /* Not yet installed -- skip it unless in +initialize.  */
    569   if (class->dtable == __objc_uninstalled_dtable)
    570     {
    571       if (__objc_prepared_dtable_for_class (class))
    572 	{
    573 	  /* There is a prepared table so we must be initialising this
    574 	     class ... we must re-do the table preparation.  */
    575 	  __objc_prepare_dtable_for_class (class);
    576 	}
    577       objc_mutex_unlock (__objc_runtime_mutex);
    578       return;
    579     }
    580 
    581   arr = class->dtable;
    582   __objc_install_premature_dtable (class); /* someone might require it... */
    583   sarray_free (arr);			   /* release memory */
    584 
    585   /* Could have been lazy...  */
    586   __objc_install_dtable_for_class (class);
    587 
    588   if (class->subclass_list)	/* Traverse subclasses.  */
    589     for (next = class->subclass_list; next; next = next->sibling_class)
    590       __objc_update_dispatch_table_for_class (next);
    591 
    592   objc_mutex_unlock (__objc_runtime_mutex);
    593 }
    594 
    595 /* This function adds a method list to a class.  This function is
    596    typically called by another function specific to the run-time.  As
    597    such this function does not worry about thread safe issues.
    598 
    599    This one is only called for categories. Class objects have their
    600    methods installed right away, and their selectors are made into
    601    SEL's by the function __objc_register_selectors_from_class.  */
    602 void
    603 class_add_method_list (Class class, struct objc_method_list * list)
    604 {
    605   /* Passing of a linked list is not allowed.  Do multiple calls.  */
    606   assert (! list->method_next);
    607 
    608   __objc_register_selectors_from_list(list);
    609 
    610   /* Add the methods to the class's method list.  */
    611   list->method_next = class->methods;
    612   class->methods = list;
    613 
    614   /* Update the dispatch table of class.  */
    615   __objc_update_dispatch_table_for_class (class);
    616 }
    617 
    618 struct objc_method *
    619 class_getInstanceMethod (Class class_, SEL selector)
    620 {
    621   struct objc_method *m;
    622 
    623   if (class_ == Nil  ||  selector == NULL)
    624     return NULL;
    625 
    626   m = search_for_method_in_hierarchy (class_, selector);
    627   if (m)
    628     return m;
    629 
    630   /* Try going through +resolveInstanceMethod:, and do the search
    631      again if successful.  */
    632   if (__objc_resolve_instance_method (class_, selector))
    633     return search_for_method_in_hierarchy (class_, selector);
    634 
    635   return NULL;
    636 }
    637 
    638 struct objc_method *
    639 class_getClassMethod (Class class_, SEL selector)
    640 {
    641   struct objc_method *m;
    642 
    643   if (class_ == Nil  ||  selector == NULL)
    644     return NULL;
    645 
    646   m = search_for_method_in_hierarchy (class_->class_pointer,
    647 				      selector);
    648   if (m)
    649     return m;
    650 
    651   /* Try going through +resolveClassMethod:, and do the search again
    652      if successful.  */
    653   if (__objc_resolve_class_method (class_, selector))
    654     return search_for_method_in_hierarchy (class_->class_pointer,
    655 					   selector);
    656 
    657   return NULL;
    658 }
    659 
    660 BOOL
    661 class_addMethod (Class class_, SEL selector, IMP implementation,
    662 		 const char *method_types)
    663 {
    664   struct objc_method_list *method_list;
    665   struct objc_method *method;
    666   const char *method_name;
    667 
    668   if (class_ == Nil  ||  selector == NULL  ||  implementation == NULL
    669       || method_types == NULL  || (strcmp (method_types, "") == 0))
    670     return NO;
    671 
    672   method_name = sel_getName (selector);
    673   if (method_name == NULL)
    674     return NO;
    675 
    676   /* If the method already exists in the class, return NO.  It is fine
    677      if the method already exists in the superclass; in that case, we
    678      are overriding it.  */
    679   if (CLS_IS_IN_CONSTRUCTION (class_))
    680     {
    681       /* The class only contains a list of methods; they have not been
    682 	 registered yet, ie, the method_name of each of them is still
    683 	 a string, not a selector.  Iterate manually over them to
    684 	 check if we have already added the method.  */
    685       struct objc_method_list * method_list = class_->methods;
    686       while (method_list)
    687 	{
    688 	  int i;
    689 
    690 	  /* Search the method list.  */
    691 	  for (i = 0; i < method_list->method_count; ++i)
    692 	    {
    693 	      struct objc_method * method = &method_list->method_list[i];
    694 
    695 	      if (method->method_name
    696 		  && strcmp ((char *)method->method_name, method_name) == 0)
    697 		return NO;
    698 	    }
    699 
    700 	  /* The method wasn't found.  Follow the link to the next list of
    701 	     methods.  */
    702 	  method_list = method_list->method_next;
    703 	}
    704       /* The method wasn't found.  It's a new one.  Go ahead and add
    705 	 it.  */
    706     }
    707   else
    708     {
    709       /* Do the standard lookup.  This assumes the selectors are
    710 	 mapped.  */
    711       if (search_for_method_in_list (class_->methods, selector))
    712 	return NO;
    713     }
    714 
    715   method_list = (struct objc_method_list *)objc_calloc (1, sizeof (struct objc_method_list));
    716   method_list->method_count = 1;
    717 
    718   method = &(method_list->method_list[0]);
    719   method->method_name = objc_malloc (strlen (method_name) + 1);
    720   strcpy ((char *)method->method_name, method_name);
    721 
    722   method->method_types = objc_malloc (strlen (method_types) + 1);
    723   strcpy ((char *)method->method_types, method_types);
    724 
    725   method->method_imp = implementation;
    726 
    727   if (CLS_IS_IN_CONSTRUCTION (class_))
    728     {
    729       /* We only need to add the method to the list.  It will be
    730 	 registered with the runtime when the class pair is registered
    731 	 (if ever).  */
    732       method_list->method_next = class_->methods;
    733       class_->methods = method_list;
    734     }
    735   else
    736     {
    737       /* Add the method to a live class.  */
    738       objc_mutex_lock (__objc_runtime_mutex);
    739       class_add_method_list (class_, method_list);
    740       objc_mutex_unlock (__objc_runtime_mutex);
    741     }
    742 
    743   return YES;
    744 }
    745 
    746 IMP
    747 class_replaceMethod (Class class_, SEL selector, IMP implementation,
    748 		     const char *method_types)
    749 {
    750   struct objc_method * method;
    751 
    752   if (class_ == Nil  ||  selector == NULL  ||  implementation == NULL
    753       || method_types == NULL)
    754     return NULL;
    755 
    756   method = search_for_method_in_hierarchy (class_, selector);
    757 
    758   if (method)
    759     {
    760       return method_setImplementation (method, implementation);
    761     }
    762   else
    763     {
    764       class_addMethod (class_, selector, implementation, method_types);
    765       return NULL;
    766     }
    767 }
    768 
    769 /* Search for a method starting from the current class up its
    770    hierarchy.  Return a pointer to the method's method structure if
    771    found.  NULL otherwise.  */
    772 static struct objc_method *
    773 search_for_method_in_hierarchy (Class cls, SEL sel)
    774 {
    775   struct objc_method * method = NULL;
    776   Class class;
    777 
    778   if (! sel_is_mapped (sel))
    779     return NULL;
    780 
    781   /* Scan the method list of the class.  If the method isn't found in
    782      the list then step to its super class.  */
    783   for (class = cls; ((! method) && class); class = class->super_class)
    784     method = search_for_method_in_list (class->methods, sel);
    785 
    786   return method;
    787 }
    788 
    789 
    790 
    791 /* Given a linked list of method and a method's name.  Search for the
    792    named method's method structure.  Return a pointer to the method's
    793    method structure if found.  NULL otherwise.  */
    794 struct objc_method *
    795 search_for_method_in_list (struct objc_method_list * list, SEL op)
    796 {
    797   struct objc_method_list * method_list = list;
    798 
    799   if (! sel_is_mapped (op))
    800     return NULL;
    801 
    802   /* If not found then we'll search the list.  */
    803   while (method_list)
    804     {
    805       int i;
    806 
    807       /* Search the method list.  */
    808       for (i = 0; i < method_list->method_count; ++i)
    809         {
    810           struct objc_method * method = &method_list->method_list[i];
    811 
    812           if (method->method_name)
    813             if (method->method_name->sel_id == op->sel_id)
    814               return method;
    815         }
    816 
    817       /* The method wasn't found.  Follow the link to the next list of
    818          methods.  */
    819       method_list = method_list->method_next;
    820     }
    821 
    822   return NULL;
    823 }
    824 
    825 typedef void * retval_t;
    826 typedef void * arglist_t;
    827 
    828 static retval_t __objc_forward (id object, SEL sel, arglist_t args);
    829 
    830 /* Forwarding pointers/integers through the normal registers.  */
    831 static id
    832 __objc_word_forward (id rcv, SEL op, ...)
    833 {
    834   void *args, *res;
    835 
    836   args = __builtin_apply_args ();
    837   res = __objc_forward (rcv, op, args);
    838   if (res)
    839     __builtin_return (res);
    840   else
    841     return res;
    842 }
    843 
    844 /* Specific routine for forwarding floats/double because of
    845    architectural differences on some processors.  i386s for example
    846    which uses a floating point stack versus general registers for
    847    floating point numbers.  This forward routine makes sure that GCC
    848    restores the proper return values.  */
    849 static double
    850 __objc_double_forward (id rcv, SEL op, ...)
    851 {
    852   void *args, *res;
    853 
    854   args = __builtin_apply_args ();
    855   res = __objc_forward (rcv, op, args);
    856   __builtin_return (res);
    857 }
    858 
    859 #if INVISIBLE_STRUCT_RETURN
    860 static __big
    861 #else
    862 static id
    863 #endif
    864 __objc_block_forward (id rcv, SEL op, ...)
    865 {
    866   void *args, *res;
    867 
    868   args = __builtin_apply_args ();
    869   res = __objc_forward (rcv, op, args);
    870   if (res)
    871     __builtin_return (res);
    872   else
    873 #if INVISIBLE_STRUCT_RETURN
    874     return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
    875 #else
    876     return nil;
    877 #endif
    878 }
    879 
    880 
    881 /* This function is called for methods which are not implemented,
    882    unless a custom forwarding routine has been installed.  Please note
    883    that most serious users of libobjc (eg, GNUstep base) do install
    884    their own forwarding routines, and hence this is never actually
    885    used.  But, if no custom forwarding routine is installed, this is
    886    called when a selector is not recognized.  */
    887 static retval_t
    888 __objc_forward (id object, SEL sel, arglist_t args)
    889 {
    890   IMP imp;
    891   static SEL frwd_sel = 0;                      /* !T:SAFE2 */
    892   SEL err_sel;
    893 
    894   /* First try if the object understands forward::.  */
    895   if (! frwd_sel)
    896     frwd_sel = sel_get_any_uid ("forward::");
    897 
    898   if (__objc_responds_to (object, frwd_sel))
    899     {
    900       imp = get_implementation (object, object->class_pointer, frwd_sel);
    901       return (*imp) (object, frwd_sel, sel, args);
    902     }
    903 
    904   /* If the object recognizes the doesNotRecognize: method then we're
    905      going to send it.  */
    906   err_sel = sel_get_any_uid ("doesNotRecognize:");
    907   if (__objc_responds_to (object, err_sel))
    908     {
    909       imp = get_implementation (object, object->class_pointer, err_sel);
    910       return (*imp) (object, err_sel, sel);
    911     }
    912 
    913   /* The object doesn't recognize the method.  Check for responding to
    914      error:.  If it does then sent it.  */
    915   {
    916     char msg[256 + strlen ((const char *) sel_getName (sel))
    917              + strlen ((const char *) object->class_pointer->name)];
    918 
    919     sprintf (msg, "(%s) %s does not recognize %s",
    920 	     (CLS_ISMETA (object->class_pointer)
    921 	      ? "class"
    922 	      : "instance" ),
    923              object->class_pointer->name, sel_getName (sel));
    924 
    925     /* The object doesn't respond to doesNotRecognize:.  Therefore, a
    926        default action is taken.  */
    927     _objc_abort ("%s\n", msg);
    928 
    929     return 0;
    930   }
    931 }
    932 
    933 void
    934 __objc_print_dtable_stats (void)
    935 {
    936   int total = 0;
    937 
    938   objc_mutex_lock (__objc_runtime_mutex);
    939 
    940 #ifdef OBJC_SPARSE2
    941   printf ("memory usage: (%s)\n", "2-level sparse arrays");
    942 #else
    943   printf ("memory usage: (%s)\n", "3-level sparse arrays");
    944 #endif
    945 
    946   printf ("arrays: %d = %ld bytes\n", narrays,
    947 	  (long) ((size_t) narrays * sizeof (struct sarray)));
    948   total += narrays * sizeof (struct sarray);
    949   printf ("buckets: %d = %ld bytes\n", nbuckets,
    950 	  (long) ((size_t) nbuckets * sizeof (struct sbucket)));
    951   total += nbuckets * sizeof (struct sbucket);
    952 
    953   printf ("idxtables: %d = %ld bytes\n",
    954 	  idxsize, (long) ((size_t) idxsize * sizeof (void *)));
    955   total += idxsize * sizeof (void *);
    956   printf ("-----------------------------------\n");
    957   printf ("total: %d bytes\n", total);
    958   printf ("===================================\n");
    959 
    960   objc_mutex_unlock (__objc_runtime_mutex);
    961 }
    962 
    963 static cache_ptr prepared_dtable_table = 0;
    964 
    965 /* This function is called by: objc_msg_lookup, get_imp and
    966    __objc_responds_to (and the dispatch table installation functions
    967    themselves) to install a dispatch table for a class.
    968 
    969    If CLS is a class, it installs instance methods.
    970    If CLS is a meta class, it installs class methods.
    971 
    972    In either case +initialize is invoked for the corresponding class.
    973 
    974    The implementation must insure that the dispatch table is not
    975    installed until +initialize completes.  Otherwise it opens a
    976    potential race since the installation of the dispatch table is used
    977    as gate in regular method dispatch and we need to guarantee that
    978    +initialize is the first method invoked an that no other thread my
    979    dispatch messages to the class before +initialize completes.  */
    980 static void
    981 __objc_install_dtable_for_class (Class cls)
    982 {
    983   /* If the class has not yet had its class links resolved, we must
    984      re-compute all class links.  */
    985   if (! CLS_ISRESOLV (cls))
    986     __objc_resolve_class_links ();
    987 
    988   /* Make sure the super class has its dispatch table installed or is
    989      at least preparing.  We do not need to send initialize for the
    990      super class since __objc_send_initialize will insure that.  */
    991   if (cls->super_class
    992       && cls->super_class->dtable == __objc_uninstalled_dtable
    993       && !__objc_prepared_dtable_for_class (cls->super_class))
    994     {
    995       __objc_install_dtable_for_class (cls->super_class);
    996       /* The superclass initialisation may have also initialised the
    997          current class, in which case there is no more to do.  */
    998       if (cls->dtable != __objc_uninstalled_dtable)
    999 	return;
   1000     }
   1001 
   1002   /* We have already been prepared but +initialize hasn't completed.
   1003      The +initialize implementation is probably sending 'self'
   1004      messages.  We rely on _objc_get_prepared_imp to retrieve the
   1005      implementation pointers.  */
   1006   if (__objc_prepared_dtable_for_class (cls))
   1007     return;
   1008 
   1009   /* We have this function cache the implementation pointers for
   1010      _objc_get_prepared_imp but the dispatch table won't be initilized
   1011      until __objc_send_initialize completes.  */
   1012   __objc_prepare_dtable_for_class (cls);
   1013 
   1014   /* We may have already invoked +initialize but
   1015      __objc_update_dispatch_table_for_class invoked by
   1016      class_add_method_list may have reset dispatch table.  */
   1017 
   1018   /* Call +initialize.  If we are a real class, we are installing
   1019      instance methods.  If we are a meta class, we are installing
   1020      class methods.  The __objc_send_initialize itself will insure
   1021      that the message is called only once per class.  */
   1022   if (CLS_ISCLASS (cls))
   1023     __objc_send_initialize (cls);
   1024   else
   1025     {
   1026       /* Retrieve the class from the meta class.  */
   1027       Class c = objc_getClass (cls->name);
   1028       assert (CLS_ISMETA (cls));
   1029       assert (c);
   1030       __objc_send_initialize (c);
   1031     }
   1032 
   1033   /* We install the dispatch table correctly when +initialize completed.  */
   1034   __objc_install_prepared_dtable_for_class (cls);
   1035 }
   1036 
   1037 /* Builds the dispatch table for the class CLS and stores it in a
   1038    place where it can be retrieved by __objc_get_prepared_imp until
   1039    __objc_install_prepared_dtable_for_class installs it into the
   1040    class.  The dispatch table should not be installed into the class
   1041    until +initialize has completed.  */
   1042 static void
   1043 __objc_prepare_dtable_for_class (Class cls)
   1044 {
   1045   struct sarray *dtable;
   1046   struct sarray *super_dtable;
   1047 
   1048   /* This table could be initialized in init.c.  We cannot use the
   1049      class name since the class maintains the instance methods and the
   1050      meta class maintains the the class methods yet both share the
   1051      same name.  Classes should be unique in any program.  */
   1052   if (! prepared_dtable_table)
   1053     prepared_dtable_table
   1054       = objc_hash_new (32,
   1055 		       (hash_func_type) objc_hash_ptr,
   1056 		       (compare_func_type) objc_compare_ptrs);
   1057 
   1058   /* If the class has not yet had its class links resolved, we must
   1059      re-compute all class links.  */
   1060   if (! CLS_ISRESOLV (cls))
   1061     __objc_resolve_class_links ();
   1062 
   1063   assert (cls);
   1064   assert (cls->dtable == __objc_uninstalled_dtable);
   1065 
   1066   /* If there is already a prepared dtable for this class, we must
   1067      replace it with a new version (since there must have been methods
   1068      added to or otherwise modified in the class while executing
   1069      +initialize, and the table needs to be recomputed.  */
   1070   dtable = __objc_prepared_dtable_for_class (cls);
   1071   if (dtable != 0)
   1072     {
   1073       objc_hash_remove (prepared_dtable_table, cls);
   1074       sarray_free (dtable);
   1075     }
   1076 
   1077   /* Now prepare the dtable for population.  */
   1078   assert (cls != cls->super_class);
   1079   if (cls->super_class)
   1080     {
   1081       /* Inherit the method list from the super class.  Yet the super
   1082          class may still be initializing in the case when a class
   1083          cluster sub class initializes its super classes.  */
   1084       if (cls->super_class->dtable == __objc_uninstalled_dtable)
   1085 	__objc_install_dtable_for_class (cls->super_class);
   1086 
   1087       super_dtable = cls->super_class->dtable;
   1088       /* If the dispatch table is not yet installed, we are still in
   1089 	 the process of executing +initialize.  Yet the dispatch table
   1090 	 should be available.  */
   1091       if (super_dtable == __objc_uninstalled_dtable)
   1092 	super_dtable = __objc_prepared_dtable_for_class (cls->super_class);
   1093 
   1094       assert (super_dtable);
   1095       dtable = sarray_lazy_copy (super_dtable);
   1096     }
   1097   else
   1098     dtable = sarray_new (__objc_selector_max_index, 0);
   1099 
   1100   __objc_install_methods_in_dtable (dtable, cls->methods);
   1101 
   1102   objc_hash_add (&prepared_dtable_table,
   1103 		 cls,
   1104 		 dtable);
   1105 }
   1106 
   1107 /* This wrapper only exists to allow an easy replacement of the lookup
   1108    implementation and it is expected that the compiler will optimize
   1109    it away.  */
   1110 static struct sarray *
   1111 __objc_prepared_dtable_for_class (Class cls)
   1112 {
   1113   struct sarray *dtable = 0;
   1114   assert (cls);
   1115   if (prepared_dtable_table)
   1116     dtable = objc_hash_value_for_key (prepared_dtable_table, cls);
   1117   /* dtable my be nil, since we call this to check whether we are
   1118      currently preparing before we start preparing.  */
   1119   return dtable;
   1120 }
   1121 
   1122 /* Helper function for messages sent to CLS or implementation pointers
   1123    retrieved from CLS during +initialize before the dtable is
   1124    installed.  When a class implicitly initializes another class which
   1125    in turn implicitly invokes methods in this class, before the
   1126    implementation of +initialize of CLS completes, this returns the
   1127    expected implementation.  Forwarding remains the responsibility of
   1128    objc_msg_lookup.  This function should only be called under the
   1129    global lock.  */
   1130 static IMP
   1131 __objc_get_prepared_imp (Class cls,SEL sel)
   1132 {
   1133   struct sarray *dtable;
   1134   IMP imp;
   1135 
   1136   assert (cls);
   1137   assert (sel);
   1138   assert (cls->dtable == __objc_uninstalled_dtable);
   1139   dtable = __objc_prepared_dtable_for_class (cls);
   1140 
   1141   assert (dtable);
   1142   assert (dtable != __objc_uninstalled_dtable);
   1143   imp = sarray_get_safe (dtable, (size_t) sel->sel_id);
   1144 
   1145   /* imp may be Nil if the method does not exist and we may fallback
   1146      to the forwarding implementation later.  */
   1147   return imp;
   1148 }
   1149 
   1150 /* When this function is called +initialize should be completed.  So
   1151    now we are safe to install the dispatch table for the class so that
   1152    they become available for other threads that may be waiting in the
   1153    lock.  */
   1154 static void
   1155 __objc_install_prepared_dtable_for_class (Class cls)
   1156 {
   1157   assert (cls);
   1158   assert (cls->dtable == __objc_uninstalled_dtable);
   1159   cls->dtable = __objc_prepared_dtable_for_class (cls);
   1160 
   1161   assert (cls->dtable);
   1162   assert (cls->dtable != __objc_uninstalled_dtable);
   1163   objc_hash_remove (prepared_dtable_table, cls);
   1164 }
   1165