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