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