136ac495dSmrg /* GNU Objective C Runtime selector related functions
2*8feb0f0bSmrg Copyright (C) 1993-2020 Free Software Foundation, Inc.
336ac495dSmrg Contributed by Kresten Krab Thorup
436ac495dSmrg
536ac495dSmrg This file is part of GCC.
636ac495dSmrg
736ac495dSmrg GCC is free software; you can redistribute it and/or modify it under the
836ac495dSmrg terms of the GNU General Public License as published by the Free Software
936ac495dSmrg Foundation; either version 3, or (at your option) any later version.
1036ac495dSmrg
1136ac495dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1236ac495dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1336ac495dSmrg FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1436ac495dSmrg details.
1536ac495dSmrg
1636ac495dSmrg Under Section 7 of GPL version 3, you are granted additional
1736ac495dSmrg permissions described in the GCC Runtime Library Exception, version
1836ac495dSmrg 3.1, as published by the Free Software Foundation.
1936ac495dSmrg
2036ac495dSmrg You should have received a copy of the GNU General Public License and
2136ac495dSmrg a copy of the GCC Runtime Library Exception along with this program;
2236ac495dSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
2336ac495dSmrg <http://www.gnu.org/licenses/>. */
2436ac495dSmrg
2536ac495dSmrg #include "objc-private/common.h"
2636ac495dSmrg #include "objc/runtime.h"
2736ac495dSmrg #include "objc/thr.h"
2836ac495dSmrg #include "objc-private/hash.h"
2936ac495dSmrg #include "objc-private/objc-list.h"
3036ac495dSmrg #include "objc-private/module-abi-8.h"
3136ac495dSmrg #include "objc-private/runtime.h"
3236ac495dSmrg #include "objc-private/sarray.h"
3336ac495dSmrg #include "objc-private/selector.h"
3436ac495dSmrg #include <stdlib.h> /* For malloc. */
3536ac495dSmrg
3636ac495dSmrg /* Initial selector hash table size. Value doesn't matter much. */
3736ac495dSmrg #define SELECTOR_HASH_SIZE 128
3836ac495dSmrg
3936ac495dSmrg /* Tables mapping selector names to uid and opposite. */
4036ac495dSmrg static struct sarray *__objc_selector_array = 0; /* uid -> sel !T:MUTEX */
4136ac495dSmrg static struct sarray *__objc_selector_names = 0; /* uid -> name !T:MUTEX */
4236ac495dSmrg static cache_ptr __objc_selector_hash = 0; /* name -> uid !T:MUTEX */
4336ac495dSmrg
4436ac495dSmrg /* Number of selectors stored in each of the above tables. */
4536ac495dSmrg unsigned int __objc_selector_max_index = 0; /* !T:MUTEX */
4636ac495dSmrg
4736ac495dSmrg /* Forward-declare an internal function. */
4836ac495dSmrg static SEL
4936ac495dSmrg __sel_register_typed_name (const char *name, const char *types,
5036ac495dSmrg struct objc_selector *orig, BOOL is_const);
5136ac495dSmrg
__objc_init_selector_tables(void)5236ac495dSmrg void __objc_init_selector_tables (void)
5336ac495dSmrg {
5436ac495dSmrg __objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0);
5536ac495dSmrg __objc_selector_names = sarray_new (SELECTOR_HASH_SIZE, 0);
5636ac495dSmrg __objc_selector_hash
5736ac495dSmrg = objc_hash_new (SELECTOR_HASH_SIZE,
5836ac495dSmrg (hash_func_type) objc_hash_string,
5936ac495dSmrg (compare_func_type) objc_compare_strings);
6036ac495dSmrg }
6136ac495dSmrg
6236ac495dSmrg /* Register a bunch of selectors from the table of selectors in a
6336ac495dSmrg module. 'selectors' should not be NULL. The list is terminated by
6436ac495dSmrg a selectors with a NULL sel_id. The selectors are assumed to
6536ac495dSmrg contain the 'name' in the sel_id field; this is replaced with the
6636ac495dSmrg final selector id after they are registered. */
6736ac495dSmrg void
__objc_register_selectors_from_module(struct objc_selector * selectors)6836ac495dSmrg __objc_register_selectors_from_module (struct objc_selector *selectors)
6936ac495dSmrg {
7036ac495dSmrg int i;
7136ac495dSmrg
7236ac495dSmrg for (i = 0; selectors[i].sel_id; ++i)
7336ac495dSmrg {
7436ac495dSmrg const char *name, *type;
7536ac495dSmrg name = (char *) selectors[i].sel_id;
7636ac495dSmrg type = (char *) selectors[i].sel_types;
7736ac495dSmrg /* Constructors are constant static data and we can safely store
7836ac495dSmrg pointers to them in the runtime structures, so we set
7936ac495dSmrg is_const == YES. */
8036ac495dSmrg __sel_register_typed_name (name, type, (struct objc_selector *) &(selectors[i]),
8136ac495dSmrg /* is_const */ YES);
8236ac495dSmrg }
8336ac495dSmrg }
8436ac495dSmrg
8536ac495dSmrg /* This routine is given a class and records all of the methods in its
8636ac495dSmrg class structure in the record table. */
8736ac495dSmrg void
__objc_register_selectors_from_class(Class class)8836ac495dSmrg __objc_register_selectors_from_class (Class class)
8936ac495dSmrg {
9036ac495dSmrg struct objc_method_list * method_list;
9136ac495dSmrg
9236ac495dSmrg method_list = class->methods;
9336ac495dSmrg while (method_list)
9436ac495dSmrg {
9536ac495dSmrg __objc_register_selectors_from_list (method_list);
9636ac495dSmrg method_list = method_list->method_next;
9736ac495dSmrg }
9836ac495dSmrg }
9936ac495dSmrg
10036ac495dSmrg
10136ac495dSmrg /* This routine is given a list of methods and records each of the
10236ac495dSmrg methods in the record table. This is the routine that does the
10336ac495dSmrg actual recording work.
10436ac495dSmrg
10536ac495dSmrg The name and type pointers in the method list must be permanent and
10636ac495dSmrg immutable. */
10736ac495dSmrg void
__objc_register_selectors_from_list(struct objc_method_list * method_list)10836ac495dSmrg __objc_register_selectors_from_list (struct objc_method_list *method_list)
10936ac495dSmrg {
11036ac495dSmrg int i = 0;
11136ac495dSmrg
11236ac495dSmrg objc_mutex_lock (__objc_runtime_mutex);
11336ac495dSmrg while (i < method_list->method_count)
11436ac495dSmrg {
11536ac495dSmrg Method method = &method_list->method_list[i];
11636ac495dSmrg if (method->method_name)
11736ac495dSmrg {
11836ac495dSmrg method->method_name
11936ac495dSmrg = __sel_register_typed_name ((const char *) method->method_name,
12036ac495dSmrg method->method_types, 0, YES);
12136ac495dSmrg }
12236ac495dSmrg i += 1;
12336ac495dSmrg }
12436ac495dSmrg objc_mutex_unlock (__objc_runtime_mutex);
12536ac495dSmrg }
12636ac495dSmrg
12736ac495dSmrg /* The same as __objc_register_selectors_from_list, but works on a
12836ac495dSmrg struct objc_method_description_list* instead of a struct
12936ac495dSmrg objc_method_list*. This is only used for protocols, which have
13036ac495dSmrg lists of method descriptions, not methods. */
13136ac495dSmrg void
__objc_register_selectors_from_description_list(struct objc_method_description_list * method_list)13236ac495dSmrg __objc_register_selectors_from_description_list
13336ac495dSmrg (struct objc_method_description_list *method_list)
13436ac495dSmrg {
13536ac495dSmrg int i = 0;
13636ac495dSmrg
13736ac495dSmrg objc_mutex_lock (__objc_runtime_mutex);
13836ac495dSmrg while (i < method_list->count)
13936ac495dSmrg {
14036ac495dSmrg struct objc_method_description *method = &method_list->list[i];
14136ac495dSmrg if (method->name)
14236ac495dSmrg {
14336ac495dSmrg method->name
14436ac495dSmrg = __sel_register_typed_name ((const char *) method->name,
14536ac495dSmrg method->types, 0, YES);
14636ac495dSmrg }
14736ac495dSmrg i += 1;
14836ac495dSmrg }
14936ac495dSmrg objc_mutex_unlock (__objc_runtime_mutex);
15036ac495dSmrg }
15136ac495dSmrg
15236ac495dSmrg /* Register instance methods as class methods for root classes. */
__objc_register_instance_methods_to_class(Class class)15336ac495dSmrg void __objc_register_instance_methods_to_class (Class class)
15436ac495dSmrg {
15536ac495dSmrg struct objc_method_list *method_list;
15636ac495dSmrg struct objc_method_list *class_method_list;
15736ac495dSmrg int max_methods_no = 16;
15836ac495dSmrg struct objc_method_list *new_list;
15936ac495dSmrg Method curr_method;
16036ac495dSmrg
16136ac495dSmrg /* Only if a root class. */
16236ac495dSmrg if (class->super_class)
16336ac495dSmrg return;
16436ac495dSmrg
16536ac495dSmrg /* Allocate a method list to hold the new class methods. */
16636ac495dSmrg new_list = objc_calloc (sizeof (struct objc_method_list)
16736ac495dSmrg + sizeof (struct objc_method[max_methods_no]), 1);
16836ac495dSmrg method_list = class->methods;
16936ac495dSmrg class_method_list = class->class_pointer->methods;
17036ac495dSmrg curr_method = &new_list->method_list[0];
17136ac495dSmrg
17236ac495dSmrg /* Iterate through the method lists for the class. */
17336ac495dSmrg while (method_list)
17436ac495dSmrg {
17536ac495dSmrg int i;
17636ac495dSmrg
17736ac495dSmrg /* Iterate through the methods from this method list. */
17836ac495dSmrg for (i = 0; i < method_list->method_count; i++)
17936ac495dSmrg {
18036ac495dSmrg Method mth = &method_list->method_list[i];
18136ac495dSmrg if (mth->method_name
18236ac495dSmrg && ! search_for_method_in_list (class_method_list,
18336ac495dSmrg mth->method_name))
18436ac495dSmrg {
18536ac495dSmrg /* This instance method isn't a class method. Add it
18636ac495dSmrg into the new_list. */
18736ac495dSmrg *curr_method = *mth;
18836ac495dSmrg
18936ac495dSmrg /* Reallocate the method list if necessary. */
19036ac495dSmrg if (++new_list->method_count == max_methods_no)
19136ac495dSmrg new_list =
19236ac495dSmrg objc_realloc (new_list, sizeof (struct objc_method_list)
19336ac495dSmrg + sizeof (struct
19436ac495dSmrg objc_method[max_methods_no += 16]));
19536ac495dSmrg curr_method = &new_list->method_list[new_list->method_count];
19636ac495dSmrg }
19736ac495dSmrg }
19836ac495dSmrg
19936ac495dSmrg method_list = method_list->method_next;
20036ac495dSmrg }
20136ac495dSmrg
20236ac495dSmrg /* If we created any new class methods then attach the method list
20336ac495dSmrg to the class. */
20436ac495dSmrg if (new_list->method_count)
20536ac495dSmrg {
20636ac495dSmrg new_list =
20736ac495dSmrg objc_realloc (new_list, sizeof (struct objc_method_list)
20836ac495dSmrg + sizeof (struct objc_method[new_list->method_count]));
20936ac495dSmrg new_list->method_next = class->class_pointer->methods;
21036ac495dSmrg class->class_pointer->methods = new_list;
21136ac495dSmrg }
21236ac495dSmrg else
21336ac495dSmrg objc_free(new_list);
21436ac495dSmrg
21536ac495dSmrg __objc_update_dispatch_table_for_class (class->class_pointer);
21636ac495dSmrg }
21736ac495dSmrg
21836ac495dSmrg BOOL
sel_isEqual(SEL s1,SEL s2)21936ac495dSmrg sel_isEqual (SEL s1, SEL s2)
22036ac495dSmrg {
22136ac495dSmrg if (s1 == 0 || s2 == 0)
22236ac495dSmrg return s1 == s2;
22336ac495dSmrg else
22436ac495dSmrg return s1->sel_id == s2->sel_id;
22536ac495dSmrg }
22636ac495dSmrg
22736ac495dSmrg /* Return YES iff t1 and t2 have same method types. Ignore the
22836ac495dSmrg argframe layout. */
22936ac495dSmrg static BOOL
sel_types_match(const char * t1,const char * t2)23036ac495dSmrg sel_types_match (const char *t1, const char *t2)
23136ac495dSmrg {
23236ac495dSmrg if (! t1 || ! t2)
23336ac495dSmrg return NO;
23436ac495dSmrg while (*t1 && *t2)
23536ac495dSmrg {
23636ac495dSmrg if (*t1 == '+') t1++;
23736ac495dSmrg if (*t2 == '+') t2++;
23836ac495dSmrg while (isdigit ((unsigned char) *t1)) t1++;
23936ac495dSmrg while (isdigit ((unsigned char) *t2)) t2++;
24036ac495dSmrg /* xxx Remove these next two lines when qualifiers are put in
24136ac495dSmrg all selectors, not just Protocol selectors. */
24236ac495dSmrg t1 = objc_skip_type_qualifiers (t1);
24336ac495dSmrg t2 = objc_skip_type_qualifiers (t2);
24436ac495dSmrg if (! *t1 && ! *t2)
24536ac495dSmrg return YES;
24636ac495dSmrg if (*t1 != *t2)
24736ac495dSmrg return NO;
24836ac495dSmrg t1++;
24936ac495dSmrg t2++;
25036ac495dSmrg }
25136ac495dSmrg return NO;
25236ac495dSmrg }
25336ac495dSmrg
25436ac495dSmrg /* Return selector representing name. */
25536ac495dSmrg SEL
sel_get_any_uid(const char * name)25636ac495dSmrg sel_get_any_uid (const char *name)
25736ac495dSmrg {
25836ac495dSmrg struct objc_list *l;
25936ac495dSmrg sidx i;
26036ac495dSmrg
26136ac495dSmrg objc_mutex_lock (__objc_runtime_mutex);
26236ac495dSmrg
26336ac495dSmrg i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
26436ac495dSmrg if (soffset_decode (i) == 0)
26536ac495dSmrg {
26636ac495dSmrg objc_mutex_unlock (__objc_runtime_mutex);
26736ac495dSmrg return 0;
26836ac495dSmrg }
26936ac495dSmrg
27036ac495dSmrg l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
27136ac495dSmrg objc_mutex_unlock (__objc_runtime_mutex);
27236ac495dSmrg
27336ac495dSmrg if (l == 0)
27436ac495dSmrg return 0;
27536ac495dSmrg
27636ac495dSmrg return (SEL) l->head;
27736ac495dSmrg }
27836ac495dSmrg
27936ac495dSmrg SEL
sel_getTypedSelector(const char * name)28036ac495dSmrg sel_getTypedSelector (const char *name)
28136ac495dSmrg {
28236ac495dSmrg sidx i;
28336ac495dSmrg
28436ac495dSmrg if (name == NULL)
28536ac495dSmrg return NULL;
28636ac495dSmrg
28736ac495dSmrg objc_mutex_lock (__objc_runtime_mutex);
28836ac495dSmrg
28936ac495dSmrg /* Look for a typed selector. */
29036ac495dSmrg i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
29136ac495dSmrg if (i != 0)
29236ac495dSmrg {
29336ac495dSmrg struct objc_list *l;
29436ac495dSmrg SEL returnValue = NULL;
29536ac495dSmrg
29636ac495dSmrg for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
29736ac495dSmrg l; l = l->tail)
29836ac495dSmrg {
29936ac495dSmrg SEL s = (SEL) l->head;
30036ac495dSmrg if (s->sel_types)
30136ac495dSmrg {
30236ac495dSmrg if (returnValue == NULL)
30336ac495dSmrg {
30436ac495dSmrg /* First typed selector that we find. Keep it in
30536ac495dSmrg returnValue, but keep checking as we want to
30636ac495dSmrg detect conflicts. */
30736ac495dSmrg returnValue = s;
30836ac495dSmrg }
30936ac495dSmrg else
31036ac495dSmrg {
31136ac495dSmrg /* We had already found a typed selectors, so we
31236ac495dSmrg have multiple ones. Double-check that they have
31336ac495dSmrg different types, just in case for some reason we
31436ac495dSmrg got duplicates with the same types. If so, it's
31536ac495dSmrg OK, we'll ignore the duplicate. */
31636ac495dSmrg if (returnValue->sel_types == s->sel_types)
31736ac495dSmrg continue;
31836ac495dSmrg else if (sel_types_match (returnValue->sel_types, s->sel_types))
31936ac495dSmrg continue;
32036ac495dSmrg else
32136ac495dSmrg {
32236ac495dSmrg /* The types of the two selectors are different;
32336ac495dSmrg it's a conflict. Too bad. Return NULL. */
32436ac495dSmrg objc_mutex_unlock (__objc_runtime_mutex);
32536ac495dSmrg return NULL;
32636ac495dSmrg }
32736ac495dSmrg }
32836ac495dSmrg }
32936ac495dSmrg }
33036ac495dSmrg
33136ac495dSmrg if (returnValue != NULL)
33236ac495dSmrg {
33336ac495dSmrg objc_mutex_unlock (__objc_runtime_mutex);
33436ac495dSmrg return returnValue;
33536ac495dSmrg }
33636ac495dSmrg }
33736ac495dSmrg
33836ac495dSmrg /* No typed selector found. Return NULL. */
33936ac495dSmrg objc_mutex_unlock (__objc_runtime_mutex);
34036ac495dSmrg return 0;
34136ac495dSmrg }
34236ac495dSmrg
34336ac495dSmrg SEL *
sel_copyTypedSelectorList(const char * name,unsigned int * numberOfReturnedSelectors)34436ac495dSmrg sel_copyTypedSelectorList (const char *name, unsigned int *numberOfReturnedSelectors)
34536ac495dSmrg {
34636ac495dSmrg unsigned int count = 0;
34736ac495dSmrg SEL *returnValue = NULL;
34836ac495dSmrg sidx i;
34936ac495dSmrg
35036ac495dSmrg if (name == NULL)
35136ac495dSmrg {
35236ac495dSmrg if (numberOfReturnedSelectors)
35336ac495dSmrg *numberOfReturnedSelectors = 0;
35436ac495dSmrg return NULL;
35536ac495dSmrg }
35636ac495dSmrg
35736ac495dSmrg objc_mutex_lock (__objc_runtime_mutex);
35836ac495dSmrg
35936ac495dSmrg /* Count how many selectors we have. */
36036ac495dSmrg i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
36136ac495dSmrg if (i != 0)
36236ac495dSmrg {
36336ac495dSmrg struct objc_list *selector_list = NULL;
36436ac495dSmrg selector_list = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
36536ac495dSmrg
36636ac495dSmrg /* Count how many selectors we have. */
36736ac495dSmrg {
36836ac495dSmrg struct objc_list *l;
36936ac495dSmrg for (l = selector_list; l; l = l->tail)
37036ac495dSmrg count++;
37136ac495dSmrg }
37236ac495dSmrg
37336ac495dSmrg if (count != 0)
37436ac495dSmrg {
37536ac495dSmrg /* Allocate enough memory to hold them. */
37636ac495dSmrg returnValue = (SEL *)(malloc (sizeof (SEL) * (count + 1)));
37736ac495dSmrg
37836ac495dSmrg /* Copy the selectors. */
37936ac495dSmrg {
38036ac495dSmrg unsigned int j;
38136ac495dSmrg for (j = 0; j < count; j++)
38236ac495dSmrg {
38336ac495dSmrg returnValue[j] = (SEL)(selector_list->head);
38436ac495dSmrg selector_list = selector_list->tail;
38536ac495dSmrg }
38636ac495dSmrg returnValue[j] = NULL;
38736ac495dSmrg }
38836ac495dSmrg }
38936ac495dSmrg }
39036ac495dSmrg
39136ac495dSmrg objc_mutex_unlock (__objc_runtime_mutex);
39236ac495dSmrg
39336ac495dSmrg if (numberOfReturnedSelectors)
39436ac495dSmrg *numberOfReturnedSelectors = count;
39536ac495dSmrg
39636ac495dSmrg return returnValue;
39736ac495dSmrg }
39836ac495dSmrg
39936ac495dSmrg /* Get the name of a selector. If the selector is unknown, the empty
40036ac495dSmrg string "" is returned. */
sel_getName(SEL selector)40136ac495dSmrg const char *sel_getName (SEL selector)
40236ac495dSmrg {
40336ac495dSmrg const char *ret;
40436ac495dSmrg
40536ac495dSmrg if (selector == NULL)
40636ac495dSmrg return "<null selector>";
40736ac495dSmrg
40836ac495dSmrg objc_mutex_lock (__objc_runtime_mutex);
40936ac495dSmrg if ((soffset_decode ((sidx)selector->sel_id) > 0)
41036ac495dSmrg && (soffset_decode ((sidx)selector->sel_id) <= __objc_selector_max_index))
41136ac495dSmrg ret = sarray_get_safe (__objc_selector_names, (sidx) selector->sel_id);
41236ac495dSmrg else
41336ac495dSmrg ret = 0;
41436ac495dSmrg objc_mutex_unlock (__objc_runtime_mutex);
41536ac495dSmrg return ret;
41636ac495dSmrg }
41736ac495dSmrg
41836ac495dSmrg BOOL
sel_is_mapped(SEL selector)41936ac495dSmrg sel_is_mapped (SEL selector)
42036ac495dSmrg {
42136ac495dSmrg unsigned int idx = soffset_decode ((sidx)selector->sel_id);
42236ac495dSmrg return ((idx > 0) && (idx <= __objc_selector_max_index));
42336ac495dSmrg }
42436ac495dSmrg
sel_getTypeEncoding(SEL selector)42536ac495dSmrg const char *sel_getTypeEncoding (SEL selector)
42636ac495dSmrg {
42736ac495dSmrg if (selector)
42836ac495dSmrg return selector->sel_types;
42936ac495dSmrg else
43036ac495dSmrg return 0;
43136ac495dSmrg }
43236ac495dSmrg
43336ac495dSmrg /* The uninstalled dispatch table. */
43436ac495dSmrg extern struct sarray *__objc_uninstalled_dtable;
43536ac495dSmrg
43636ac495dSmrg /* __sel_register_typed_name allocates lots of struct objc_selector:s
43736ac495dSmrg of 8 (16, if pointers are 64 bits) bytes at startup. To reduce the
43836ac495dSmrg number of malloc calls and memory lost to malloc overhead, we
43936ac495dSmrg allocate objc_selector:s in blocks here. This is only called from
44036ac495dSmrg __sel_register_typed_name, and __sel_register_typed_name may only
44136ac495dSmrg be called when __objc_runtime_mutex is locked.
44236ac495dSmrg
44336ac495dSmrg Note that the objc_selector:s allocated from
44436ac495dSmrg __sel_register_typed_name are never freed.
44536ac495dSmrg
44636ac495dSmrg 62 because 62 * sizeof (struct objc_selector) = 496 (992). This
44736ac495dSmrg should let malloc add some overhead and use a nice, round 512
44836ac495dSmrg (1024) byte chunk. */
44936ac495dSmrg #define SELECTOR_POOL_SIZE 62
45036ac495dSmrg static struct objc_selector *selector_pool;
45136ac495dSmrg static int selector_pool_left;
45236ac495dSmrg
45336ac495dSmrg static struct objc_selector *
pool_alloc_selector(void)45436ac495dSmrg pool_alloc_selector(void)
45536ac495dSmrg {
45636ac495dSmrg if (!selector_pool_left)
45736ac495dSmrg {
45836ac495dSmrg selector_pool = objc_malloc (sizeof (struct objc_selector)
45936ac495dSmrg * SELECTOR_POOL_SIZE);
46036ac495dSmrg selector_pool_left = SELECTOR_POOL_SIZE;
46136ac495dSmrg }
46236ac495dSmrg return &selector_pool[--selector_pool_left];
46336ac495dSmrg }
46436ac495dSmrg
46536ac495dSmrg /* Store the passed selector name in the selector record and return
46636ac495dSmrg its selector value (value returned by sel_get_uid). Assume that
46736ac495dSmrg the calling function has locked down __objc_runtime_mutex. The
46836ac495dSmrg 'is_const' parameter tells us if the name and types parameters are
46936ac495dSmrg really constant or not. If YES then they are constant and we can
47036ac495dSmrg just store the pointers. If NO then we need to copy name and types
47136ac495dSmrg because the pointers may disappear later on. If the 'orig'
47236ac495dSmrg parameter is not NULL, then we are registering a selector from a
47336ac495dSmrg module, and 'orig' is that selector. In this case, we can put the
47436ac495dSmrg selector in the tables if needed, and orig->sel_id is updated with
47536ac495dSmrg the selector ID of the registered selector, and 'orig' is
47636ac495dSmrg returned. */
47736ac495dSmrg static SEL
__sel_register_typed_name(const char * name,const char * types,struct objc_selector * orig,BOOL is_const)47836ac495dSmrg __sel_register_typed_name (const char *name, const char *types,
47936ac495dSmrg struct objc_selector *orig, BOOL is_const)
48036ac495dSmrg {
48136ac495dSmrg struct objc_selector *j;
48236ac495dSmrg sidx i;
48336ac495dSmrg struct objc_list *l;
48436ac495dSmrg
48536ac495dSmrg i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
48636ac495dSmrg if (soffset_decode (i) != 0)
48736ac495dSmrg {
48836ac495dSmrg /* There are already selectors with that name. Examine them to
48936ac495dSmrg see if the one we're registering already exists. */
49036ac495dSmrg for (l = (struct objc_list *)sarray_get_safe (__objc_selector_array, i);
49136ac495dSmrg l; l = l->tail)
49236ac495dSmrg {
49336ac495dSmrg SEL s = (SEL)l->head;
49436ac495dSmrg if (types == 0 || s->sel_types == 0)
49536ac495dSmrg {
49636ac495dSmrg if (s->sel_types == types)
49736ac495dSmrg {
49836ac495dSmrg if (orig)
49936ac495dSmrg {
50036ac495dSmrg orig->sel_id = (void *)i;
50136ac495dSmrg return orig;
50236ac495dSmrg }
50336ac495dSmrg else
50436ac495dSmrg return s;
50536ac495dSmrg }
50636ac495dSmrg }
50736ac495dSmrg else if (sel_types_match (s->sel_types, types))
50836ac495dSmrg {
50936ac495dSmrg if (orig)
51036ac495dSmrg {
51136ac495dSmrg orig->sel_id = (void *)i;
51236ac495dSmrg return orig;
51336ac495dSmrg }
51436ac495dSmrg else
51536ac495dSmrg return s;
51636ac495dSmrg }
51736ac495dSmrg }
51836ac495dSmrg /* A selector with this specific name/type combination does not
51936ac495dSmrg exist yet. We need to register it. */
52036ac495dSmrg if (orig)
52136ac495dSmrg j = orig;
52236ac495dSmrg else
52336ac495dSmrg j = pool_alloc_selector ();
52436ac495dSmrg
52536ac495dSmrg j->sel_id = (void *)i;
52636ac495dSmrg /* Can we use the pointer or must we copy types ? Don't copy if
52736ac495dSmrg NULL. */
52836ac495dSmrg if ((is_const) || (types == 0))
52936ac495dSmrg j->sel_types = types;
53036ac495dSmrg else
53136ac495dSmrg {
53236ac495dSmrg j->sel_types = (char *)objc_malloc (strlen (types) + 1);
53336ac495dSmrg strcpy ((char *)j->sel_types, types);
53436ac495dSmrg }
53536ac495dSmrg l = (struct objc_list *)sarray_get_safe (__objc_selector_array, i);
53636ac495dSmrg }
53736ac495dSmrg else
53836ac495dSmrg {
53936ac495dSmrg /* There are no other selectors with this name registered in the
54036ac495dSmrg runtime tables. */
54136ac495dSmrg const char *new_name;
54236ac495dSmrg
54336ac495dSmrg /* Determine i. */
54436ac495dSmrg __objc_selector_max_index += 1;
54536ac495dSmrg i = soffset_encode (__objc_selector_max_index);
54636ac495dSmrg
54736ac495dSmrg /* Prepare the selector. */
54836ac495dSmrg if (orig)
54936ac495dSmrg j = orig;
55036ac495dSmrg else
55136ac495dSmrg j = pool_alloc_selector ();
55236ac495dSmrg
55336ac495dSmrg j->sel_id = (void *)i;
55436ac495dSmrg /* Can we use the pointer or must we copy types ? Don't copy if
55536ac495dSmrg NULL. */
55636ac495dSmrg if (is_const || (types == 0))
55736ac495dSmrg j->sel_types = types;
55836ac495dSmrg else
55936ac495dSmrg {
56036ac495dSmrg j->sel_types = (char *)objc_malloc (strlen (types) + 1);
56136ac495dSmrg strcpy ((char *)j->sel_types, types);
56236ac495dSmrg }
56336ac495dSmrg
56436ac495dSmrg /* Since this is the first selector with this name, we need to
56536ac495dSmrg register the correspondence between 'i' (the sel_id) and
56636ac495dSmrg 'name' (the actual string) in __objc_selector_names and
56736ac495dSmrg __objc_selector_hash. */
56836ac495dSmrg
56936ac495dSmrg /* Can we use the pointer or must we copy name ? Don't copy if
57036ac495dSmrg NULL. (FIXME: Can the name really be NULL here ?) */
57136ac495dSmrg if (is_const || (name == 0))
57236ac495dSmrg new_name = name;
57336ac495dSmrg else
57436ac495dSmrg {
57536ac495dSmrg new_name = (char *)objc_malloc (strlen (name) + 1);
57636ac495dSmrg strcpy ((char *)new_name, name);
57736ac495dSmrg }
57836ac495dSmrg
57936ac495dSmrg /* This maps the sel_id to the name. */
58036ac495dSmrg sarray_at_put_safe (__objc_selector_names, i, (void *)new_name);
58136ac495dSmrg
58236ac495dSmrg /* This maps the name to the sel_id. */
58336ac495dSmrg objc_hash_add (&__objc_selector_hash, (void *)new_name, (void *)i);
58436ac495dSmrg
58536ac495dSmrg l = 0;
58636ac495dSmrg }
58736ac495dSmrg
58836ac495dSmrg DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", name, types,
58936ac495dSmrg (long)soffset_decode (i));
59036ac495dSmrg
59136ac495dSmrg /* Now add the selector to the list of selectors with that id. */
59236ac495dSmrg l = list_cons ((void *)j, l);
59336ac495dSmrg sarray_at_put_safe (__objc_selector_array, i, (void *)l);
59436ac495dSmrg
59536ac495dSmrg sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1);
59636ac495dSmrg
59736ac495dSmrg return (SEL)j;
59836ac495dSmrg }
59936ac495dSmrg
60036ac495dSmrg SEL
sel_registerName(const char * name)60136ac495dSmrg sel_registerName (const char *name)
60236ac495dSmrg {
60336ac495dSmrg SEL ret;
60436ac495dSmrg
60536ac495dSmrg if (name == NULL)
60636ac495dSmrg return NULL;
60736ac495dSmrg
60836ac495dSmrg objc_mutex_lock (__objc_runtime_mutex);
60936ac495dSmrg /* Assume that name is not constant static memory and needs to be
61036ac495dSmrg copied before put into a runtime structure. is_const == NO. */
61136ac495dSmrg ret = __sel_register_typed_name (name, 0, 0, NO);
61236ac495dSmrg objc_mutex_unlock (__objc_runtime_mutex);
61336ac495dSmrg
61436ac495dSmrg return ret;
61536ac495dSmrg }
61636ac495dSmrg
61736ac495dSmrg SEL
sel_registerTypedName(const char * name,const char * type)61836ac495dSmrg sel_registerTypedName (const char *name, const char *type)
61936ac495dSmrg {
62036ac495dSmrg SEL ret;
62136ac495dSmrg
62236ac495dSmrg if (name == NULL)
62336ac495dSmrg return NULL;
62436ac495dSmrg
62536ac495dSmrg objc_mutex_lock (__objc_runtime_mutex);
62636ac495dSmrg /* Assume that name and type are not constant static memory and need
62736ac495dSmrg to be copied before put into a runtime structure. is_const ==
62836ac495dSmrg NO. */
62936ac495dSmrg ret = __sel_register_typed_name (name, type, 0, NO);
63036ac495dSmrg objc_mutex_unlock (__objc_runtime_mutex);
63136ac495dSmrg
63236ac495dSmrg return ret;
63336ac495dSmrg }
63436ac495dSmrg
63536ac495dSmrg /* Return the selector representing name. */
63636ac495dSmrg SEL
sel_getUid(const char * name)63736ac495dSmrg sel_getUid (const char *name)
63836ac495dSmrg {
63936ac495dSmrg return sel_registerTypedName (name, 0);
64036ac495dSmrg }
641