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