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