]> gcc.gnu.org Git - gcc.git/blame - libobjc/selector.c
In libobjc/:
[gcc.git] / libobjc / selector.c
CommitLineData
88e17b57 1/* GNU Objective C Runtime selector related functions
748086b7 2 Copyright (C) 1993, 1995, 1996, 1997, 2002, 2004, 2009 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
6dead247 25#include "objc-private/common.h"
a19fac96
NP
26#include "objc/objc.h"
27#include "objc/objc-api.h"
28#include "objc/thr.h"
29#include "objc/hash.h"
30#include "objc/objc-list.h"
31#include "objc-private/runtime.h"
348a3445
DA
32#include "objc/sarray.h"
33#include "objc/encoding.h"
88e17b57
BE
34
35/* Initial selector hash table size. Value doesn't matter much */
36#define SELECTOR_HASH_SIZE 128
37
38/* Tables mapping selector names to uid and opposite */
40165636
RB
39static struct sarray *__objc_selector_array = 0; /* uid -> sel !T:MUTEX */
40static struct sarray *__objc_selector_names = 0; /* uid -> name !T:MUTEX */
88e17b57
BE
41static cache_ptr __objc_selector_hash = 0; /* name -> uid !T:MUTEX */
42
88e17b57 43/* Number of selectors stored in each of the above tables */
b62cc13a 44unsigned int __objc_selector_max_index = 0; /* !T:MUTEX */
88e17b57 45
64cbe55e 46void __objc_init_selector_tables (void)
88e17b57
BE
47{
48 __objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0);
49 __objc_selector_names = sarray_new (SELECTOR_HASH_SIZE, 0);
50 __objc_selector_hash
270a1283
DA
51 = objc_hash_new (SELECTOR_HASH_SIZE,
52 (hash_func_type) objc_hash_string,
53 (compare_func_type) objc_compare_strings);
88e17b57
BE
54}
55
56/* This routine is given a class and records all of the methods in its class
57 structure in the record table. */
58void
59__objc_register_selectors_from_class (Class class)
60{
61 MethodList_t method_list;
62
63 method_list = class->methods;
64 while (method_list)
65 {
435317e2 66 __objc_register_selectors_from_list (method_list);
88e17b57
BE
67 method_list = method_list->method_next;
68 }
69}
70
71
72/* This routine is given a list of methods and records each of the methods in
73 the record table. This is the routine that does the actual recording
74 work.
75
435317e2
AP
76 The name and type pointers in the method list must be permanent and
77 immutable.
88e17b57 78 */
435317e2
AP
79void
80__objc_register_selectors_from_list (MethodList_t method_list)
88e17b57
BE
81{
82 int i = 0;
435317e2
AP
83
84 objc_mutex_lock (__objc_runtime_mutex);
88e17b57
BE
85 while (i < method_list->method_count)
86 {
87 Method_t method = &method_list->method_list[i];
435317e2
AP
88 if (method->method_name)
89 {
90 method->method_name
91 = __sel_register_typed_name ((const char *) method->method_name,
92 method->method_types, 0, YES);
93 }
88e17b57
BE
94 i += 1;
95 }
435317e2 96 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
97}
98
99
100/* Register instance methods as class methods for root classes */
40165636 101void __objc_register_instance_methods_to_class (Class class)
88e17b57
BE
102{
103 MethodList_t method_list;
104 MethodList_t class_method_list;
105 int max_methods_no = 16;
106 MethodList_t new_list;
107 Method_t curr_method;
108
109 /* Only if a root class. */
40165636 110 if (class->super_class)
88e17b57
BE
111 return;
112
113 /* Allocate a method list to hold the new class methods */
40165636
RB
114 new_list = objc_calloc (sizeof (struct objc_method_list)
115 + sizeof (struct objc_method[max_methods_no]), 1);
88e17b57
BE
116 method_list = class->methods;
117 class_method_list = class->class_pointer->methods;
118 curr_method = &new_list->method_list[0];
119
120 /* Iterate through the method lists for the class */
121 while (method_list)
122 {
123 int i;
124
125 /* Iterate through the methods from this method list */
126 for (i = 0; i < method_list->method_count; i++)
127 {
128 Method_t mth = &method_list->method_list[i];
129 if (mth->method_name
40165636 130 && ! search_for_method_in_list (class_method_list,
88e17b57
BE
131 mth->method_name))
132 {
133 /* This instance method isn't a class method.
134 Add it into the new_list. */
135 *curr_method = *mth;
136
137 /* Reallocate the method list if necessary */
40165636 138 if (++new_list->method_count == max_methods_no)
88e17b57 139 new_list =
40165636
RB
140 objc_realloc (new_list, sizeof (struct objc_method_list)
141 + sizeof (struct
88e17b57
BE
142 objc_method[max_methods_no += 16]));
143 curr_method = &new_list->method_list[new_list->method_count];
144 }
145 }
146
147 method_list = method_list->method_next;
148 }
149
150 /* If we created any new class methods
151 then attach the method list to the class */
152 if (new_list->method_count)
153 {
154 new_list =
40165636
RB
155 objc_realloc (new_list, sizeof (struct objc_method_list)
156 + sizeof (struct objc_method[new_list->method_count]));
88e17b57
BE
157 new_list->method_next = class->class_pointer->methods;
158 class->class_pointer->methods = new_list;
159 }
5af0e6ae
AF
160 else
161 objc_free(new_list);
88e17b57
BE
162
163 __objc_update_dispatch_table_for_class (class->class_pointer);
164}
165
166
167/* Returns YES iff t1 and t2 have same method types, but we ignore
168 the argframe layout */
169BOOL
40165636 170sel_types_match (const char *t1, const char *t2)
88e17b57 171{
40165636 172 if (! t1 || ! t2)
88e17b57
BE
173 return NO;
174 while (*t1 && *t2)
175 {
176 if (*t1 == '+') t1++;
177 if (*t2 == '+') t2++;
40165636
RB
178 while (isdigit ((unsigned char) *t1)) t1++;
179 while (isdigit ((unsigned char) *t2)) t2++;
88e17b57
BE
180 /* xxx Remove these next two lines when qualifiers are put in
181 all selectors, not just Protocol selectors. */
40165636
RB
182 t1 = objc_skip_type_qualifiers (t1);
183 t2 = objc_skip_type_qualifiers (t2);
184 if (! *t1 && ! *t2)
88e17b57
BE
185 return YES;
186 if (*t1 != *t2)
187 return NO;
188 t1++;
189 t2++;
190 }
191 return NO;
192}
193
194/* return selector representing name */
195SEL
196sel_get_typed_uid (const char *name, const char *types)
197{
198 struct objc_list *l;
199 sidx i;
200
40165636 201 objc_mutex_lock (__objc_runtime_mutex);
88e17b57 202
270a1283 203 i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
88e17b57
BE
204 if (i == 0)
205 {
40165636 206 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
207 return 0;
208 }
209
40165636 210 for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
88e17b57
BE
211 l; l = l->tail)
212 {
40165636 213 SEL s = (SEL) l->head;
88e17b57
BE
214 if (types == 0 || s->sel_types == 0)
215 {
216 if (s->sel_types == types)
217 {
40165636 218 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
219 return s;
220 }
221 }
222 else if (sel_types_match (s->sel_types, types))
223 {
40165636 224 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
225 return s;
226 }
227 }
228
40165636 229 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
230 return 0;
231}
232
233/* Return selector representing name; prefer a selector with non-NULL type */
234SEL
235sel_get_any_typed_uid (const char *name)
236{
237 struct objc_list *l;
238 sidx i;
239 SEL s = NULL;
240
40165636 241 objc_mutex_lock (__objc_runtime_mutex);
88e17b57 242
270a1283 243 i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
88e17b57
BE
244 if (i == 0)
245 {
40165636 246 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
247 return 0;
248 }
249
40165636 250 for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
88e17b57
BE
251 l; l = l->tail)
252 {
253 s = (SEL) l->head;
254 if (s->sel_types)
255 {
40165636 256 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
257 return s;
258 }
259 }
260
40165636 261 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
262 return s;
263}
264
265/* return selector representing name */
266SEL
267sel_get_any_uid (const char *name)
268{
269 struct objc_list *l;
270 sidx i;
271
40165636 272 objc_mutex_lock (__objc_runtime_mutex);
88e17b57 273
270a1283 274 i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
88e17b57
BE
275 if (soffset_decode (i) == 0)
276 {
40165636 277 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
278 return 0;
279 }
280
40165636
RB
281 l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
282 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
283
284 if (l == 0)
285 return 0;
286
40165636 287 return (SEL) l->head;
88e17b57
BE
288}
289
290/* return selector representing name */
291SEL
292sel_get_uid (const char *name)
293{
294 return sel_register_typed_name (name, 0);
295}
296
297/* Get name of selector. If selector is unknown, the empty string ""
298 is returned */
40165636 299const char *sel_get_name (SEL selector)
88e17b57
BE
300{
301 const char *ret;
302
40165636
RB
303 objc_mutex_lock (__objc_runtime_mutex);
304 if ((soffset_decode ((sidx)selector->sel_id) > 0)
305 && (soffset_decode ((sidx)selector->sel_id) <= __objc_selector_max_index))
88e17b57
BE
306 ret = sarray_get_safe (__objc_selector_names, (sidx) selector->sel_id);
307 else
308 ret = 0;
40165636 309 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
310 return ret;
311}
312
313BOOL
314sel_is_mapped (SEL selector)
315{
316 unsigned int idx = soffset_decode ((sidx)selector->sel_id);
317 return ((idx > 0) && (idx <= __objc_selector_max_index));
318}
319
320
40165636 321const char *sel_get_type (SEL selector)
88e17b57
BE
322{
323 if (selector)
324 return selector->sel_types;
325 else
326 return 0;
327}
328
329/* The uninstalled dispatch table */
40165636 330extern struct sarray *__objc_uninstalled_dtable;
88e17b57 331
435317e2
AP
332/* __sel_register_typed_name allocates lots of struct objc_selector:s
333 of 8 (16, if pointers are 64 bits) bytes at startup. To reduce the number
334 of malloc calls and memory lost to malloc overhead, we allocate
335 objc_selector:s in blocks here. This is only called from
336 __sel_register_typed_name, and __sel_register_typed_name may only be
337 called when __objc_runtime_mutex is locked.
338
339 Note that the objc_selector:s allocated from __sel_register_typed_name
340 are never freed.
341
342 62 because 62 * sizeof (struct objc_selector) = 496 (992). This should
343 let malloc add some overhead and use a nice, round 512 (1024) byte chunk.
344 */
345#define SELECTOR_POOL_SIZE 62
346static struct objc_selector *selector_pool;
347static int selector_pool_left;
348
349static struct objc_selector *
350pool_alloc_selector(void)
351{
352 if (!selector_pool_left)
353 {
354 selector_pool = objc_malloc (sizeof (struct objc_selector)
355 * SELECTOR_POOL_SIZE);
356 selector_pool_left = SELECTOR_POOL_SIZE;
357 }
358 return &selector_pool[--selector_pool_left];
359}
360
88e17b57
BE
361/* Store the passed selector name in the selector record and return its
362 selector value (value returned by sel_get_uid).
363 Assumes that the calling function has locked down __objc_runtime_mutex. */
364/* is_const parameter tells us if the name and types parameters
365 are really constant or not. If YES then they are constant and
366 we can just store the pointers. If NO then we need to copy
367 name and types because the pointers may disappear later on. */
368SEL
369__sel_register_typed_name (const char *name, const char *types,
370 struct objc_selector *orig, BOOL is_const)
371{
40165636 372 struct objc_selector *j;
88e17b57
BE
373 sidx i;
374 struct objc_list *l;
375
270a1283 376 i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
88e17b57
BE
377 if (soffset_decode (i) != 0)
378 {
40165636 379 for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
88e17b57
BE
380 l; l = l->tail)
381 {
40165636 382 SEL s = (SEL) l->head;
88e17b57
BE
383 if (types == 0 || s->sel_types == 0)
384 {
385 if (s->sel_types == types)
386 {
387 if (orig)
388 {
40165636 389 orig->sel_id = (void *) i;
88e17b57
BE
390 return orig;
391 }
392 else
393 return s;
394 }
395 }
40165636 396 else if (! strcmp (s->sel_types, types))
88e17b57
BE
397 {
398 if (orig)
399 {
40165636 400 orig->sel_id = (void *) i;
88e17b57
BE
401 return orig;
402 }
403 else
404 return s;
405 }
406 }
407 if (orig)
408 j = orig;
409 else
435317e2 410 j = pool_alloc_selector ();
88e17b57 411
40165636 412 j->sel_id = (void *) i;
88e17b57
BE
413 /* Can we use the pointer or must copy types? Don't copy if NULL */
414 if ((is_const) || (types == 0))
40165636 415 j->sel_types = (const char *) types;
88e17b57 416 else {
40165636
RB
417 j->sel_types = (char *) objc_malloc (strlen (types) + 1);
418 strcpy ((char *) j->sel_types, types);
88e17b57 419 }
40165636 420 l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
88e17b57
BE
421 }
422 else
423 {
424 __objc_selector_max_index += 1;
40165636 425 i = soffset_encode (__objc_selector_max_index);
88e17b57
BE
426 if (orig)
427 j = orig;
428 else
435317e2 429 j = pool_alloc_selector ();
88e17b57 430
40165636 431 j->sel_id = (void *) i;
88e17b57
BE
432 /* Can we use the pointer or must copy types? Don't copy if NULL */
433 if ((is_const) || (types == 0))
40165636 434 j->sel_types = (const char *) types;
88e17b57 435 else {
40165636
RB
436 j->sel_types = (char *) objc_malloc (strlen (types) + 1);
437 strcpy ((char *) j->sel_types, types);
88e17b57
BE
438 }
439 l = 0;
440 }
441
442 DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", name, types,
435317e2 443 (long) soffset_decode (i));
88e17b57
BE
444
445 {
446 int is_new = (l == 0);
447 const char *new_name;
448
449 /* Can we use the pointer or must copy name? Don't copy if NULL */
450 if ((is_const) || (name == 0))
451 new_name = name;
452 else {
40165636
RB
453 new_name = (char *) objc_malloc (strlen (name) + 1);
454 strcpy ((char *) new_name, name);
88e17b57
BE
455 }
456
40165636 457 l = list_cons ((void *) j, l);
88e17b57
BE
458 sarray_at_put_safe (__objc_selector_names, i, (void *) new_name);
459 sarray_at_put_safe (__objc_selector_array, i, (void *) l);
460 if (is_new)
270a1283 461 objc_hash_add (&__objc_selector_hash, (void *) new_name, (void *) i);
88e17b57
BE
462 }
463
40165636 464 sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1);
88e17b57
BE
465
466 return (SEL) j;
467}
468
469SEL
470sel_register_name (const char *name)
471{
472 SEL ret;
473
40165636 474 objc_mutex_lock (__objc_runtime_mutex);
88e17b57
BE
475 /* Assume that name is not constant static memory and needs to be
476 copied before put into a runtime structure. is_const == NO */
477 ret = __sel_register_typed_name (name, 0, 0, NO);
40165636 478 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
479
480 return ret;
481}
482
483SEL
484sel_register_typed_name (const char *name, const char *type)
485{
486 SEL ret;
435317e2 487
40165636 488 objc_mutex_lock (__objc_runtime_mutex);
88e17b57
BE
489 /* Assume that name and type are not constant static memory and need to
490 be copied before put into a runtime structure. is_const == NO */
491 ret = __sel_register_typed_name (name, type, 0, NO);
40165636 492 objc_mutex_unlock (__objc_runtime_mutex);
88e17b57
BE
493
494 return ret;
495}
This page took 1.058737 seconds and 5 git commands to generate.