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