selector.c 17.8 KB
Newer Older
1
/* GNU Objective C Runtime selector related functions
2
   Copyright (C) 1993-2019 Free Software Foundation, Inc.
3 4
   Contributed by Kresten Krab Thorup

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 13 14 15
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
details.

16 17 18 19 20 21 22 23
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.

You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
<http://www.gnu.org/licenses/>.  */
24

Nicola Pero committed
25
#include "objc-private/common.h"
26
#include "objc/runtime.h"
Nicola Pero committed
27
#include "objc/thr.h"
Nicola Pero committed
28
#include "objc-private/hash.h"
29 30
#include "objc-private/objc-list.h"
#include "objc-private/module-abi-8.h"
Nicola Pero committed
31
#include "objc-private/runtime.h"
Nicola Pero committed
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 38
#define SELECTOR_HASH_SIZE 128

39
/* Tables mapping selector names to uid and opposite.  */
40 41
static struct sarray *__objc_selector_array = 0; /* uid -> sel  !T:MUTEX */
static struct sarray *__objc_selector_names = 0; /* uid -> name !T:MUTEX */
42 43
static cache_ptr      __objc_selector_hash  = 0; /* name -> uid !T:MUTEX */

44
/* Number of selectors stored in each of the above tables.  */
45
unsigned int __objc_selector_max_index = 0;     /* !T:MUTEX */
46

47 48 49 50 51
/* Forward-declare an internal function.  */
static SEL
__sel_register_typed_name (const char *name, const char *types,
			   struct objc_selector *orig, BOOL is_const);

52
void __objc_init_selector_tables (void)
53 54 55 56
{
  __objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0);
  __objc_selector_names = sarray_new (SELECTOR_HASH_SIZE, 0);
  __objc_selector_hash
57 58 59
    = objc_hash_new (SELECTOR_HASH_SIZE,
		     (hash_func_type) objc_hash_string,
		     (compare_func_type) objc_compare_strings);
60 61
}  

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
/* Register a bunch of selectors from the table of selectors in a
   module.  'selectors' should not be NULL.  The list is terminated by
   a selectors with a NULL sel_id.  The selectors are assumed to
   contain the 'name' in the sel_id field; this is replaced with the
   final selector id after they are registered.  */
void
__objc_register_selectors_from_module (struct objc_selector *selectors)
{
  int i;

  for (i = 0; selectors[i].sel_id; ++i)
    {
      const char *name, *type;
      name = (char *) selectors[i].sel_id;
      type = (char *) selectors[i].sel_types;
      /* Constructors are constant static data and we can safely store
	 pointers to them in the runtime structures, so we set
	 is_const == YES.  */
      __sel_register_typed_name (name, type, (struct objc_selector *) &(selectors[i]),
				 /* is_const */ YES);
    }
}

85 86
/* This routine is given a class and records all of the methods in its
   class structure in the record table.  */
87 88 89
void
__objc_register_selectors_from_class (Class class)
{
90
  struct objc_method_list * method_list;
91 92 93 94

  method_list = class->methods;
  while (method_list)
    {
Andrew Pinski committed
95
      __objc_register_selectors_from_list (method_list);
96 97 98 99 100
      method_list = method_list->method_next;
    }
}


101 102 103
/* This routine is given a list of methods and records each of the
   methods in the record table.  This is the routine that does the
   actual recording work.
104

Andrew Pinski committed
105
   The name and type pointers in the method list must be permanent and
106
   immutable.  */
Andrew Pinski committed
107
void
108
__objc_register_selectors_from_list (struct objc_method_list *method_list)
109 110
{
  int i = 0;
Andrew Pinski committed
111 112

  objc_mutex_lock (__objc_runtime_mutex);
113 114
  while (i < method_list->method_count)
    {
115
      Method method = &method_list->method_list[i];
Andrew Pinski committed
116 117 118 119 120 121
      if (method->method_name)
	{
	  method->method_name
	    = __sel_register_typed_name ((const char *) method->method_name,
					 method->method_types, 0, YES);
	}
122 123
      i += 1;
    }
Andrew Pinski committed
124
  objc_mutex_unlock (__objc_runtime_mutex);
125 126
}

127 128 129
/* The same as __objc_register_selectors_from_list, but works on a
   struct objc_method_description_list* instead of a struct
   objc_method_list*.  This is only used for protocols, which have
130
   lists of method descriptions, not methods.  */
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
void
__objc_register_selectors_from_description_list 
(struct objc_method_description_list *method_list)
{
  int i = 0;
  
  objc_mutex_lock (__objc_runtime_mutex);
  while (i < method_list->count)
    {
      struct objc_method_description *method = &method_list->list[i];
      if (method->name)
	{
	  method->name
	    = __sel_register_typed_name ((const char *) method->name,
					 method->types, 0, YES);
	}
      i += 1;
    }
  objc_mutex_unlock (__objc_runtime_mutex);
}
151

152
/* Register instance methods as class methods for root classes.  */
153
void __objc_register_instance_methods_to_class (Class class)
154
{
155 156
  struct objc_method_list *method_list;
  struct objc_method_list *class_method_list;
157
  int max_methods_no = 16;
158 159
  struct objc_method_list *new_list;
  Method curr_method;
160 161

  /* Only if a root class. */
162
  if (class->super_class)
163 164
    return;

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 169 170
  method_list = class->methods;
  class_method_list = class->class_pointer->methods;
  curr_method = &new_list->method_list[0];
171 172
  
  /* Iterate through the method lists for the class.  */
173 174 175
  while (method_list)
    {
      int i;
176 177
      
      /* Iterate through the methods from this method list.  */
178 179
      for (i = 0; i < method_list->method_count; i++)
	{
180
	  Method mth = &method_list->method_list[i];
181
	  if (mth->method_name
182
	      && ! search_for_method_in_list (class_method_list,
183 184
					      mth->method_name))
	    {
185 186
	      /* This instance method isn't a class method.  Add it
		 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 193
		  objc_realloc (new_list, sizeof (struct objc_method_list)
				+ sizeof (struct 
194
					  objc_method[max_methods_no += 16]));
195 196 197 198 199 200 201
	      curr_method = &new_list->method_list[new_list->method_count];
	    }
	}

      method_list = method_list->method_next;
    }

202 203
  /* If we created any new class methods then attach the method list
     to the class.  */
204 205 206
  if (new_list->method_count)
    {
      new_list =
207
 	objc_realloc (new_list, sizeof (struct objc_method_list)
208
		      + sizeof (struct objc_method[new_list->method_count]));
209 210 211
      new_list->method_next = class->class_pointer->methods;
      class->class_pointer->methods = new_list;
    }
212 213
  else
    objc_free(new_list);
214 215
  
  __objc_update_dispatch_table_for_class (class->class_pointer);
216 217
}

218 219 220 221 222 223 224 225
BOOL
sel_isEqual (SEL s1, SEL s2)
{
  if (s1 == 0 || s2 == 0)
    return s1 == s2;
  else
    return s1->sel_id == s2->sel_id;
}
226

227 228
/* Return YES iff t1 and t2 have same method types.  Ignore the
   argframe layout.  */
229
static BOOL
230
sel_types_match (const char *t1, const char *t2)
231
{
232
  if (! t1 || ! t2)
233 234 235 236 237
    return NO;
  while (*t1 && *t2)
    {
      if (*t1 == '+') t1++;
      if (*t2 == '+') t2++;
238 239
      while (isdigit ((unsigned char) *t1)) t1++;
      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 243 244
      t1 = objc_skip_type_qualifiers (t1);
      t2 = objc_skip_type_qualifiers (t2);
      if (! *t1 && ! *t2)
245 246 247 248 249 250 251 252 253
	return YES;
      if (*t1 != *t2)
	return NO;
      t1++;
      t2++;
    }
  return NO;
}

254
/* Return selector representing name.  */
255 256 257 258 259 260
SEL
sel_get_any_uid (const char *name)
{
  struct objc_list *l;
  sidx i;

261
  objc_mutex_lock (__objc_runtime_mutex);
262

263
  i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
264 265
  if (soffset_decode (i) == 0)
    {
266
      objc_mutex_unlock (__objc_runtime_mutex);
267 268 269
      return 0;
    }

270 271
  l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
  objc_mutex_unlock (__objc_runtime_mutex);
272 273 274 275

  if (l == 0)
    return 0;

276
  return (SEL) l->head;
277 278
}

279 280 281 282 283
SEL
sel_getTypedSelector (const char *name)
{
  sidx i;

284 285 286 287 288
  if (name == NULL)
    return NULL;
  
  objc_mutex_lock (__objc_runtime_mutex);
  
289 290 291 292 293
  /* Look for a typed selector.  */
  i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
  if (i != 0)
    {
      struct objc_list *l;
294
      SEL returnValue = NULL;
295 296 297 298 299 300 301

      for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
	   l; l = l->tail)
	{
	  SEL s = (SEL) l->head;
	  if (s->sel_types)
	    {
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
	      if (returnValue == NULL)
		{
		  /* First typed selector that we find.  Keep it in
		     returnValue, but keep checking as we want to
		     detect conflicts.  */
		  returnValue = s;
		}
	      else
		{
		  /* We had already found a typed selectors, so we
		     have multiple ones.  Double-check that they have
		     different types, just in case for some reason we
		     got duplicates with the same types.  If so, it's
		     OK, we'll ignore the duplicate.  */
		  if (returnValue->sel_types == s->sel_types)
		    continue;
		  else if (sel_types_match (returnValue->sel_types, s->sel_types))
		    continue;
		  else
		    {
		      /* The types of the two selectors are different;
			 it's a conflict.  Too bad.  Return NULL.  */
		      objc_mutex_unlock (__objc_runtime_mutex);
		      return NULL;
		    }
		}
328 329
	    }
	}
330 331 332 333 334 335

      if (returnValue != NULL)
	{
	  objc_mutex_unlock (__objc_runtime_mutex);
	  return returnValue;
	}
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
    }

  /* No typed selector found.  Return NULL.  */
  objc_mutex_unlock (__objc_runtime_mutex);
  return 0;
}

SEL *
sel_copyTypedSelectorList (const char *name, unsigned int *numberOfReturnedSelectors)
{
  unsigned int count = 0;
  SEL *returnValue = NULL;
  sidx i;
  
  if (name == NULL)
    {
      if (numberOfReturnedSelectors)
	*numberOfReturnedSelectors = 0;
      return NULL;
    }

  objc_mutex_lock (__objc_runtime_mutex);

  /* Count how many selectors we have.  */
  i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
  if (i != 0)
    {
      struct objc_list *selector_list = NULL;
      selector_list = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);

      /* Count how many selectors we have.  */
      {
	struct objc_list *l;
	for (l = selector_list; l; l = l->tail)
	  count++;
      }

      if (count != 0)
	{
	  /* Allocate enough memory to hold them.  */
	  returnValue = (SEL *)(malloc (sizeof (SEL) * (count + 1)));
	  
	  /* Copy the selectors.  */
	  {
	    unsigned int j;
	    for (j = 0; j < count; j++)
	      {
		returnValue[j] = (SEL)(selector_list->head);
		selector_list = selector_list->tail;
	      }
	    returnValue[j] = NULL;
	  }
	}
    }      

  objc_mutex_unlock (__objc_runtime_mutex);
  
  if (numberOfReturnedSelectors)
    *numberOfReturnedSelectors = count;
  
  return returnValue;
}

399 400
/* Get the name of a selector.  If the selector is unknown, the empty
   string "" is returned.  */ 
Nicola Pero committed
401
const char *sel_getName (SEL selector)
402 403 404
{
  const char *ret;

405 406
  if (selector == NULL)
    return "<null selector>";
407
  
408 409 410
  objc_mutex_lock (__objc_runtime_mutex);
  if ((soffset_decode ((sidx)selector->sel_id) > 0)
      && (soffset_decode ((sidx)selector->sel_id) <= __objc_selector_max_index))
411 412 413
    ret = sarray_get_safe (__objc_selector_names, (sidx) selector->sel_id);
  else
    ret = 0;
414
  objc_mutex_unlock (__objc_runtime_mutex);
415 416 417 418 419 420 421 422 423 424
  return ret;
}

BOOL
sel_is_mapped (SEL selector)
{
  unsigned int idx = soffset_decode ((sidx)selector->sel_id);
  return ((idx > 0) && (idx <= __objc_selector_max_index));
}

425
const char *sel_getTypeEncoding (SEL selector)
426 427 428 429 430 431 432
{
  if (selector)
    return selector->sel_types;
  else
    return 0;
}

433
/* The uninstalled dispatch table.  */
434
extern struct sarray *__objc_uninstalled_dtable;
435

Andrew Pinski committed
436
/* __sel_register_typed_name allocates lots of struct objc_selector:s
437 438 439 440 441 442 443 444 445 446 447 448
   of 8 (16, if pointers are 64 bits) bytes at startup. To reduce the
   number of malloc calls and memory lost to malloc overhead, we
   allocate objc_selector:s in blocks here. This is only called from
   __sel_register_typed_name, and __sel_register_typed_name may only
   be called when __objc_runtime_mutex is locked.

   Note that the objc_selector:s allocated from
   __sel_register_typed_name are never freed.

   62 because 62 * sizeof (struct objc_selector) = 496 (992). This
   should let malloc add some overhead and use a nice, round 512
   (1024) byte chunk.  */
Andrew Pinski committed
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
#define SELECTOR_POOL_SIZE 62
static struct objc_selector *selector_pool;
static int selector_pool_left;

static struct objc_selector *
pool_alloc_selector(void)
{
  if (!selector_pool_left)
    {
      selector_pool = objc_malloc (sizeof (struct objc_selector)
				   * SELECTOR_POOL_SIZE);
      selector_pool_left = SELECTOR_POOL_SIZE;
    }
  return &selector_pool[--selector_pool_left];
}

465 466 467
/* Store the passed selector name in the selector record and return
   its selector value (value returned by sel_get_uid).  Assume that
   the calling function has locked down __objc_runtime_mutex.  The
468
   'is_const' parameter tells us if the name and types parameters are
469 470
   really constant or not.  If YES then they are constant and we can
   just store the pointers.  If NO then we need to copy name and types
471 472 473 474 475 476 477
   because the pointers may disappear later on.  If the 'orig'
   parameter is not NULL, then we are registering a selector from a
   module, and 'orig' is that selector.  In this case, we can put the
   selector in the tables if needed, and orig->sel_id is updated with
   the selector ID of the registered selector, and 'orig' is
   returned.  */
static SEL
478 479 480
__sel_register_typed_name (const char *name, const char *types, 
			   struct objc_selector *orig, BOOL is_const)
{
481
  struct objc_selector *j;
482 483 484
  sidx i;
  struct objc_list *l;

485
  i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
486 487
  if (soffset_decode (i) != 0)
    {
488 489 490
      /* There are already selectors with that name.  Examine them to
	 see if the one we're registering already exists.  */
      for (l = (struct objc_list *)sarray_get_safe (__objc_selector_array, i);
491 492
	   l; l = l->tail)
	{
493
	  SEL s = (SEL)l->head;
494 495 496 497 498 499
	  if (types == 0 || s->sel_types == 0)
	    {
	      if (s->sel_types == types)
		{
		  if (orig)
		    {
500
		      orig->sel_id = (void *)i;
501 502 503 504 505 506
		      return orig;
		    }
		  else
		    return s;
		}
	    }
507
	  else if (sel_types_match (s->sel_types, types))
508 509 510
	    {
	      if (orig)
		{
511
		  orig->sel_id = (void *)i;
512 513 514 515 516 517
		  return orig;
		}
	      else
		return s;
	    }
	}
518 519
      /* A selector with this specific name/type combination does not
	 exist yet.  We need to register it.  */
520 521 522
      if (orig)
	j = orig;
      else
Andrew Pinski committed
523
	j = pool_alloc_selector ();
524
      
525 526
      j->sel_id = (void *)i;
      /* 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 531
      else
	{
532 533
	  j->sel_types = (char *)objc_malloc (strlen (types) + 1);
	  strcpy ((char *)j->sel_types, types);
534
	}
535
      l = (struct objc_list *)sarray_get_safe (__objc_selector_array, i);
536 537 538
    }
  else
    {
539 540 541 542 543
      /* There are no other selectors with this name registered in the
	 runtime tables.  */
      const char *new_name;

      /* Determine i.  */
544
      __objc_selector_max_index += 1;
545
      i = soffset_encode (__objc_selector_max_index);
546 547

      /* Prepare the selector.  */
548 549 550
      if (orig)
	j = orig;
      else
Andrew Pinski committed
551
	j = pool_alloc_selector ();
552
      
553 554
      j->sel_id = (void *)i;
      /* Can we use the pointer or must we copy types ?  Don't copy if
555
	 NULL.  */
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
      if (is_const || (types == 0))
	j->sel_types = types;
      else
	{
	  j->sel_types = (char *)objc_malloc (strlen (types) + 1);
	  strcpy ((char *)j->sel_types, types);
	}

      /* Since this is the first selector with this name, we need to
	 register the correspondence between 'i' (the sel_id) and
	 'name' (the actual string) in __objc_selector_names and
	 __objc_selector_hash.  */
      
      /* Can we use the pointer or must we copy name ?  Don't copy if
	 NULL.  (FIXME: Can the name really be NULL here ?)  */
      if (is_const || (name == 0))
	new_name = name;
573 574
      else
	{
575 576
	  new_name = (char *)objc_malloc (strlen (name) + 1);
	  strcpy ((char *)new_name, name);
577
	}
578 579 580 581 582 583 584
      
      /* This maps the sel_id to the name.  */
      sarray_at_put_safe (__objc_selector_names, i, (void *)new_name);

      /* This maps the name to the sel_id.  */
      objc_hash_add (&__objc_selector_hash, (void *)new_name, (void *)i);

585 586 587 588
      l = 0;
    }

  DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", name, types, 
589 590 591 592 593 594
		(long)soffset_decode (i));

  /* Now add the selector to the list of selectors with that id.  */
  l = list_cons ((void *)j, l);
  sarray_at_put_safe (__objc_selector_array, i, (void *)l);

595
  sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1);
596
  
597
  return (SEL)j;
598 599 600
}

SEL
Nicola Pero committed
601
sel_registerName (const char *name)
602 603
{
  SEL ret;
604 605 606

  if (name == NULL)
    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 615 616
  
  return ret;
}

Nicola Pero committed
617 618
SEL
sel_registerTypedName (const char *name, const char *type)
619 620
{
  SEL ret;
Andrew Pinski committed
621

622 623 624
  if (name == NULL)
    return NULL;

625
  objc_mutex_lock (__objc_runtime_mutex);
626 627 628
  /* Assume that name and type are not constant static memory and need
     to be copied before put into a runtime structure.  is_const ==
     NO.  */
629
  ret = __sel_register_typed_name (name, type, 0, NO);
630
  objc_mutex_unlock (__objc_runtime_mutex);
631 632 633
  
  return ret;
}
Nicola Pero committed
634

635
/* Return the selector representing name.  */
Nicola Pero committed
636 637 638 639 640
SEL
sel_getUid (const char *name)
{
  return sel_registerTypedName (name, 0);
}