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