Home | History | Annotate | Line # | Download | only in libobjc
      1 /* GNU Objective C Runtime selector related functions
      2    Copyright (C) 1993-2022 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/runtime.h"
     27 #include "objc/thr.h"
     28 #include "objc-private/hash.h"
     29 #include "objc-private/objc-list.h"
     30 #include "objc-private/module-abi-8.h"
     31 #include "objc-private/runtime.h"
     32 #include "objc-private/sarray.h"
     33 #include "objc-private/selector.h"
     34 #include <stdlib.h>                    /* For malloc.  */
     35 
     36 /* Initial selector hash table size. Value doesn't matter much.  */
     37 #define SELECTOR_HASH_SIZE 128
     38 
     39 /* Tables mapping selector names to uid and opposite.  */
     40 static struct sarray *__objc_selector_array = 0; /* uid -> sel  !T:MUTEX */
     41 static struct sarray *__objc_selector_names = 0; /* uid -> name !T:MUTEX */
     42 static cache_ptr      __objc_selector_hash  = 0; /* name -> uid !T:MUTEX */
     43 
     44 /* Number of selectors stored in each of the above tables.  */
     45 unsigned int __objc_selector_max_index = 0;     /* !T:MUTEX */
     46 
     47 /* Forward-declare an internal function.  */
     48 static SEL
     49 __sel_register_typed_name (const char *name, const char *types,
     50 			   struct objc_selector *orig, BOOL is_const);
     51 
     52 void __objc_init_selector_tables (void)
     53 {
     54   __objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0);
     55   __objc_selector_names = sarray_new (SELECTOR_HASH_SIZE, 0);
     56   __objc_selector_hash
     57     = objc_hash_new (SELECTOR_HASH_SIZE,
     58 		     (hash_func_type) objc_hash_string,
     59 		     (compare_func_type) objc_compare_strings);
     60 }
     61 
     62 /* Register a bunch of selectors from the table of selectors in a
     63    module.  'selectors' should not be NULL.  The list is terminated by
     64    a selectors with a NULL sel_id.  The selectors are assumed to
     65    contain the 'name' in the sel_id field; this is replaced with the
     66    final selector id after they are registered.  */
     67 void
     68 __objc_register_selectors_from_module (struct objc_selector *selectors)
     69 {
     70   int i;
     71 
     72   for (i = 0; selectors[i].sel_id; ++i)
     73     {
     74       const char *name, *type;
     75       name = (char *) selectors[i].sel_id;
     76       type = (char *) selectors[i].sel_types;
     77       /* Constructors are constant static data and we can safely store
     78 	 pointers to them in the runtime structures, so we set
     79 	 is_const == YES.  */
     80       __sel_register_typed_name (name, type, (struct objc_selector *) &(selectors[i]),
     81 				 /* is_const */ YES);
     82     }
     83 }
     84 
     85 /* This routine is given a class and records all of the methods in its
     86    class structure in the record table.  */
     87 void
     88 __objc_register_selectors_from_class (Class class)
     89 {
     90   struct objc_method_list * method_list;
     91 
     92   method_list = class->methods;
     93   while (method_list)
     94     {
     95       __objc_register_selectors_from_list (method_list);
     96       method_list = method_list->method_next;
     97     }
     98 }
     99 
    100 
    101 /* This routine is given a list of methods and records each of the
    102    methods in the record table.  This is the routine that does the
    103    actual recording work.
    104 
    105    The name and type pointers in the method list must be permanent and
    106    immutable.  */
    107 void
    108 __objc_register_selectors_from_list (struct objc_method_list *method_list)
    109 {
    110   int i = 0;
    111 
    112   objc_mutex_lock (__objc_runtime_mutex);
    113   while (i < method_list->method_count)
    114     {
    115       Method method = &method_list->method_list[i];
    116       if (method->method_name)
    117 	{
    118 	  method->method_name
    119 	    = __sel_register_typed_name ((const char *) method->method_name,
    120 					 method->method_types, 0, YES);
    121 	}
    122       i += 1;
    123     }
    124   objc_mutex_unlock (__objc_runtime_mutex);
    125 }
    126 
    127 /* The same as __objc_register_selectors_from_list, but works on a
    128    struct objc_method_description_list* instead of a struct
    129    objc_method_list*.  This is only used for protocols, which have
    130    lists of method descriptions, not methods.  */
    131 void
    132 __objc_register_selectors_from_description_list
    133 (struct objc_method_description_list *method_list)
    134 {
    135   int i = 0;
    136 
    137   objc_mutex_lock (__objc_runtime_mutex);
    138   while (i < method_list->count)
    139     {
    140       struct objc_method_description *method = &method_list->list[i];
    141       if (method->name)
    142 	{
    143 	  method->name
    144 	    = __sel_register_typed_name ((const char *) method->name,
    145 					 method->types, 0, YES);
    146 	}
    147       i += 1;
    148     }
    149   objc_mutex_unlock (__objc_runtime_mutex);
    150 }
    151 
    152 /* Register instance methods as class methods for root classes.  */
    153 void __objc_register_instance_methods_to_class (Class class)
    154 {
    155   struct objc_method_list *method_list;
    156   struct objc_method_list *class_method_list;
    157   int max_methods_no = 16;
    158   struct objc_method_list *new_list;
    159   Method curr_method;
    160 
    161   /* Only if a root class. */
    162   if (class->super_class)
    163     return;
    164 
    165   /* Allocate a method list to hold the new class methods.  */
    166   new_list = objc_calloc (sizeof (struct objc_method_list)
    167 			  + sizeof (struct objc_method[max_methods_no]), 1);
    168   method_list = class->methods;
    169   class_method_list = class->class_pointer->methods;
    170   curr_method = &new_list->method_list[0];
    171 
    172   /* Iterate through the method lists for the class.  */
    173   while (method_list)
    174     {
    175       int i;
    176 
    177       /* Iterate through the methods from this method list.  */
    178       for (i = 0; i < method_list->method_count; i++)
    179 	{
    180 	  Method mth = &method_list->method_list[i];
    181 	  if (mth->method_name
    182 	      && ! search_for_method_in_list (class_method_list,
    183 					      mth->method_name))
    184 	    {
    185 	      /* This instance method isn't a class method.  Add it
    186 		 into the new_list. */
    187 	      *curr_method = *mth;
    188 
    189 	      /* Reallocate the method list if necessary.  */
    190 	      if (++new_list->method_count == max_methods_no)
    191 		new_list =
    192 		  objc_realloc (new_list, sizeof (struct objc_method_list)
    193 				+ sizeof (struct
    194 					  objc_method[max_methods_no += 16]));
    195 	      curr_method = &new_list->method_list[new_list->method_count];
    196 	    }
    197 	}
    198 
    199       method_list = method_list->method_next;
    200     }
    201 
    202   /* If we created any new class methods then attach the method list
    203      to the class.  */
    204   if (new_list->method_count)
    205     {
    206       new_list =
    207  	objc_realloc (new_list, sizeof (struct objc_method_list)
    208 		      + sizeof (struct objc_method[new_list->method_count]));
    209       new_list->method_next = class->class_pointer->methods;
    210       class->class_pointer->methods = new_list;
    211     }
    212   else
    213     objc_free(new_list);
    214 
    215   __objc_update_dispatch_table_for_class (class->class_pointer);
    216 }
    217 
    218 BOOL
    219 sel_isEqual (SEL s1, SEL s2)
    220 {
    221   if (s1 == 0 || s2 == 0)
    222     return s1 == s2;
    223   else
    224     return s1->sel_id == s2->sel_id;
    225 }
    226 
    227 /* Return YES iff t1 and t2 have same method types.  Ignore the
    228    argframe layout.  */
    229 static BOOL
    230 sel_types_match (const char *t1, const char *t2)
    231 {
    232   if (! t1 || ! t2)
    233     return NO;
    234   while (*t1 && *t2)
    235     {
    236       if (*t1 == '+') t1++;
    237       if (*t2 == '+') t2++;
    238       while (isdigit ((unsigned char) *t1)) t1++;
    239       while (isdigit ((unsigned char) *t2)) t2++;
    240       /* xxx Remove these next two lines when qualifiers are put in
    241 	 all selectors, not just Protocol selectors.  */
    242       t1 = objc_skip_type_qualifiers (t1);
    243       t2 = objc_skip_type_qualifiers (t2);
    244       if (! *t1 && ! *t2)
    245 	return YES;
    246       if (*t1 != *t2)
    247 	return NO;
    248       t1++;
    249       t2++;
    250     }
    251   return NO;
    252 }
    253 
    254 /* Return selector representing name.  */
    255 SEL
    256 sel_get_any_uid (const char *name)
    257 {
    258   struct objc_list *l;
    259   sidx i;
    260 
    261   objc_mutex_lock (__objc_runtime_mutex);
    262 
    263   i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
    264   if (soffset_decode (i) == 0)
    265     {
    266       objc_mutex_unlock (__objc_runtime_mutex);
    267       return 0;
    268     }
    269 
    270   l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
    271   objc_mutex_unlock (__objc_runtime_mutex);
    272 
    273   if (l == 0)
    274     return 0;
    275 
    276   return (SEL) l->head;
    277 }
    278 
    279 SEL
    280 sel_getTypedSelector (const char *name)
    281 {
    282   sidx i;
    283 
    284   if (name == NULL)
    285     return NULL;
    286 
    287   objc_mutex_lock (__objc_runtime_mutex);
    288 
    289   /* Look for a typed selector.  */
    290   i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
    291   if (i != 0)
    292     {
    293       struct objc_list *l;
    294       SEL returnValue = NULL;
    295 
    296       for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
    297 	   l; l = l->tail)
    298 	{
    299 	  SEL s = (SEL) l->head;
    300 	  if (s->sel_types)
    301 	    {
    302 	      if (returnValue == NULL)
    303 		{
    304 		  /* First typed selector that we find.  Keep it in
    305 		     returnValue, but keep checking as we want to
    306 		     detect conflicts.  */
    307 		  returnValue = s;
    308 		}
    309 	      else
    310 		{
    311 		  /* We had already found a typed selectors, so we
    312 		     have multiple ones.  Double-check that they have
    313 		     different types, just in case for some reason we
    314 		     got duplicates with the same types.  If so, it's
    315 		     OK, we'll ignore the duplicate.  */
    316 		  if (returnValue->sel_types == s->sel_types)
    317 		    continue;
    318 		  else if (sel_types_match (returnValue->sel_types, s->sel_types))
    319 		    continue;
    320 		  else
    321 		    {
    322 		      /* The types of the two selectors are different;
    323 			 it's a conflict.  Too bad.  Return NULL.  */
    324 		      objc_mutex_unlock (__objc_runtime_mutex);
    325 		      return NULL;
    326 		    }
    327 		}
    328 	    }
    329 	}
    330 
    331       if (returnValue != NULL)
    332 	{
    333 	  objc_mutex_unlock (__objc_runtime_mutex);
    334 	  return returnValue;
    335 	}
    336     }
    337 
    338   /* No typed selector found.  Return NULL.  */
    339   objc_mutex_unlock (__objc_runtime_mutex);
    340   return 0;
    341 }
    342 
    343 SEL *
    344 sel_copyTypedSelectorList (const char *name, unsigned int *numberOfReturnedSelectors)
    345 {
    346   unsigned int count = 0;
    347   SEL *returnValue = NULL;
    348   sidx i;
    349 
    350   if (name == NULL)
    351     {
    352       if (numberOfReturnedSelectors)
    353 	*numberOfReturnedSelectors = 0;
    354       return NULL;
    355     }
    356 
    357   objc_mutex_lock (__objc_runtime_mutex);
    358 
    359   /* Count how many selectors we have.  */
    360   i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
    361   if (i != 0)
    362     {
    363       struct objc_list *selector_list = NULL;
    364       selector_list = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
    365 
    366       /* Count how many selectors we have.  */
    367       {
    368 	struct objc_list *l;
    369 	for (l = selector_list; l; l = l->tail)
    370 	  count++;
    371       }
    372 
    373       if (count != 0)
    374 	{
    375 	  /* Allocate enough memory to hold them.  */
    376 	  returnValue = (SEL *)(malloc (sizeof (SEL) * (count + 1)));
    377 
    378 	  /* Copy the selectors.  */
    379 	  {
    380 	    unsigned int j;
    381 	    for (j = 0; j < count; j++)
    382 	      {
    383 		returnValue[j] = (SEL)(selector_list->head);
    384 		selector_list = selector_list->tail;
    385 	      }
    386 	    returnValue[j] = NULL;
    387 	  }
    388 	}
    389     }
    390 
    391   objc_mutex_unlock (__objc_runtime_mutex);
    392 
    393   if (numberOfReturnedSelectors)
    394     *numberOfReturnedSelectors = count;
    395 
    396   return returnValue;
    397 }
    398 
    399 /* Get the name of a selector.  If the selector is unknown, the empty
    400    string "" is returned.  */
    401 const char *sel_getName (SEL selector)
    402 {
    403   const char *ret;
    404 
    405   if (selector == NULL)
    406     return "<null selector>";
    407 
    408   objc_mutex_lock (__objc_runtime_mutex);
    409   if ((soffset_decode ((sidx)selector->sel_id) > 0)
    410       && (soffset_decode ((sidx)selector->sel_id) <= __objc_selector_max_index))
    411     ret = sarray_get_safe (__objc_selector_names, (sidx) selector->sel_id);
    412   else
    413     ret = 0;
    414   objc_mutex_unlock (__objc_runtime_mutex);
    415   return ret;
    416 }
    417 
    418 BOOL
    419 sel_is_mapped (SEL selector)
    420 {
    421   unsigned int idx = soffset_decode ((sidx)selector->sel_id);
    422   return ((idx > 0) && (idx <= __objc_selector_max_index));
    423 }
    424 
    425 const char *sel_getTypeEncoding (SEL selector)
    426 {
    427   if (selector)
    428     return selector->sel_types;
    429   else
    430     return 0;
    431 }
    432 
    433 /* The uninstalled dispatch table.  */
    434 extern struct sarray *__objc_uninstalled_dtable;
    435 
    436 /* __sel_register_typed_name allocates lots of struct objc_selector:s
    437    of 8 (16, if pointers are 64 bits) bytes at startup. To reduce the
    438    number of malloc calls and memory lost to malloc overhead, we
    439    allocate objc_selector:s in blocks here. This is only called from
    440    __sel_register_typed_name, and __sel_register_typed_name may only
    441    be called when __objc_runtime_mutex is locked.
    442 
    443    Note that the objc_selector:s allocated from
    444    __sel_register_typed_name are never freed.
    445 
    446    62 because 62 * sizeof (struct objc_selector) = 496 (992). This
    447    should let malloc add some overhead and use a nice, round 512
    448    (1024) byte chunk.  */
    449 #define SELECTOR_POOL_SIZE 62
    450 static struct objc_selector *selector_pool;
    451 static int selector_pool_left;
    452 
    453 static struct objc_selector *
    454 pool_alloc_selector(void)
    455 {
    456   if (!selector_pool_left)
    457     {
    458       selector_pool = objc_malloc (sizeof (struct objc_selector)
    459 				   * SELECTOR_POOL_SIZE);
    460       selector_pool_left = SELECTOR_POOL_SIZE;
    461     }
    462   return &selector_pool[--selector_pool_left];
    463 }
    464 
    465 /* Store the passed selector name in the selector record and return
    466    its selector value (value returned by sel_get_uid).  Assume that
    467    the calling function has locked down __objc_runtime_mutex.  The
    468    'is_const' parameter tells us if the name and types parameters are
    469    really constant or not.  If YES then they are constant and we can
    470    just store the pointers.  If NO then we need to copy name and types
    471    because the pointers may disappear later on.  If the 'orig'
    472    parameter is not NULL, then we are registering a selector from a
    473    module, and 'orig' is that selector.  In this case, we can put the
    474    selector in the tables if needed, and orig->sel_id is updated with
    475    the selector ID of the registered selector, and 'orig' is
    476    returned.  */
    477 static SEL
    478 __sel_register_typed_name (const char *name, const char *types,
    479 			   struct objc_selector *orig, BOOL is_const)
    480 {
    481   struct objc_selector *j;
    482   sidx i;
    483   struct objc_list *l;
    484 
    485   i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
    486   if (soffset_decode (i) != 0)
    487     {
    488       /* There are already selectors with that name.  Examine them to
    489 	 see if the one we're registering already exists.  */
    490       for (l = (struct objc_list *)sarray_get_safe (__objc_selector_array, i);
    491 	   l; l = l->tail)
    492 	{
    493 	  SEL s = (SEL)l->head;
    494 	  if (types == 0 || s->sel_types == 0)
    495 	    {
    496 	      if (s->sel_types == types)
    497 		{
    498 		  if (orig)
    499 		    {
    500 		      orig->sel_id = (void *)i;
    501 		      return orig;
    502 		    }
    503 		  else
    504 		    return s;
    505 		}
    506 	    }
    507 	  else if (sel_types_match (s->sel_types, types))
    508 	    {
    509 	      if (orig)
    510 		{
    511 		  orig->sel_id = (void *)i;
    512 		  return orig;
    513 		}
    514 	      else
    515 		return s;
    516 	    }
    517 	}
    518       /* A selector with this specific name/type combination does not
    519 	 exist yet.  We need to register it.  */
    520       if (orig)
    521 	j = orig;
    522       else
    523 	j = pool_alloc_selector ();
    524 
    525       j->sel_id = (void *)i;
    526       /* Can we use the pointer or must we copy types ?  Don't copy if
    527 	 NULL.  */
    528       if ((is_const) || (types == 0))
    529 	j->sel_types = types;
    530       else
    531 	{
    532 	  j->sel_types = (char *)objc_malloc (strlen (types) + 1);
    533 	  strcpy ((char *)j->sel_types, types);
    534 	}
    535       l = (struct objc_list *)sarray_get_safe (__objc_selector_array, i);
    536     }
    537   else
    538     {
    539       /* There are no other selectors with this name registered in the
    540 	 runtime tables.  */
    541       const char *new_name;
    542 
    543       /* Determine i.  */
    544       __objc_selector_max_index += 1;
    545       i = soffset_encode (__objc_selector_max_index);
    546 
    547       /* Prepare the selector.  */
    548       if (orig)
    549 	j = orig;
    550       else
    551 	j = pool_alloc_selector ();
    552 
    553       j->sel_id = (void *)i;
    554       /* Can we use the pointer or must we copy types ?  Don't copy if
    555 	 NULL.  */
    556       if (is_const || (types == 0))
    557 	j->sel_types = types;
    558       else
    559 	{
    560 	  j->sel_types = (char *)objc_malloc (strlen (types) + 1);
    561 	  strcpy ((char *)j->sel_types, types);
    562 	}
    563 
    564       /* Since this is the first selector with this name, we need to
    565 	 register the correspondence between 'i' (the sel_id) and
    566 	 'name' (the actual string) in __objc_selector_names and
    567 	 __objc_selector_hash.  */
    568 
    569       /* Can we use the pointer or must we copy name ?  Don't copy if
    570 	 NULL.  (FIXME: Can the name really be NULL here ?)  */
    571       if (is_const || (name == 0))
    572 	new_name = name;
    573       else
    574 	{
    575 	  new_name = (char *)objc_malloc (strlen (name) + 1);
    576 	  strcpy ((char *)new_name, name);
    577 	}
    578 
    579       /* This maps the sel_id to the name.  */
    580       sarray_at_put_safe (__objc_selector_names, i, (void *)new_name);
    581 
    582       /* This maps the name to the sel_id.  */
    583       objc_hash_add (&__objc_selector_hash, (void *)new_name, (void *)i);
    584 
    585       l = 0;
    586     }
    587 
    588   DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", name, types,
    589 		(long)soffset_decode (i));
    590 
    591   /* Now add the selector to the list of selectors with that id.  */
    592   l = list_cons ((void *)j, l);
    593   sarray_at_put_safe (__objc_selector_array, i, (void *)l);
    594 
    595   sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1);
    596 
    597   return (SEL)j;
    598 }
    599 
    600 SEL
    601 sel_registerName (const char *name)
    602 {
    603   SEL ret;
    604 
    605   if (name == NULL)
    606     return NULL;
    607 
    608   objc_mutex_lock (__objc_runtime_mutex);
    609   /* Assume that name is not constant static memory and needs to be
    610      copied before put into a runtime structure.  is_const == NO.  */
    611   ret = __sel_register_typed_name (name, 0, 0, NO);
    612   objc_mutex_unlock (__objc_runtime_mutex);
    613 
    614   return ret;
    615 }
    616 
    617 SEL
    618 sel_registerTypedName (const char *name, const char *type)
    619 {
    620   SEL ret;
    621 
    622   if (name == NULL)
    623     return NULL;
    624 
    625   objc_mutex_lock (__objc_runtime_mutex);
    626   /* Assume that name and type are not constant static memory and need
    627      to be copied before put into a runtime structure.  is_const ==
    628      NO.  */
    629   ret = __sel_register_typed_name (name, type, 0, NO);
    630   objc_mutex_unlock (__objc_runtime_mutex);
    631 
    632   return ret;
    633 }
    634 
    635 /* Return the selector representing name.  */
    636 SEL
    637 sel_getUid (const char *name)
    638 {
    639   return sel_registerTypedName (name, 0);
    640 }
    641