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