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