]> git.ipfire.org Git - thirdparty/gcc.git/blame - libobjc/sendmsg.c
In libobjc/:
[thirdparty/gcc.git] / libobjc / sendmsg.c
CommitLineData
88e17b57 1/* GNU Objective C Runtime message lookup
0fc39d8a 2 Copyright (C) 1993, 1995, 1996, 1997, 1998,
748086b7 3 2001, 2002, 2004, 2009 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
88e17b57 26
4977bab6 27/* FIXME: This file has no business including tm.h. */
435317e2
AP
28/* FIXME: This should be using libffi instead of __builtin_apply
29 and friends. */
4977bab6 30
6dead247 31#include "objc-private/common.h"
7b869986 32#include "objc-private/error.h"
bce1b489 33#include "tconfig.h"
4977bab6
ZW
34#include "coretypes.h"
35#include "tm.h"
a19fac96
NP
36#include "objc/objc.h"
37#include "objc/objc-api.h"
38#include "objc/thr.h"
a19fac96 39#include "objc-private/runtime.h"
348a3445
DA
40#include "objc/sarray.h"
41#include "objc/encoding.h"
88e17b57 42#include "runtime-info.h"
5be9cdc1 43#include <string.h> /* For strlen */
88e17b57 44
435317e2 45/* This is how we hack STRUCT_VALUE to be 1 or 0. */
88e17b57
BE
46#define gen_rtx(args...) 1
47#define gen_rtx_MEM(args...) 1
68b61df9 48#define gen_rtx_REG(args...) 1
c24aadf3
KT
49/* Alread defined in gcc/coretypes.h. So prevent double definition warning. */
50#undef rtx
88e17b57
BE
51#define rtx int
52
40165636 53#if ! defined (STRUCT_VALUE) || STRUCT_VALUE == 0
88e17b57
BE
54#define INVISIBLE_STRUCT_RETURN 1
55#else
56#define INVISIBLE_STRUCT_RETURN 0
57#endif
58
59/* The uninstalled dispatch table */
40165636 60struct sarray *__objc_uninstalled_dtable = 0; /* !T:MUTEX */
88e17b57 61
80ae8e8a
AR
62/* Two hooks for method forwarding. If either is set, it is invoked
63 * to return a function that performs the real forwarding. If both
64 * are set, the result of __objc_msg_forward2 will be preferred over
65 * that of __objc_msg_forward. If both return NULL or are unset,
66 * the libgcc based functions (__builtin_apply and friends) are
67 * used.
68 */
40165636 69IMP (*__objc_msg_forward) (SEL) = NULL;
80ae8e8a 70IMP (*__objc_msg_forward2) (id, SEL) = NULL;
68b61df9 71
88e17b57 72/* Send +initialize to class */
40165636 73static void __objc_send_initialize (Class);
88e17b57
BE
74
75static void __objc_install_dispatch_table_for_class (Class);
76
77/* Forward declare some functions */
40165636 78static void __objc_init_install_dtable (id, SEL);
88e17b57
BE
79
80/* Various forwarding functions that are used based upon the
81 return type for the selector.
82 __objc_block_forward for structures.
83 __objc_double_forward for floats/doubles.
80ae8e8a 84 __objc_word_forward for pointers or types that fit in registers. */
40165636
RB
85static double __objc_double_forward (id, SEL, ...);
86static id __objc_word_forward (id, SEL, ...);
88e17b57
BE
87typedef struct { id many[8]; } __big;
88#if INVISIBLE_STRUCT_RETURN
89static __big
90#else
91static id
92#endif
40165636 93__objc_block_forward (id, SEL, ...);
88e17b57 94static Method_t search_for_method_in_hierarchy (Class class, SEL sel);
40165636 95Method_t search_for_method_in_list (MethodList_t list, SEL op);
faaa30fe 96id nil_method (id, SEL);
40165636
RB
97
98/* Given a selector, return the proper forwarding implementation. */
435317e2 99inline
40165636 100IMP
80ae8e8a 101__objc_get_forward_imp (id rcv, SEL sel)
40165636 102{
bd8d449d 103 /* If a custom forwarding hook was registered, try getting a forwarding
80ae8e8a
AR
104 function from it. There are two forward routine hooks, one that
105 takes the receiver as an argument and one that does 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)
40165636
RB
116 return result;
117 }
bd8d449d
NP
118
119 /* In all other cases, use the default forwarding functions built using
80ae8e8a 120 __builtin_apply and friends. */
40165636
RB
121 {
122 const char *t = sel->sel_types;
123
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
BE
136
137/* Given a class and selector, return the selector's implementation. */
435317e2 138inline
88e17b57
BE
139IMP
140get_imp (Class class, SEL sel)
141{
c19f8e35
NP
142 /* In a vanilla implementation we would first check if the dispatch
143 table is installed. Here instead, to get more speed in the
144 standard case (that the dispatch table is installed) we first try
145 to get the imp using brute force. Only if that fails, we do what
146 we should have been doing from the very beginning, that is, check
147 if the dispatch table needs to be installed, install it if it's
148 not installed, and retrieve the imp from the table if it's
149 installed. */
40165636 150 void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
88e17b57
BE
151 if (res == 0)
152 {
153 /* Not a valid method */
40165636 154 if (class->dtable == __objc_uninstalled_dtable)
88e17b57
BE
155 {
156 /* The dispatch table needs to be installed. */
40165636 157 objc_mutex_lock (__objc_runtime_mutex);
c19f8e35
NP
158
159 /* Double-checked locking pattern: Check
160 __objc_uninstalled_dtable again in case another thread
161 installed the dtable while we were waiting for the lock
162 to be released. */
163 if (class->dtable == __objc_uninstalled_dtable)
164 {
165 __objc_install_dispatch_table_for_class (class);
166 }
167
40165636 168 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
169 /* Call ourselves with the installed dispatch table
170 and get the real method */
40165636 171 res = get_imp (class, sel);
88e17b57
BE
172 }
173 else
174 {
c19f8e35
NP
175 /* The dispatch table has been installed. */
176
177 /* Get the method from the dispatch table (we try to get it
178 again in case another thread has installed the dtable just
179 after we invoked sarray_get_safe, but before we checked
180 class->dtable == __objc_uninstalled_dtable).
181 */
182 res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
183 if (res == 0)
184 {
185 /* The dispatch table has been installed, and the method
186 is not in the dispatch table. So the method just
187 doesn't exist for the class. Return the forwarding
188 implementation. */
80ae8e8a 189 res = __objc_get_forward_imp ((id)class, sel);
c19f8e35 190 }
88e17b57
BE
191 }
192 }
193 return res;
194}
195
196/* Query if an object can respond to a selector, returns YES if the
197object implements the selector otherwise NO. Does not check if the
198method can be forwarded. */
435317e2 199inline
88e17b57
BE
200BOOL
201__objc_responds_to (id object, SEL sel)
202{
40165636 203 void *res;
88e17b57
BE
204
205 /* Install dispatch table if need be */
206 if (object->class_pointer->dtable == __objc_uninstalled_dtable)
207 {
40165636 208 objc_mutex_lock (__objc_runtime_mutex);
c19f8e35
NP
209 if (object->class_pointer->dtable == __objc_uninstalled_dtable)
210 {
211 __objc_install_dispatch_table_for_class (object->class_pointer);
212 }
40165636 213 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
214 }
215
216 /* Get the method from the dispatch table */
217 res = sarray_get_safe (object->class_pointer->dtable, (size_t) sel->sel_id);
218 return (res != 0);
219}
220
221/* This is the lookup function. All entries in the table are either a
222 valid method *or* zero. If zero then either the dispatch table
223 needs to be installed or it doesn't exist and forwarding is attempted. */
435317e2 224inline
88e17b57 225IMP
40165636 226objc_msg_lookup (id receiver, SEL op)
88e17b57
BE
227{
228 IMP result;
40165636 229 if (receiver)
88e17b57
BE
230 {
231 result = sarray_get_safe (receiver->class_pointer->dtable,
232 (sidx)op->sel_id);
233 if (result == 0)
234 {
235 /* Not a valid method */
40165636 236 if (receiver->class_pointer->dtable == __objc_uninstalled_dtable)
88e17b57
BE
237 {
238 /* The dispatch table needs to be installed.
239 This happens on the very first method call to the class. */
40165636 240 __objc_init_install_dtable (receiver, op);
88e17b57
BE
241
242 /* Get real method for this in newly installed dtable */
40165636 243 result = get_imp (receiver->class_pointer, op);
88e17b57
BE
244 }
245 else
246 {
c19f8e35
NP
247 /* The dispatch table has been installed. Check again
248 if the method exists (just in case the dispatch table
249 has been installed by another thread after we did the
250 previous check that the method exists).
251 */
252 result = sarray_get_safe (receiver->class_pointer->dtable,
253 (sidx)op->sel_id);
254 if (result == 0)
255 {
256 /* If the method still just doesn't exist for the
257 class, attempt to forward the method. */
80ae8e8a 258 result = __objc_get_forward_imp (receiver, op);
c19f8e35 259 }
88e17b57
BE
260 }
261 }
262 return result;
263 }
264 else
faaa30fe 265 return (IMP)nil_method;
88e17b57
BE
266}
267
268IMP
269objc_msg_lookup_super (Super_t super, SEL sel)
270{
271 if (super->self)
272 return get_imp (super->class, sel);
273 else
faaa30fe 274 return (IMP)nil_method;
88e17b57
BE
275}
276
40165636 277int method_get_sizeof_arguments (Method *);
88e17b57
BE
278
279retval_t
40165636 280objc_msg_sendv (id object, SEL op, arglist_t arg_frame)
88e17b57 281{
40165636 282 Method *m = class_get_instance_method (object->class_pointer, op);
88e17b57 283 const char *type;
40165636
RB
284 *((id *) method_get_first_argument (m, arg_frame, &type)) = object;
285 *((SEL *) method_get_next_argument (arg_frame, &type)) = op;
286 return __builtin_apply ((apply_t) m->method_imp,
287 arg_frame,
288 method_get_sizeof_arguments (m));
88e17b57
BE
289}
290
291void
40165636 292__objc_init_dispatch_tables ()
88e17b57 293{
40165636 294 __objc_uninstalled_dtable = sarray_new (200, 0);
88e17b57
BE
295}
296
297/* This function is called by objc_msg_lookup when the
298 dispatch table needs to be installed; thus it is called once
299 for each class, namely when the very first message is sent to it. */
300static void
40165636 301__objc_init_install_dtable (id receiver, SEL op __attribute__ ((__unused__)))
88e17b57 302{
c19f8e35
NP
303 objc_mutex_lock (__objc_runtime_mutex);
304
88e17b57
BE
305 /* This may happen, if the programmer has taken the address of a
306 method before the dtable was initialized... too bad for him! */
40165636 307 if (receiver->class_pointer->dtable != __objc_uninstalled_dtable)
c19f8e35
NP
308 {
309 objc_mutex_unlock (__objc_runtime_mutex);
310 return;
311 }
312
40165636 313 if (CLS_ISCLASS (receiver->class_pointer))
88e17b57
BE
314 {
315 /* receiver is an ordinary object */
40165636 316 assert (CLS_ISCLASS (receiver->class_pointer));
88e17b57
BE
317
318 /* install instance methods table */
319 __objc_install_dispatch_table_for_class (receiver->class_pointer);
320
321 /* call +initialize -- this will in turn install the factory
322 dispatch table if not already done :-) */
40165636 323 __objc_send_initialize (receiver->class_pointer);
88e17b57
BE
324 }
325 else
326 {
327 /* receiver is a class object */
40165636
RB
328 assert (CLS_ISCLASS ((Class)receiver));
329 assert (CLS_ISMETA (receiver->class_pointer));
88e17b57
BE
330
331 /* Install real dtable for factory methods */
332 __objc_install_dispatch_table_for_class (receiver->class_pointer);
333
40165636 334 __objc_send_initialize ((Class)receiver);
88e17b57 335 }
40165636 336 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
337}
338
339/* Install dummy table for class which causes the first message to
340 that class (or instances hereof) to be initialized properly */
341void
40165636 342__objc_install_premature_dtable (Class class)
88e17b57 343{
40165636 344 assert (__objc_uninstalled_dtable);
88e17b57
BE
345 class->dtable = __objc_uninstalled_dtable;
346}
347
348/* Send +initialize to class if not already done */
349static void
40165636 350__objc_send_initialize (Class class)
88e17b57
BE
351{
352 /* This *must* be a class object */
40165636
RB
353 assert (CLS_ISCLASS (class));
354 assert (! CLS_ISMETA (class));
88e17b57 355
40165636 356 if (! CLS_ISINITIALIZED (class))
88e17b57 357 {
40165636
RB
358 CLS_SETINITIALIZED (class);
359 CLS_SETINITIALIZED (class->class_pointer);
88e17b57
BE
360
361 /* Create the garbage collector type memory description */
362 __objc_generate_gc_type_description (class);
363
40165636
RB
364 if (class->super_class)
365 __objc_send_initialize (class->super_class);
88e17b57
BE
366
367 {
368 SEL op = sel_register_name ("initialize");
369 IMP imp = 0;
370 MethodList_t method_list = class->class_pointer->methods;
371
372 while (method_list) {
373 int i;
374 Method_t method;
375
40165636 376 for (i = 0; i < method_list->method_count; i++) {
88e17b57
BE
377 method = &(method_list->method_list[i]);
378 if (method->method_name
379 && method->method_name->sel_id == op->sel_id) {
380 imp = method->method_imp;
381 break;
382 }
383 }
384
385 if (imp)
386 break;
387
388 method_list = method_list->method_next;
389
390 }
391 if (imp)
40165636 392 (*imp) ((id) class, op);
88e17b57
BE
393
394 }
395 }
396}
397
398/* Walk on the methods list of class and install the methods in the reverse
399 order of the lists. Since methods added by categories are before the methods
400 of class in the methods list, this allows categories to substitute methods
401 declared in class. However if more than one category replaces the same
402 method nothing is guaranteed about what method will be used.
403 Assumes that __objc_runtime_mutex is locked down. */
404static void
405__objc_install_methods_in_dtable (Class class, MethodList_t method_list)
406{
407 int i;
408
40165636 409 if (! method_list)
88e17b57
BE
410 return;
411
412 if (method_list->method_next)
413 __objc_install_methods_in_dtable (class, method_list->method_next);
414
415 for (i = 0; i < method_list->method_count; i++)
416 {
417 Method_t method = &(method_list->method_list[i]);
418 sarray_at_put_safe (class->dtable,
419 (sidx) method->method_name->sel_id,
420 method->method_imp);
421 }
422}
423
424/* Assumes that __objc_runtime_mutex is locked down. */
425static void
426__objc_install_dispatch_table_for_class (Class class)
427{
428 Class super;
429
430 /* If the class has not yet had its class links resolved, we must
431 re-compute all class links */
40165636
RB
432 if (! CLS_ISRESOLV (class))
433 __objc_resolve_class_links ();
88e17b57
BE
434
435 super = class->super_class;
436
437 if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
438 __objc_install_dispatch_table_for_class (super);
439
440 /* Allocate dtable if necessary */
441 if (super == 0)
442 {
40165636 443 objc_mutex_lock (__objc_runtime_mutex);
88e17b57 444 class->dtable = sarray_new (__objc_selector_max_index, 0);
40165636 445 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
446 }
447 else
448 class->dtable = sarray_lazy_copy (super->dtable);
449
450 __objc_install_methods_in_dtable (class, class->methods);
451}
452
453void
454__objc_update_dispatch_table_for_class (Class class)
455{
456 Class next;
457 struct sarray *arr;
458
459 /* not yet installed -- skip it */
460 if (class->dtable == __objc_uninstalled_dtable)
461 return;
462
40165636 463 objc_mutex_lock (__objc_runtime_mutex);
88e17b57
BE
464
465 arr = class->dtable;
466 __objc_install_premature_dtable (class); /* someone might require it... */
467 sarray_free (arr); /* release memory */
468
469 /* could have been lazy... */
470 __objc_install_dispatch_table_for_class (class);
471
472 if (class->subclass_list) /* Traverse subclasses */
473 for (next = class->subclass_list; next; next = next->sibling_class)
474 __objc_update_dispatch_table_for_class (next);
475
40165636 476 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
477}
478
479
480/* This function adds a method list to a class. This function is
481 typically called by another function specific to the run-time. As
482 such this function does not worry about thread safe issues.
483
484 This one is only called for categories. Class objects have their
485 methods installed right away, and their selectors are made into
435317e2 486 SEL's by the function __objc_register_selectors_from_class. */
88e17b57
BE
487void
488class_add_method_list (Class class, MethodList_t list)
489{
88e17b57 490 /* Passing of a linked list is not allowed. Do multiple calls. */
40165636 491 assert (! list->method_next);
88e17b57 492
435317e2 493 __objc_register_selectors_from_list(list);
88e17b57
BE
494
495 /* Add the methods to the class's method list. */
496 list->method_next = class->methods;
497 class->methods = list;
498
499 /* Update the dispatch table of class */
500 __objc_update_dispatch_table_for_class (class);
501}
502
503Method_t
40165636 504class_get_instance_method (Class class, SEL op)
88e17b57 505{
40165636 506 return search_for_method_in_hierarchy (class, op);
88e17b57
BE
507}
508
509Method_t
40165636 510class_get_class_method (MetaClass class, SEL op)
88e17b57 511{
40165636 512 return search_for_method_in_hierarchy (class, op);
88e17b57
BE
513}
514
515
516/* Search for a method starting from the current class up its hierarchy.
517 Return a pointer to the method's method structure if found. NULL
518 otherwise. */
519
520static Method_t
521search_for_method_in_hierarchy (Class cls, SEL sel)
522{
523 Method_t method = NULL;
524 Class class;
525
526 if (! sel_is_mapped (sel))
527 return NULL;
528
529 /* Scan the method list of the class. If the method isn't found in the
530 list then step to its super class. */
531 for (class = cls; ((! method) && class); class = class->super_class)
532 method = search_for_method_in_list (class->methods, sel);
533
534 return method;
535}
536
537
538
539/* Given a linked list of method and a method's name. Search for the named
540 method's method structure. Return a pointer to the method's method
541 structure if found. NULL otherwise. */
542Method_t
543search_for_method_in_list (MethodList_t list, SEL op)
544{
545 MethodList_t method_list = list;
546
547 if (! sel_is_mapped (op))
548 return NULL;
549
550 /* If not found then we'll search the list. */
551 while (method_list)
552 {
553 int i;
554
555 /* Search the method list. */
556 for (i = 0; i < method_list->method_count; ++i)
557 {
558 Method_t method = &method_list->method_list[i];
559
560 if (method->method_name)
561 if (method->method_name->sel_id == op->sel_id)
562 return method;
563 }
564
565 /* The method wasn't found. Follow the link to the next list of
566 methods. */
567 method_list = method_list->method_next;
568 }
569
570 return NULL;
571}
572
573static retval_t __objc_forward (id object, SEL sel, arglist_t args);
574
575/* Forwarding pointers/integers through the normal registers */
576static id
577__objc_word_forward (id rcv, SEL op, ...)
578{
579 void *args, *res;
580
581 args = __builtin_apply_args ();
582 res = __objc_forward (rcv, op, args);
583 if (res)
584 __builtin_return (res);
585 else
586 return res;
587}
588
589/* Specific routine for forwarding floats/double because of
590 architectural differences on some processors. i386s for
591 example which uses a floating point stack versus general
592 registers for floating point numbers. This forward routine
593 makes sure that GCC restores the proper return values */
594static double
595__objc_double_forward (id rcv, SEL op, ...)
596{
597 void *args, *res;
598
599 args = __builtin_apply_args ();
600 res = __objc_forward (rcv, op, args);
601 __builtin_return (res);
602}
603
604#if INVISIBLE_STRUCT_RETURN
605static __big
606#else
607static id
608#endif
609__objc_block_forward (id rcv, SEL op, ...)
610{
611 void *args, *res;
612
613 args = __builtin_apply_args ();
614 res = __objc_forward (rcv, op, args);
615 if (res)
616 __builtin_return (res);
617 else
618#if INVISIBLE_STRUCT_RETURN
619 return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
620#else
621 return nil;
622#endif
623}
624
625
626/* This function is installed in the dispatch table for all methods which are
627 not implemented. Thus, it is called when a selector is not recognized. */
628static retval_t
629__objc_forward (id object, SEL sel, arglist_t args)
630{
631 IMP imp;
632 static SEL frwd_sel = 0; /* !T:SAFE2 */
633 SEL err_sel;
634
635 /* first try if the object understands forward:: */
40165636
RB
636 if (! frwd_sel)
637 frwd_sel = sel_get_any_uid ("forward::");
88e17b57
BE
638
639 if (__objc_responds_to (object, frwd_sel))
640 {
40165636
RB
641 imp = get_imp (object->class_pointer, frwd_sel);
642 return (*imp) (object, frwd_sel, sel, args);
88e17b57
BE
643 }
644
645 /* If the object recognizes the doesNotRecognize: method then we're going
646 to send it. */
647 err_sel = sel_get_any_uid ("doesNotRecognize:");
648 if (__objc_responds_to (object, err_sel))
649 {
650 imp = get_imp (object->class_pointer, err_sel);
651 return (*imp) (object, err_sel, sel);
652 }
653
654 /* The object doesn't recognize the method. Check for responding to
655 error:. If it does then sent it. */
656 {
40165636
RB
657 char msg[256 + strlen ((const char *) sel_get_name (sel))
658 + strlen ((const char *) object->class_pointer->name)];
88e17b57
BE
659
660 sprintf (msg, "(%s) %s does not recognize %s",
40165636 661 (CLS_ISMETA (object->class_pointer)
88e17b57
BE
662 ? "class"
663 : "instance" ),
664 object->class_pointer->name, sel_get_name (sel));
665
7b869986 666 /* TODO: support for error: is surely deprecated ? */
88e17b57
BE
667 err_sel = sel_get_any_uid ("error:");
668 if (__objc_responds_to (object, err_sel))
669 {
670 imp = get_imp (object->class_pointer, err_sel);
671 return (*imp) (object, sel_get_any_uid ("error:"), msg);
672 }
673
674 /* The object doesn't respond to doesNotRecognize: or error:; Therefore,
675 a default action is taken. */
7b869986 676 _objc_abort ("%s\n", msg);
88e17b57
BE
677
678 return 0;
679 }
680}
681
682void
40165636 683__objc_print_dtable_stats ()
88e17b57
BE
684{
685 int total = 0;
686
40165636 687 objc_mutex_lock (__objc_runtime_mutex);
88e17b57 688
88e17b57 689#ifdef OBJC_SPARSE2
40165636 690 printf ("memory usage: (%s)\n", "2-level sparse arrays");
88e17b57 691#else
40165636 692 printf ("memory usage: (%s)\n", "3-level sparse arrays");
88e17b57 693#endif
88e17b57 694
40165636 695 printf ("arrays: %d = %ld bytes\n", narrays,
b15b7ef8 696 (long) ((size_t) narrays * sizeof (struct sarray)));
40165636
RB
697 total += narrays * sizeof (struct sarray);
698 printf ("buckets: %d = %ld bytes\n", nbuckets,
b15b7ef8 699 (long) ((size_t) nbuckets * sizeof (struct sbucket)));
40165636
RB
700 total += nbuckets * sizeof (struct sbucket);
701
702 printf ("idxtables: %d = %ld bytes\n",
b15b7ef8 703 idxsize, (long) ((size_t) idxsize * sizeof (void *)));
40165636
RB
704 total += idxsize * sizeof (void *);
705 printf ("-----------------------------------\n");
706 printf ("total: %d bytes\n", total);
707 printf ("===================================\n");
708
709 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
710}
711
712/* Returns the uninstalled dispatch table indicator.
713 If a class' dispatch table points to __objc_uninstalled_dtable
714 then that means it needs its dispatch table to be installed. */
435317e2 715inline
40165636
RB
716struct sarray *
717objc_get_uninstalled_dtable ()
88e17b57
BE
718{
719 return __objc_uninstalled_dtable;
720}