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