]> git.ipfire.org Git - thirdparty/gcc.git/blob - libobjc/selector.c
objc.h: Updated comments.
[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.h"
27 #include "objc/objc-api.h"
28 #include "objc/thr.h"
29 #include "objc-private/hash.h"
30 #include "objc-private/objc-list.h"
31 #include "objc-private/runtime.h"
32 #include "objc-private/sarray.h"
33 #include "objc/encoding.h"
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 */
39 static struct sarray *__objc_selector_array = 0; /* uid -> sel !T:MUTEX */
40 static struct sarray *__objc_selector_names = 0; /* uid -> name !T:MUTEX */
41 static cache_ptr __objc_selector_hash = 0; /* name -> uid !T:MUTEX */
42
43 /* Number of selectors stored in each of the above tables */
44 unsigned int __objc_selector_max_index = 0; /* !T:MUTEX */
45
46 void __objc_init_selector_tables (void)
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
51 = objc_hash_new (SELECTOR_HASH_SIZE,
52 (hash_func_type) objc_hash_string,
53 (compare_func_type) objc_compare_strings);
54 }
55
56 /* This routine is given a class and records all of the methods in its class
57 structure in the record table. */
58 void
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 {
66 __objc_register_selectors_from_list (method_list);
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
76 The name and type pointers in the method list must be permanent and
77 immutable.
78 */
79 void
80 __objc_register_selectors_from_list (MethodList_t method_list)
81 {
82 int i = 0;
83
84 objc_mutex_lock (__objc_runtime_mutex);
85 while (i < method_list->method_count)
86 {
87 Method_t method = &method_list->method_list[i];
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 }
94 i += 1;
95 }
96 objc_mutex_unlock (__objc_runtime_mutex);
97 }
98
99
100 /* Register instance methods as class methods for root classes */
101 void __objc_register_instance_methods_to_class (Class class)
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. */
110 if (class->super_class)
111 return;
112
113 /* Allocate a method list to hold the new class methods */
114 new_list = objc_calloc (sizeof (struct objc_method_list)
115 + sizeof (struct objc_method[max_methods_no]), 1);
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
130 && ! search_for_method_in_list (class_method_list,
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 */
138 if (++new_list->method_count == max_methods_no)
139 new_list =
140 objc_realloc (new_list, sizeof (struct objc_method_list)
141 + sizeof (struct
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 =
155 objc_realloc (new_list, sizeof (struct objc_method_list)
156 + sizeof (struct objc_method[new_list->method_count]));
157 new_list->method_next = class->class_pointer->methods;
158 class->class_pointer->methods = new_list;
159 }
160 else
161 objc_free(new_list);
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 */
169 BOOL
170 sel_types_match (const char *t1, const char *t2)
171 {
172 if (! t1 || ! t2)
173 return NO;
174 while (*t1 && *t2)
175 {
176 if (*t1 == '+') t1++;
177 if (*t2 == '+') t2++;
178 while (isdigit ((unsigned char) *t1)) t1++;
179 while (isdigit ((unsigned char) *t2)) t2++;
180 /* xxx Remove these next two lines when qualifiers are put in
181 all selectors, not just Protocol selectors. */
182 t1 = objc_skip_type_qualifiers (t1);
183 t2 = objc_skip_type_qualifiers (t2);
184 if (! *t1 && ! *t2)
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 */
195 SEL
196 sel_get_typed_uid (const char *name, const char *types)
197 {
198 struct objc_list *l;
199 sidx i;
200
201 objc_mutex_lock (__objc_runtime_mutex);
202
203 i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
204 if (i == 0)
205 {
206 objc_mutex_unlock (__objc_runtime_mutex);
207 return 0;
208 }
209
210 for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
211 l; l = l->tail)
212 {
213 SEL s = (SEL) l->head;
214 if (types == 0 || s->sel_types == 0)
215 {
216 if (s->sel_types == types)
217 {
218 objc_mutex_unlock (__objc_runtime_mutex);
219 return s;
220 }
221 }
222 else if (sel_types_match (s->sel_types, types))
223 {
224 objc_mutex_unlock (__objc_runtime_mutex);
225 return s;
226 }
227 }
228
229 objc_mutex_unlock (__objc_runtime_mutex);
230 return 0;
231 }
232
233 /* Return selector representing name; prefer a selector with non-NULL type */
234 SEL
235 sel_get_any_typed_uid (const char *name)
236 {
237 struct objc_list *l;
238 sidx i;
239 SEL s = NULL;
240
241 objc_mutex_lock (__objc_runtime_mutex);
242
243 i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
244 if (i == 0)
245 {
246 objc_mutex_unlock (__objc_runtime_mutex);
247 return 0;
248 }
249
250 for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
251 l; l = l->tail)
252 {
253 s = (SEL) l->head;
254 if (s->sel_types)
255 {
256 objc_mutex_unlock (__objc_runtime_mutex);
257 return s;
258 }
259 }
260
261 objc_mutex_unlock (__objc_runtime_mutex);
262 return s;
263 }
264
265 /* return selector representing name */
266 SEL
267 sel_get_any_uid (const char *name)
268 {
269 struct objc_list *l;
270 sidx i;
271
272 objc_mutex_lock (__objc_runtime_mutex);
273
274 i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
275 if (soffset_decode (i) == 0)
276 {
277 objc_mutex_unlock (__objc_runtime_mutex);
278 return 0;
279 }
280
281 l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
282 objc_mutex_unlock (__objc_runtime_mutex);
283
284 if (l == 0)
285 return 0;
286
287 return (SEL) l->head;
288 }
289
290 /* Get name of selector. If selector is unknown, the empty string ""
291 is returned */
292 const char *sel_getName (SEL selector)
293 {
294 const char *ret;
295
296 objc_mutex_lock (__objc_runtime_mutex);
297 if ((soffset_decode ((sidx)selector->sel_id) > 0)
298 && (soffset_decode ((sidx)selector->sel_id) <= __objc_selector_max_index))
299 ret = sarray_get_safe (__objc_selector_names, (sidx) selector->sel_id);
300 else
301 ret = 0;
302 objc_mutex_unlock (__objc_runtime_mutex);
303 return ret;
304 }
305
306 /* Traditional GNU Objective-C Runtime API. */
307 const char *sel_get_name (SEL selector)
308 {
309 return sel_getName (selector);
310 }
311
312 BOOL
313 sel_is_mapped (SEL selector)
314 {
315 unsigned int idx = soffset_decode ((sidx)selector->sel_id);
316 return ((idx > 0) && (idx <= __objc_selector_max_index));
317 }
318
319 const char *sel_getType (SEL selector)
320 {
321 if (selector)
322 return selector->sel_types;
323 else
324 return 0;
325 }
326
327 /* Traditional GNU Objective-C Runtime API. */
328 const char *sel_get_type (SEL selector)
329 {
330 return sel_getType (selector);
331 }
332
333 /* The uninstalled dispatch table */
334 extern struct sarray *__objc_uninstalled_dtable;
335
336 /* __sel_register_typed_name allocates lots of struct objc_selector:s
337 of 8 (16, if pointers are 64 bits) bytes at startup. To reduce the number
338 of malloc calls and memory lost to malloc overhead, we allocate
339 objc_selector:s in blocks here. This is only called from
340 __sel_register_typed_name, and __sel_register_typed_name may only be
341 called when __objc_runtime_mutex is locked.
342
343 Note that the objc_selector:s allocated from __sel_register_typed_name
344 are never freed.
345
346 62 because 62 * sizeof (struct objc_selector) = 496 (992). This should
347 let malloc add some overhead and use a nice, round 512 (1024) byte chunk.
348 */
349 #define SELECTOR_POOL_SIZE 62
350 static struct objc_selector *selector_pool;
351 static int selector_pool_left;
352
353 static struct objc_selector *
354 pool_alloc_selector(void)
355 {
356 if (!selector_pool_left)
357 {
358 selector_pool = objc_malloc (sizeof (struct objc_selector)
359 * SELECTOR_POOL_SIZE);
360 selector_pool_left = SELECTOR_POOL_SIZE;
361 }
362 return &selector_pool[--selector_pool_left];
363 }
364
365 /* Store the passed selector name in the selector record and return its
366 selector value (value returned by sel_get_uid).
367 Assumes that the calling function has locked down __objc_runtime_mutex. */
368 /* is_const parameter tells us if the name and types parameters
369 are really constant or not. If YES then they are constant and
370 we can just store the pointers. If NO then we need to copy
371 name and types because the pointers may disappear later on. */
372 SEL
373 __sel_register_typed_name (const char *name, const char *types,
374 struct objc_selector *orig, BOOL is_const)
375 {
376 struct objc_selector *j;
377 sidx i;
378 struct objc_list *l;
379
380 i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
381 if (soffset_decode (i) != 0)
382 {
383 for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
384 l; l = l->tail)
385 {
386 SEL s = (SEL) l->head;
387 if (types == 0 || s->sel_types == 0)
388 {
389 if (s->sel_types == types)
390 {
391 if (orig)
392 {
393 orig->sel_id = (void *) i;
394 return orig;
395 }
396 else
397 return s;
398 }
399 }
400 else if (! strcmp (s->sel_types, types))
401 {
402 if (orig)
403 {
404 orig->sel_id = (void *) i;
405 return orig;
406 }
407 else
408 return s;
409 }
410 }
411 if (orig)
412 j = orig;
413 else
414 j = pool_alloc_selector ();
415
416 j->sel_id = (void *) i;
417 /* Can we use the pointer or must copy types? Don't copy if NULL */
418 if ((is_const) || (types == 0))
419 j->sel_types = (const char *) types;
420 else {
421 j->sel_types = (char *) objc_malloc (strlen (types) + 1);
422 strcpy ((char *) j->sel_types, types);
423 }
424 l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
425 }
426 else
427 {
428 __objc_selector_max_index += 1;
429 i = soffset_encode (__objc_selector_max_index);
430 if (orig)
431 j = orig;
432 else
433 j = pool_alloc_selector ();
434
435 j->sel_id = (void *) i;
436 /* Can we use the pointer or must copy types? Don't copy if NULL */
437 if ((is_const) || (types == 0))
438 j->sel_types = (const char *) types;
439 else {
440 j->sel_types = (char *) objc_malloc (strlen (types) + 1);
441 strcpy ((char *) j->sel_types, types);
442 }
443 l = 0;
444 }
445
446 DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", name, types,
447 (long) soffset_decode (i));
448
449 {
450 int is_new = (l == 0);
451 const char *new_name;
452
453 /* Can we use the pointer or must copy name? Don't copy if NULL */
454 if ((is_const) || (name == 0))
455 new_name = name;
456 else {
457 new_name = (char *) objc_malloc (strlen (name) + 1);
458 strcpy ((char *) new_name, name);
459 }
460
461 l = list_cons ((void *) j, l);
462 sarray_at_put_safe (__objc_selector_names, i, (void *) new_name);
463 sarray_at_put_safe (__objc_selector_array, i, (void *) l);
464 if (is_new)
465 objc_hash_add (&__objc_selector_hash, (void *) new_name, (void *) i);
466 }
467
468 sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1);
469
470 return (SEL) j;
471 }
472
473 SEL
474 sel_registerName (const char *name)
475 {
476 SEL ret;
477
478 objc_mutex_lock (__objc_runtime_mutex);
479 /* Assume that name is not constant static memory and needs to be
480 copied before put into a runtime structure. is_const == NO */
481 ret = __sel_register_typed_name (name, 0, 0, NO);
482 objc_mutex_unlock (__objc_runtime_mutex);
483
484 return ret;
485 }
486
487 /* Traditional GNU Objective-C Runtime API. */
488 SEL
489 sel_register_name (const char *name)
490 {
491 return sel_registerName (name);
492 }
493
494 SEL
495 sel_registerTypedName (const char *name, const char *type)
496 {
497 SEL ret;
498
499 objc_mutex_lock (__objc_runtime_mutex);
500 /* Assume that name and type are not constant static memory and need to
501 be copied before put into a runtime structure. is_const == NO */
502 ret = __sel_register_typed_name (name, type, 0, NO);
503 objc_mutex_unlock (__objc_runtime_mutex);
504
505 return ret;
506 }
507
508 SEL
509 sel_register_typed_name (const char *name, const char *type)
510 {
511 return sel_registerTypedName (name, type);
512 }
513
514 /* return selector representing name */
515 SEL
516 sel_getUid (const char *name)
517 {
518 return sel_registerTypedName (name, 0);
519 }
520
521 /* Traditional GNU Objective-C Runtime API. */
522 SEL
523 sel_get_uid (const char *name)
524 {
525 return sel_getUid (name);
526 }