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