source: trunk/third/gcc/libobjc/selector.c @ 21199

Revision 21199, 12.2 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21198, which included commits to RCS files with non-trunk default branches.
Line 
1/* GNU Objective C Runtime selector related functions
2   Copyright (C) 1993, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
3   Contributed by Kresten Krab Thorup
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under the
8terms of the GNU General Public License as published by the Free Software
9Foundation; either version 2, or (at your option) any later version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14details.
15
16You should have received a copy of the GNU General Public License along with
17GCC; see the file COPYING.  If not, write to the Free Software
18Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20/* As a special exception, if you link this library with files compiled with
21   GCC to produce an executable, this does not cause the resulting executable
22   to be covered by the GNU General Public License. This exception does not
23   however invalidate any other reasons why the executable file might be
24   covered by the GNU General Public License.  */
25
26#include "runtime.h"
27#include "sarray.h"
28#include "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 */
34static struct sarray *__objc_selector_array = 0; /* uid -> sel  !T:MUTEX */
35static struct sarray *__objc_selector_names = 0; /* uid -> name !T:MUTEX */
36static cache_ptr      __objc_selector_hash  = 0; /* name -> uid !T:MUTEX */
37
38static void register_selectors_from_list (MethodList_t);
39
40/* Number of selectors stored in each of the above tables */
41unsigned int __objc_selector_max_index = 0;     /* !T:MUTEX */
42
43void __objc_init_selector_tables ()
44{
45  __objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0);
46  __objc_selector_names = sarray_new (SELECTOR_HASH_SIZE, 0);
47  __objc_selector_hash
48    = hash_new (SELECTOR_HASH_SIZE,
49                (hash_func_type) hash_string,
50                (compare_func_type) compare_strings);
51
52
53/* This routine is given a class and records all of the methods in its class
54   structure in the record table.  */
55void
56__objc_register_selectors_from_class (Class class)
57{
58  MethodList_t method_list;
59
60  method_list = class->methods;
61  while (method_list)
62    {
63      register_selectors_from_list (method_list);
64      method_list = method_list->method_next;
65    }
66}
67
68
69/* This routine is given a list of methods and records each of the methods in
70   the record table.  This is the routine that does the actual recording
71   work.
72
73   This one is only called for Class objects.  For categories,
74   class_add_method_list is called.
75   */
76static void
77register_selectors_from_list (MethodList_t method_list)
78{
79  int i = 0;
80  while (i < method_list->method_count)
81    {
82      Method_t method = &method_list->method_list[i];
83      method->method_name
84        = sel_register_typed_name ((const char *) method->method_name,
85                                   method->method_types);
86      i += 1;
87    }
88}
89
90
91/* Register instance methods as class methods for root classes */
92void __objc_register_instance_methods_to_class (Class class)
93{
94  MethodList_t method_list;
95  MethodList_t class_method_list;
96  int max_methods_no = 16;
97  MethodList_t new_list;
98  Method_t curr_method;
99
100  /* Only if a root class. */
101  if (class->super_class)
102    return;
103
104  /* Allocate a method list to hold the new class methods */
105  new_list = objc_calloc (sizeof (struct objc_method_list)
106                            + sizeof (struct objc_method[max_methods_no]), 1);
107  method_list = class->methods;
108  class_method_list = class->class_pointer->methods;
109  curr_method = &new_list->method_list[0];
110
111  /* Iterate through the method lists for the class */
112  while (method_list)
113    {
114      int i;
115
116      /* Iterate through the methods from this method list */
117      for (i = 0; i < method_list->method_count; i++)
118        {
119          Method_t mth = &method_list->method_list[i];
120          if (mth->method_name
121              && ! search_for_method_in_list (class_method_list,
122                                              mth->method_name))
123            {
124              /* This instance method isn't a class method.
125                  Add it into the new_list. */
126              *curr_method = *mth;
127 
128              /* Reallocate the method list if necessary */
129              if (++new_list->method_count == max_methods_no)
130                new_list =
131                  objc_realloc (new_list, sizeof (struct objc_method_list)
132                                + sizeof (struct
133                                        objc_method[max_methods_no += 16]));
134              curr_method = &new_list->method_list[new_list->method_count];
135            }
136        }
137
138      method_list = method_list->method_next;
139    }
140
141  /* If we created any new class methods
142     then attach the method list to the class */
143  if (new_list->method_count)
144    {
145      new_list =
146        objc_realloc (new_list, sizeof (struct objc_method_list)
147                     + sizeof (struct objc_method[new_list->method_count]));
148      new_list->method_next = class->class_pointer->methods;
149      class->class_pointer->methods = new_list;
150    }
151  else
152    objc_free(new_list);
153
154    __objc_update_dispatch_table_for_class (class->class_pointer);
155}
156
157
158/* Returns YES iff t1 and t2 have same method types, but we ignore
159   the argframe layout */
160BOOL
161sel_types_match (const char *t1, const char *t2)
162{
163  if (! t1 || ! t2)
164    return NO;
165  while (*t1 && *t2)
166    {
167      if (*t1 == '+') t1++;
168      if (*t2 == '+') t2++;
169      while (isdigit ((unsigned char) *t1)) t1++;
170      while (isdigit ((unsigned char) *t2)) t2++;
171      /* xxx Remove these next two lines when qualifiers are put in
172         all selectors, not just Protocol selectors. */
173      t1 = objc_skip_type_qualifiers (t1);
174      t2 = objc_skip_type_qualifiers (t2);
175      if (! *t1 && ! *t2)
176        return YES;
177      if (*t1 != *t2)
178        return NO;
179      t1++;
180      t2++;
181    }
182  return NO;
183}
184
185/* return selector representing name */
186SEL
187sel_get_typed_uid (const char *name, const char *types)
188{
189  struct objc_list *l;
190  sidx i;
191
192  objc_mutex_lock (__objc_runtime_mutex);
193
194  i = (sidx) hash_value_for_key (__objc_selector_hash, name);
195  if (i == 0)
196    {
197      objc_mutex_unlock (__objc_runtime_mutex);
198      return 0;
199    }
200
201  for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
202       l; l = l->tail)
203    {
204      SEL s = (SEL) l->head;
205      if (types == 0 || s->sel_types == 0)
206        {
207          if (s->sel_types == types)
208            {
209              objc_mutex_unlock (__objc_runtime_mutex);
210              return s;
211            }
212        }
213      else if (sel_types_match (s->sel_types, types))
214        {
215          objc_mutex_unlock (__objc_runtime_mutex);
216          return s;
217        }
218    }
219
220  objc_mutex_unlock (__objc_runtime_mutex);
221  return 0;
222}
223
224/* Return selector representing name; prefer a selector with non-NULL type */
225SEL
226sel_get_any_typed_uid (const char *name)
227{
228  struct objc_list *l;
229  sidx i;
230  SEL s = NULL;
231
232  objc_mutex_lock (__objc_runtime_mutex);
233
234  i = (sidx) hash_value_for_key (__objc_selector_hash, name);
235  if (i == 0)
236    {
237      objc_mutex_unlock (__objc_runtime_mutex);
238      return 0;
239    }
240
241  for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
242       l; l = l->tail)
243    {
244      s = (SEL) l->head;
245      if (s->sel_types)
246        {
247            objc_mutex_unlock (__objc_runtime_mutex);
248            return s;
249        }
250    }
251
252  objc_mutex_unlock (__objc_runtime_mutex);
253  return s;
254}
255
256/* return selector representing name */
257SEL
258sel_get_any_uid (const char *name)
259{
260  struct objc_list *l;
261  sidx i;
262
263  objc_mutex_lock (__objc_runtime_mutex);
264
265  i = (sidx) hash_value_for_key (__objc_selector_hash, name);
266  if (soffset_decode (i) == 0)
267    {
268      objc_mutex_unlock (__objc_runtime_mutex);
269      return 0;
270    }
271
272  l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
273  objc_mutex_unlock (__objc_runtime_mutex);
274
275  if (l == 0)
276    return 0;
277
278  return (SEL) l->head;
279}
280
281/* return selector representing name */
282SEL
283sel_get_uid (const char *name)
284{
285  return sel_register_typed_name (name, 0);
286}
287
288/* Get name of selector.  If selector is unknown, the empty string ""
289   is returned */
290const char *sel_get_name (SEL selector)
291{
292  const char *ret;
293
294  objc_mutex_lock (__objc_runtime_mutex);
295  if ((soffset_decode ((sidx)selector->sel_id) > 0)
296      && (soffset_decode ((sidx)selector->sel_id) <= __objc_selector_max_index))
297    ret = sarray_get_safe (__objc_selector_names, (sidx) selector->sel_id);
298  else
299    ret = 0;
300  objc_mutex_unlock (__objc_runtime_mutex);
301  return ret;
302}
303
304BOOL
305sel_is_mapped (SEL selector)
306{
307  unsigned int idx = soffset_decode ((sidx)selector->sel_id);
308  return ((idx > 0) && (idx <= __objc_selector_max_index));
309}
310
311
312const char *sel_get_type (SEL selector)
313{
314  if (selector)
315    return selector->sel_types;
316  else
317    return 0;
318}
319
320/* The uninstalled dispatch table */
321extern struct sarray *__objc_uninstalled_dtable;
322
323/* Store the passed selector name in the selector record and return its
324   selector value (value returned by sel_get_uid).
325   Assumes that the calling function has locked down __objc_runtime_mutex. */
326/* is_const parameter tells us if the name and types parameters
327   are really constant or not.  If YES then they are constant and
328   we can just store the pointers.  If NO then we need to copy
329   name and types because the pointers may disappear later on. */
330SEL
331__sel_register_typed_name (const char *name, const char *types,
332                           struct objc_selector *orig, BOOL is_const)
333{
334  struct objc_selector *j;
335  sidx i;
336  struct objc_list *l;
337
338  i = (sidx) hash_value_for_key (__objc_selector_hash, name);
339  if (soffset_decode (i) != 0)
340    {
341      for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
342           l; l = l->tail)
343        {
344          SEL s = (SEL) l->head;
345          if (types == 0 || s->sel_types == 0)
346            {
347              if (s->sel_types == types)
348                {
349                  if (orig)
350                    {
351                      orig->sel_id = (void *) i;
352                      return orig;
353                    }
354                  else
355                    return s;
356                }
357            }
358          else if (! strcmp (s->sel_types, types))
359            {
360              if (orig)
361                {
362                  orig->sel_id = (void *) i;
363                  return orig;
364                }
365              else
366                return s;
367            }
368        }
369      if (orig)
370        j = orig;
371      else
372        j = objc_malloc (sizeof (struct objc_selector));
373
374      j->sel_id = (void *) i;
375      /* Can we use the pointer or must copy types?  Don't copy if NULL */
376      if ((is_const) || (types == 0))
377        j->sel_types = (const char *) types;
378      else {
379        j->sel_types = (char *) objc_malloc (strlen (types) + 1);
380        strcpy ((char *) j->sel_types, types);
381      }
382      l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
383    }
384  else
385    {
386      __objc_selector_max_index += 1;
387      i = soffset_encode (__objc_selector_max_index);
388      if (orig)
389        j = orig;
390      else
391        j = objc_malloc (sizeof (struct objc_selector));
392       
393      j->sel_id = (void *) i;
394      /* Can we use the pointer or must copy types?  Don't copy if NULL */
395      if ((is_const) || (types == 0))
396        j->sel_types = (const char *) types;
397      else {
398        j->sel_types = (char *) objc_malloc (strlen (types) + 1);
399        strcpy ((char *) j->sel_types, types);
400      }
401      l = 0;
402    }
403
404  DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", name, types,
405                soffset_decode (i));
406 
407  {
408    int is_new = (l == 0);
409    const char *new_name;
410
411    /* Can we use the pointer or must copy name?  Don't copy if NULL */
412    if ((is_const) || (name == 0))
413      new_name = name;
414    else {
415      new_name = (char *) objc_malloc (strlen (name) + 1);
416      strcpy ((char *) new_name, name);
417    }
418
419    l = list_cons ((void *) j, l);
420    sarray_at_put_safe (__objc_selector_names, i, (void *) new_name);
421    sarray_at_put_safe (__objc_selector_array, i, (void *) l);
422    if (is_new)
423      hash_add (&__objc_selector_hash, (void *) new_name, (void *) i);
424  }
425
426  sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1);
427
428  return (SEL) j;
429}
430
431SEL
432sel_register_name (const char *name)
433{
434  SEL ret;
435   
436  objc_mutex_lock (__objc_runtime_mutex);
437  /* Assume that name is not constant static memory and needs to be
438     copied before put into a runtime structure.  is_const == NO */
439  ret = __sel_register_typed_name (name, 0, 0, NO);
440  objc_mutex_unlock (__objc_runtime_mutex);
441 
442  return ret;
443}
444
445SEL
446sel_register_typed_name (const char *name, const char *type)
447{
448  SEL ret;
449   
450  objc_mutex_lock (__objc_runtime_mutex);
451  /* Assume that name and type are not constant static memory and need to
452     be copied before put into a runtime structure.  is_const == NO */
453  ret = __sel_register_typed_name (name, type, 0, NO);
454  objc_mutex_unlock (__objc_runtime_mutex);
455 
456  return ret;
457}
Note: See TracBrowser for help on using the repository browser.