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