]> git.ipfire.org Git - thirdparty/gcc.git/blob - libobjc/selector.c
In libobjc/: 2010-10-14 Nicola Pero <nicola.pero@meta-innovation.com>
[thirdparty/gcc.git] / libobjc / selector.c
1 /* GNU Objective C Runtime selector related functions
2 Copyright (C) 1993, 1995, 1996, 1997, 2002, 2004, 2009 Free Software Foundation, Inc.
3 Contributed by Kresten Krab Thorup
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 3, or (at your option) any later version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 details.
15
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
19
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
24
25 #include "objc-private/common.h"
26 #include "objc/objc-api.h"
27 #include "objc/thr.h"
28 #include "objc-private/hash.h"
29 #include "objc-private/objc-list.h"
30 #include "objc-private/runtime.h"
31 #include "objc-private/sarray.h"
32 #include "objc/encoding.h"
33
34 /* Initial selector hash table size. Value doesn't matter much */
35 #define SELECTOR_HASH_SIZE 128
36
37 /* Tables mapping selector names to uid and opposite */
38 static struct sarray *__objc_selector_array = 0; /* uid -> sel !T:MUTEX */
39 static struct sarray *__objc_selector_names = 0; /* uid -> name !T:MUTEX */
40 static cache_ptr __objc_selector_hash = 0; /* name -> uid !T:MUTEX */
41
42 /* Number of selectors stored in each of the above tables */
43 unsigned int __objc_selector_max_index = 0; /* !T:MUTEX */
44
45 void __objc_init_selector_tables (void)
46 {
47 __objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0);
48 __objc_selector_names = sarray_new (SELECTOR_HASH_SIZE, 0);
49 __objc_selector_hash
50 = objc_hash_new (SELECTOR_HASH_SIZE,
51 (hash_func_type) objc_hash_string,
52 (compare_func_type) objc_compare_strings);
53 }
54
55 /* This routine is given a class and records all of the methods in its class
56 structure in the record table. */
57 void
58 __objc_register_selectors_from_class (Class class)
59 {
60 MethodList_t method_list;
61
62 method_list = class->methods;
63 while (method_list)
64 {
65 __objc_register_selectors_from_list (method_list);
66 method_list = method_list->method_next;
67 }
68 }
69
70
71 /* This routine is given a list of methods and records each of the methods in
72 the record table. This is the routine that does the actual recording
73 work.
74
75 The name and type pointers in the method list must be permanent and
76 immutable.
77 */
78 void
79 __objc_register_selectors_from_list (MethodList_t method_list)
80 {
81 int i = 0;
82
83 objc_mutex_lock (__objc_runtime_mutex);
84 while (i < method_list->method_count)
85 {
86 Method_t method = &method_list->method_list[i];
87 if (method->method_name)
88 {
89 method->method_name
90 = __sel_register_typed_name ((const char *) method->method_name,
91 method->method_types, 0, YES);
92 }
93 i += 1;
94 }
95 objc_mutex_unlock (__objc_runtime_mutex);
96 }
97
98 /* Temporary definition while we include objc/objc-api.h instead of
99 objc-private/module-abi-8.h. It should go away once we include
100 module-abi-8.h. */
101 struct objc_method_description_list
102 {
103 int count;
104 struct objc_method_description list[1];
105 };
106
107 /* The same as __objc_register_selectors_from_list, but works on a
108 struct objc_method_description_list* instead of a struct
109 objc_method_list*. This is only used for protocols, which have
110 lists of method descriptions, not methods.
111 */
112 void
113 __objc_register_selectors_from_description_list
114 (struct objc_method_description_list *method_list)
115 {
116 int i = 0;
117
118 objc_mutex_lock (__objc_runtime_mutex);
119 while (i < method_list->count)
120 {
121 struct objc_method_description *method = &method_list->list[i];
122 if (method->name)
123 {
124 method->name
125 = __sel_register_typed_name ((const char *) method->name,
126 method->types, 0, YES);
127 }
128 i += 1;
129 }
130 objc_mutex_unlock (__objc_runtime_mutex);
131 }
132
133 /* Register instance methods as class methods for root classes */
134 void __objc_register_instance_methods_to_class (Class class)
135 {
136 MethodList_t method_list;
137 MethodList_t class_method_list;
138 int max_methods_no = 16;
139 MethodList_t new_list;
140 Method_t curr_method;
141
142 /* Only if a root class. */
143 if (class->super_class)
144 return;
145
146 /* Allocate a method list to hold the new class methods */
147 new_list = objc_calloc (sizeof (struct objc_method_list)
148 + sizeof (struct objc_method[max_methods_no]), 1);
149 method_list = class->methods;
150 class_method_list = class->class_pointer->methods;
151 curr_method = &new_list->method_list[0];
152
153 /* Iterate through the method lists for the class */
154 while (method_list)
155 {
156 int i;
157
158 /* Iterate through the methods from this method list */
159 for (i = 0; i < method_list->method_count; i++)
160 {
161 Method_t mth = &method_list->method_list[i];
162 if (mth->method_name
163 && ! search_for_method_in_list (class_method_list,
164 mth->method_name))
165 {
166 /* This instance method isn't a class method.
167 Add it into the new_list. */
168 *curr_method = *mth;
169
170 /* Reallocate the method list if necessary */
171 if (++new_list->method_count == max_methods_no)
172 new_list =
173 objc_realloc (new_list, sizeof (struct objc_method_list)
174 + sizeof (struct
175 objc_method[max_methods_no += 16]));
176 curr_method = &new_list->method_list[new_list->method_count];
177 }
178 }
179
180 method_list = method_list->method_next;
181 }
182
183 /* If we created any new class methods
184 then attach the method list to the class */
185 if (new_list->method_count)
186 {
187 new_list =
188 objc_realloc (new_list, sizeof (struct objc_method_list)
189 + sizeof (struct objc_method[new_list->method_count]));
190 new_list->method_next = class->class_pointer->methods;
191 class->class_pointer->methods = new_list;
192 }
193 else
194 objc_free(new_list);
195
196 __objc_update_dispatch_table_for_class (class->class_pointer);
197 }
198
199 BOOL
200 sel_isEqual (SEL s1, SEL s2)
201 {
202 if (s1 == 0 || s2 == 0)
203 return s1 == s2;
204 else
205 return s1->sel_id == s2->sel_id;
206 }
207
208 /* Returns YES iff t1 and t2 have same method types, but we ignore
209 the argframe layout */
210 BOOL
211 sel_types_match (const char *t1, const char *t2)
212 {
213 if (! t1 || ! t2)
214 return NO;
215 while (*t1 && *t2)
216 {
217 if (*t1 == '+') t1++;
218 if (*t2 == '+') t2++;
219 while (isdigit ((unsigned char) *t1)) t1++;
220 while (isdigit ((unsigned char) *t2)) t2++;
221 /* xxx Remove these next two lines when qualifiers are put in
222 all selectors, not just Protocol selectors. */
223 t1 = objc_skip_type_qualifiers (t1);
224 t2 = objc_skip_type_qualifiers (t2);
225 if (! *t1 && ! *t2)
226 return YES;
227 if (*t1 != *t2)
228 return NO;
229 t1++;
230 t2++;
231 }
232 return NO;
233 }
234
235 /* return selector representing name */
236 SEL
237 sel_get_typed_uid (const char *name, const char *types)
238 {
239 struct objc_list *l;
240 sidx i;
241
242 objc_mutex_lock (__objc_runtime_mutex);
243
244 i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
245 if (i == 0)
246 {
247 objc_mutex_unlock (__objc_runtime_mutex);
248 return 0;
249 }
250
251 for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
252 l; l = l->tail)
253 {
254 SEL s = (SEL) l->head;
255 if (types == 0 || s->sel_types == 0)
256 {
257 if (s->sel_types == types)
258 {
259 objc_mutex_unlock (__objc_runtime_mutex);
260 return s;
261 }
262 }
263 else if (sel_types_match (s->sel_types, types))
264 {
265 objc_mutex_unlock (__objc_runtime_mutex);
266 return s;
267 }
268 }
269
270 objc_mutex_unlock (__objc_runtime_mutex);
271 return 0;
272 }
273
274 /* Return selector representing name; prefer a selector with non-NULL type */
275 SEL
276 sel_get_any_typed_uid (const char *name)
277 {
278 struct objc_list *l;
279 sidx i;
280 SEL s = NULL;
281
282 objc_mutex_lock (__objc_runtime_mutex);
283
284 i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
285 if (i == 0)
286 {
287 objc_mutex_unlock (__objc_runtime_mutex);
288 return 0;
289 }
290
291 for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
292 l; l = l->tail)
293 {
294 s = (SEL) l->head;
295 if (s->sel_types)
296 {
297 objc_mutex_unlock (__objc_runtime_mutex);
298 return s;
299 }
300 }
301
302 objc_mutex_unlock (__objc_runtime_mutex);
303 return s;
304 }
305
306 /* return selector representing name */
307 SEL
308 sel_get_any_uid (const char *name)
309 {
310 struct objc_list *l;
311 sidx i;
312
313 objc_mutex_lock (__objc_runtime_mutex);
314
315 i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
316 if (soffset_decode (i) == 0)
317 {
318 objc_mutex_unlock (__objc_runtime_mutex);
319 return 0;
320 }
321
322 l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
323 objc_mutex_unlock (__objc_runtime_mutex);
324
325 if (l == 0)
326 return 0;
327
328 return (SEL) l->head;
329 }
330
331 /* Get name of selector. If selector is unknown, the empty string ""
332 is returned */
333 const char *sel_getName (SEL selector)
334 {
335 const char *ret;
336
337 if (selector == NULL)
338 return "<null selector>";
339
340 objc_mutex_lock (__objc_runtime_mutex);
341 if ((soffset_decode ((sidx)selector->sel_id) > 0)
342 && (soffset_decode ((sidx)selector->sel_id) <= __objc_selector_max_index))
343 ret = sarray_get_safe (__objc_selector_names, (sidx) selector->sel_id);
344 else
345 ret = 0;
346 objc_mutex_unlock (__objc_runtime_mutex);
347 return ret;
348 }
349
350 /* Traditional GNU Objective-C Runtime API. */
351 const char *sel_get_name (SEL selector)
352 {
353 if (selector == NULL)
354 return 0;
355
356 return sel_getName (selector);
357 }
358
359 BOOL
360 sel_is_mapped (SEL selector)
361 {
362 unsigned int idx = soffset_decode ((sidx)selector->sel_id);
363 return ((idx > 0) && (idx <= __objc_selector_max_index));
364 }
365
366 const char *sel_getType (SEL selector)
367 {
368 if (selector)
369 return selector->sel_types;
370 else
371 return 0;
372 }
373
374 /* Traditional GNU Objective-C Runtime API. */
375 const char *sel_get_type (SEL selector)
376 {
377 return sel_getType (selector);
378 }
379
380 /* The uninstalled dispatch table */
381 extern struct sarray *__objc_uninstalled_dtable;
382
383 /* __sel_register_typed_name allocates lots of struct objc_selector:s
384 of 8 (16, if pointers are 64 bits) bytes at startup. To reduce the number
385 of malloc calls and memory lost to malloc overhead, we allocate
386 objc_selector:s in blocks here. This is only called from
387 __sel_register_typed_name, and __sel_register_typed_name may only be
388 called when __objc_runtime_mutex is locked.
389
390 Note that the objc_selector:s allocated from __sel_register_typed_name
391 are never freed.
392
393 62 because 62 * sizeof (struct objc_selector) = 496 (992). This should
394 let malloc add some overhead and use a nice, round 512 (1024) byte chunk.
395 */
396 #define SELECTOR_POOL_SIZE 62
397 static struct objc_selector *selector_pool;
398 static int selector_pool_left;
399
400 static struct objc_selector *
401 pool_alloc_selector(void)
402 {
403 if (!selector_pool_left)
404 {
405 selector_pool = objc_malloc (sizeof (struct objc_selector)
406 * SELECTOR_POOL_SIZE);
407 selector_pool_left = SELECTOR_POOL_SIZE;
408 }
409 return &selector_pool[--selector_pool_left];
410 }
411
412 /* Store the passed selector name in the selector record and return its
413 selector value (value returned by sel_get_uid).
414 Assumes that the calling function has locked down __objc_runtime_mutex. */
415 /* is_const parameter tells us if the name and types parameters
416 are really constant or not. If YES then they are constant and
417 we can just store the pointers. If NO then we need to copy
418 name and types because the pointers may disappear later on. */
419 SEL
420 __sel_register_typed_name (const char *name, const char *types,
421 struct objc_selector *orig, BOOL is_const)
422 {
423 struct objc_selector *j;
424 sidx i;
425 struct objc_list *l;
426
427 i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
428 if (soffset_decode (i) != 0)
429 {
430 for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
431 l; l = l->tail)
432 {
433 SEL s = (SEL) l->head;
434 if (types == 0 || s->sel_types == 0)
435 {
436 if (s->sel_types == types)
437 {
438 if (orig)
439 {
440 orig->sel_id = (void *) i;
441 return orig;
442 }
443 else
444 return s;
445 }
446 }
447 else if (! strcmp (s->sel_types, types))
448 {
449 if (orig)
450 {
451 orig->sel_id = (void *) i;
452 return orig;
453 }
454 else
455 return s;
456 }
457 }
458 if (orig)
459 j = orig;
460 else
461 j = pool_alloc_selector ();
462
463 j->sel_id = (void *) i;
464 /* Can we use the pointer or must copy types? Don't copy if NULL */
465 if ((is_const) || (types == 0))
466 j->sel_types = (const char *) types;
467 else {
468 j->sel_types = (char *) objc_malloc (strlen (types) + 1);
469 strcpy ((char *) j->sel_types, types);
470 }
471 l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
472 }
473 else
474 {
475 __objc_selector_max_index += 1;
476 i = soffset_encode (__objc_selector_max_index);
477 if (orig)
478 j = orig;
479 else
480 j = pool_alloc_selector ();
481
482 j->sel_id = (void *) i;
483 /* Can we use the pointer or must copy types? Don't copy if NULL */
484 if ((is_const) || (types == 0))
485 j->sel_types = (const char *) types;
486 else {
487 j->sel_types = (char *) objc_malloc (strlen (types) + 1);
488 strcpy ((char *) j->sel_types, types);
489 }
490 l = 0;
491 }
492
493 DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", name, types,
494 (long) soffset_decode (i));
495
496 {
497 int is_new = (l == 0);
498 const char *new_name;
499
500 /* Can we use the pointer or must copy name? Don't copy if NULL */
501 if ((is_const) || (name == 0))
502 new_name = name;
503 else {
504 new_name = (char *) objc_malloc (strlen (name) + 1);
505 strcpy ((char *) new_name, name);
506 }
507
508 l = list_cons ((void *) j, l);
509 sarray_at_put_safe (__objc_selector_names, i, (void *) new_name);
510 sarray_at_put_safe (__objc_selector_array, i, (void *) l);
511 if (is_new)
512 objc_hash_add (&__objc_selector_hash, (void *) new_name, (void *) i);
513 }
514
515 sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1);
516
517 return (SEL) j;
518 }
519
520 SEL
521 sel_registerName (const char *name)
522 {
523 SEL ret;
524
525 objc_mutex_lock (__objc_runtime_mutex);
526 /* Assume that name is not constant static memory and needs to be
527 copied before put into a runtime structure. is_const == NO */
528 ret = __sel_register_typed_name (name, 0, 0, NO);
529 objc_mutex_unlock (__objc_runtime_mutex);
530
531 return ret;
532 }
533
534 /* Traditional GNU Objective-C Runtime API. */
535 SEL
536 sel_register_name (const char *name)
537 {
538 return sel_registerName (name);
539 }
540
541 SEL
542 sel_registerTypedName (const char *name, const char *type)
543 {
544 SEL ret;
545
546 objc_mutex_lock (__objc_runtime_mutex);
547 /* Assume that name and type are not constant static memory and need to
548 be copied before put into a runtime structure. is_const == NO */
549 ret = __sel_register_typed_name (name, type, 0, NO);
550 objc_mutex_unlock (__objc_runtime_mutex);
551
552 return ret;
553 }
554
555 SEL
556 sel_register_typed_name (const char *name, const char *type)
557 {
558 return sel_registerTypedName (name, type);
559 }
560
561 /* return selector representing name */
562 SEL
563 sel_getUid (const char *name)
564 {
565 return sel_registerTypedName (name, 0);
566 }
567
568 /* Traditional GNU Objective-C Runtime API. */
569 SEL
570 sel_get_uid (const char *name)
571 {
572 return sel_getUid (name);
573 }