OSDN Git Service

PR ada/60703
[pf3gnuchains/gcc-fork.git] / libobjc / selector.c
index 7211f90..55ca706 100644 (file)
 /* GNU Objective C Runtime selector related functions
-   Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1993, 1995, 1996, 1997, 2002, 2004, 2009, 2010
+   Free Software Foundation, Inc.
    Contributed by Kresten Krab Thorup
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify it under the
+GCC is free software; you can redistribute it and/or modify it under the
 terms of the GNU General Public License as published by the Free Software
-Foundation; either version 2, or (at your option) any later version.
+Foundation; either version 3, or (at your option) any later version.
 
-GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 details.
 
-You should have received a copy of the GNU General Public License along with
-GNU CC; see the file COPYING.  If not, write to the Free Software
-Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
-
-/* As a special exception, if you link this library with files compiled with
-   GCC to produce an executable, this does not cause the resulting executable
-   to be covered by the GNU General Public License. This exception does not
-   however invalidate any other reasons why the executable file might be
-   covered by the GNU General Public License.  */
-
-#include "runtime.h"
-#include "sarray.h"
-#include "encoding.h"
-
-/* Initial selector hash table size. Value doesn't matter much */
+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/>.  */
+
+#include "objc-private/common.h"
+#include "objc/runtime.h"
+#include "objc/thr.h"
+#include "objc-private/hash.h"
+#include "objc-private/objc-list.h"
+#include "objc-private/module-abi-8.h"
+#include "objc-private/runtime.h"
+#include "objc-private/sarray.h"
+#include "objc-private/selector.h"
+#include <stdlib.h>                    /* For malloc.  */
+
+/* Initial selector hash table size. Value doesn't matter much.  */
 #define SELECTOR_HASH_SIZE 128
 
-/* Tables mapping selector names to uid and opposite */
-static struct sarray__objc_selector_array = 0; /* uid -> sel  !T:MUTEX */
-static struct sarray__objc_selector_names = 0; /* uid -> name !T:MUTEX */
+/* Tables mapping selector names to uid and opposite */
+static struct sarray *__objc_selector_array = 0; /* uid -> sel  !T:MUTEX */
+static struct sarray *__objc_selector_names = 0; /* uid -> name !T:MUTEX */
 static cache_ptr      __objc_selector_hash  = 0; /* name -> uid !T:MUTEX */
 
-static void register_selectors_from_list(MethodList_t);
+/* Number of selectors stored in each of the above tables.  */
+unsigned int __objc_selector_max_index = 0;     /* !T:MUTEX */
 
-/* Number of selectors stored in each of the above tables */
-int __objc_selector_max_index = 0;              /* !T:MUTEX */
+/* Forward-declare an internal function.  */
+static SEL
+__sel_register_typed_name (const char *name, const char *types,
+                          struct objc_selector *orig, BOOL is_const);
 
-void __objc_init_selector_tables()
+void __objc_init_selector_tables (void)
 {
   __objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0);
   __objc_selector_names = sarray_new (SELECTOR_HASH_SIZE, 0);
   __objc_selector_hash
-    = hash_new (SELECTOR_HASH_SIZE,
-               (hash_func_type) hash_string,
-               (compare_func_type) compare_strings);
+    = objc_hash_new (SELECTOR_HASH_SIZE,
+                    (hash_func_type) objc_hash_string,
+                    (compare_func_type) objc_compare_strings);
 }  
 
-/* This routine is given a class and records all of the methods in its class
-   structure in the record table.  */
+/* 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);
+    }
+}
+
+/* This routine is given a class and records all of the methods in its
+   class structure in the record table.  */
 void
 __objc_register_selectors_from_class (Class class)
 {
-  MethodList_t method_list;
+  struct objc_method_list * method_list;
 
   method_list = class->methods;
   while (method_list)
     {
-      register_selectors_from_list (method_list);
+      __objc_register_selectors_from_list (method_list);
       method_list = method_list->method_next;
     }
 }
 
 
-/* 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.
+/* 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.
 
-   This one is only called for Class objects.  For categories,
-   class_add_method_list is called.
-   */
-static void
-register_selectors_from_list (MethodList_t method_list)
+   The name and type pointers in the method list must be permanent and
+   immutable.  */
+void
+__objc_register_selectors_from_list (struct objc_method_list *method_list)
 {
   int i = 0;
+
+  objc_mutex_lock (__objc_runtime_mutex);
   while (i < method_list->method_count)
     {
-      Method_t method = &method_list->method_list[i];
-      method->method_name 
-       = sel_register_typed_name ((const char*)method->method_name, 
-                                    method->method_types);
+      Method method = &method_list->method_list[i];
+      if (method->method_name)
+       {
+         method->method_name
+           = __sel_register_typed_name ((const char *) method->method_name,
+                                        method->method_types, 0, YES);
+       }
       i += 1;
     }
+  objc_mutex_unlock (__objc_runtime_mutex);
 }
 
+/* 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
+   lists of method descriptions, not methods.  */
+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);
+}
 
-/* Register instance methods as class methods for root classes */
-void __objc_register_instance_methods_to_class(Class class)
+/* Register instance methods as class methods for root classes */
+void __objc_register_instance_methods_to_class (Class class)
 {
-  MethodList_t method_list;
-  MethodList_t class_method_list;
+  struct objc_method_list *method_list;
+  struct objc_method_list *class_method_list;
   int max_methods_no = 16;
-  MethodList_t new_list;
-  Method_t curr_method;
+  struct objc_method_list *new_list;
+  Method curr_method;
 
   /* Only if a root class. */
-  if(class->super_class)
+  if (class->super_class)
     return;
 
-  /* Allocate a method list to hold the new class methods */
-  new_list = objc_calloc(sizeof(struct objc_method_list)
-                           + sizeof(struct objc_method[max_methods_no]), 1);
+  /* Allocate a method list to hold the new class methods */
+  new_list = objc_calloc (sizeof (struct objc_method_list)
+                         + sizeof (struct objc_method[max_methods_no]), 1);
   method_list = class->methods;
   class_method_list = class->class_pointer->methods;
   curr_method = &new_list->method_list[0];
-
-  /* Iterate through the method lists for the class */
+  
+  /* Iterate through the method lists for the class */
   while (method_list)
     {
       int i;
-
-      /* Iterate through the methods from this method list */
+      
+      /* Iterate through the methods from this method list */
       for (i = 0; i < method_list->method_count; i++)
        {
-         Method_t mth = &method_list->method_list[i];
+         Method mth = &method_list->method_list[i];
          if (mth->method_name
-             && !search_for_method_in_list (class_method_list,
+             && ! search_for_method_in_list (class_method_list,
                                              mth->method_name))
            {
-             /* This instance method isn't a class method. 
-                 Add it into the new_list. */
+             /* This instance method isn't a class method.  Add it
+                into the new_list. */
              *curr_method = *mth;
-  
-             /* Reallocate the method list if necessary */
-             if(++new_list->method_count == max_methods_no)
+             
+             /* Reallocate the method list if necessary */
+             if (++new_list->method_count == max_methods_no)
                new_list =
-                 objc_realloc(new_list, sizeof(struct objc_method_list)
-                               + sizeof(struct 
-                                       objc_method[max_methods_no += 16]));
+                 objc_realloc (new_list, sizeof (struct objc_method_list)
+                               + sizeof (struct 
+                                         objc_method[max_methods_no += 16]));
              curr_method = &new_list->method_list[new_list->method_count];
            }
        }
@@ -138,39 +200,49 @@ void __objc_register_instance_methods_to_class(Class class)
       method_list = method_list->method_next;
     }
 
-  /* If we created any new class methods
-     then attach the method list to the class */
+  /* If we created any new class methods then attach the method list
+     to the class.  */
   if (new_list->method_count)
     {
       new_list =
-       objc_realloc(new_list, sizeof(struct objc_method_list)
-                    + sizeof(struct objc_method[new_list->method_count]));
+       objc_realloc (new_list, sizeof (struct objc_method_list)
+                     + sizeof (struct objc_method[new_list->method_count]));
       new_list->method_next = class->class_pointer->methods;
       class->class_pointer->methods = new_list;
     }
-
-    __objc_update_dispatch_table_for_class (class->class_pointer);
+  else
+    objc_free(new_list);
+  
+  __objc_update_dispatch_table_for_class (class->class_pointer);
 }
 
-
-/* Returns YES iff t1 and t2 have same method types, but we ignore
-   the argframe layout */
 BOOL
-sel_types_match (const char* t1, const char* t2)
+sel_isEqual (SEL s1, SEL s2)
+{
+  if (s1 == 0 || s2 == 0)
+    return s1 == s2;
+  else
+    return s1->sel_id == s2->sel_id;
+}
+
+/* Return YES iff t1 and t2 have same method types.  Ignore the
+   argframe layout.  */
+static BOOL
+sel_types_match (const char *t1, const char *t2)
 {
-  if (!t1 || !t2)
+  if (! t1 || ! t2)
     return NO;
   while (*t1 && *t2)
     {
       if (*t1 == '+') t1++;
       if (*t2 == '+') t2++;
-      while (isdigit((unsigned char)*t1)) t1++;
-      while (isdigit((unsigned char)*t2)) t2++;
+      while (isdigit ((unsigned char) *t1)) t1++;
+      while (isdigit ((unsigned char) *t2)) t2++;
       /* xxx Remove these next two lines when qualifiers are put in
-        all selectors, not just Protocol selectors. */
-      t1 = objc_skip_type_qualifiers(t1);
-      t2 = objc_skip_type_qualifiers(t2);
-      if (!*t1 && !*t2)
+        all selectors, not just Protocol selectors.  */
+      t1 = objc_skip_type_qualifiers (t1);
+      t2 = objc_skip_type_qualifiers (t2);
+      if (! *t1 && ! *t2)
        return YES;
       if (*t1 != *t2)
        return NO;
@@ -180,123 +252,167 @@ sel_types_match (const char* t1, const char* t2)
   return NO;
 }
 
-/* return selector representing name */
+/* Return selector representing name.  */
 SEL
-sel_get_typed_uid (const char *name, const char *types)
+sel_get_any_uid (const char *name)
 {
   struct objc_list *l;
   sidx i;
 
-  objc_mutex_lock(__objc_runtime_mutex);
+  objc_mutex_lock (__objc_runtime_mutex);
 
-  i = (sidx) hash_value_for_key (__objc_selector_hash, name);
-  if (i == 0)
+  i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
+  if (soffset_decode (i) == 0)
     {
-      objc_mutex_unlock(__objc_runtime_mutex);
+      objc_mutex_unlock (__objc_runtime_mutex);
       return 0;
     }
 
-  for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
-       l; l = l->tail)
-    {
-      SEL s = (SEL)l->head;
-      if (types == 0 || s->sel_types == 0)
-       {
-         if (s->sel_types == types)
-           {
-             objc_mutex_unlock(__objc_runtime_mutex);
-             return s;
-           }
-       }
-      else if (sel_types_match (s->sel_types, types))
-       {
-         objc_mutex_unlock(__objc_runtime_mutex);
-         return s;
-       }
-    }
+  l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
+  objc_mutex_unlock (__objc_runtime_mutex);
 
-  objc_mutex_unlock(__objc_runtime_mutex);
-  return 0;
+  if (l == 0)
+    return 0;
+
+  return (SEL) l->head;
 }
 
-/* Return selector representing name; prefer a selector with non-NULL type */
 SEL
-sel_get_any_typed_uid (const char *name)
+sel_getTypedSelector (const char *name)
 {
-  struct objc_list *l;
   sidx i;
-  SEL s = NULL;
-
-  objc_mutex_lock(__objc_runtime_mutex);
 
-  i = (sidx) hash_value_for_key (__objc_selector_hash, name);
-  if (i == 0)
+  if (name == NULL)
+    return NULL;
+  
+  objc_mutex_lock (__objc_runtime_mutex);
+  
+  /* Look for a typed selector.  */
+  i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
+  if (i != 0)
     {
-      objc_mutex_unlock(__objc_runtime_mutex);
-      return 0;
-    }
+      struct objc_list *l;
+      SEL returnValue = NULL;
 
-  for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
-       l; l = l->tail)
-    {
-      s = (SEL) l->head;
-      if (s->sel_types)
+      for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
+          l; l = l->tail)
        {
-           objc_mutex_unlock(__objc_runtime_mutex);
-           return s;
+         SEL s = (SEL) l->head;
+         if (s->sel_types)
+           {
+             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;
+                   }
+               }
+           }
+       }
+
+      if (returnValue != NULL)
+       {
+         objc_mutex_unlock (__objc_runtime_mutex);
+         return returnValue;
        }
     }
 
-  objc_mutex_unlock(__objc_runtime_mutex);
-  return s;
+  /* No typed selector found.  Return NULL.  */
+  objc_mutex_unlock (__objc_runtime_mutex);
+  return 0;
 }
 
-/* return selector representing name */
-SEL
-sel_get_any_uid (const char *name)
+SEL *
+sel_copyTypedSelectorList (const char *name, unsigned int *numberOfReturnedSelectors)
 {
-  struct objc_list *l;
+  unsigned int count = 0;
+  SEL *returnValue = NULL;
   sidx i;
-
-  objc_mutex_lock(__objc_runtime_mutex);
-
-  i = (sidx) hash_value_for_key (__objc_selector_hash, name);
-  if (soffset_decode (i) == 0)
+  
+  if (name == NULL)
     {
-      objc_mutex_unlock(__objc_runtime_mutex);
-      return 0;
+      if (numberOfReturnedSelectors)
+       *numberOfReturnedSelectors = 0;
+      return NULL;
     }
 
-  l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
-  objc_mutex_unlock(__objc_runtime_mutex);
+  objc_mutex_lock (__objc_runtime_mutex);
 
-  if (l == 0)
-    return 0;
+  /* 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++;
+      }
 
-  return (SEL)l->head;
-}
+      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;
+         }
+       }
+    }      
 
-/* return selector representing name */
-SEL
-sel_get_uid (const char *name)
-{
-  return sel_register_typed_name (name, 0);
+  objc_mutex_unlock (__objc_runtime_mutex);
+  
+  if (numberOfReturnedSelectors)
+    *numberOfReturnedSelectors = count;
+  
+  return returnValue;
 }
 
-/* Get name of selector.  If selector is unknown, the empty string "" 
-   is returned */ 
-const char*
-sel_get_name (SEL selector)
+/* Get the name of a selector.  If the selector is unknown, the empty
+   string "" is returned.  */ 
+const char *sel_getName (SEL selector)
 {
   const char *ret;
 
-  objc_mutex_lock(__objc_runtime_mutex);
-  if ((soffset_decode((sidx)selector->sel_id) > 0)
-      && (soffset_decode((sidx)selector->sel_id) <= __objc_selector_max_index))
+  if (selector == NULL)
+    return "<null selector>";
+  
+  objc_mutex_lock (__objc_runtime_mutex);
+  if ((soffset_decode ((sidx)selector->sel_id) > 0)
+      && (soffset_decode ((sidx)selector->sel_id) <= __objc_selector_max_index))
     ret = sarray_get_safe (__objc_selector_names, (sidx) selector->sel_id);
   else
     ret = 0;
-  objc_mutex_unlock(__objc_runtime_mutex);
+  objc_mutex_unlock (__objc_runtime_mutex);
   return ret;
 }
 
@@ -307,9 +423,7 @@ sel_is_mapped (SEL selector)
   return ((idx > 0) && (idx <= __objc_selector_max_index));
 }
 
-
-const char*
-sel_get_type (SEL selector)
+const char *sel_getTypeEncoding (SEL selector)
 {
   if (selector)
     return selector->sel_types;
@@ -317,28 +431,64 @@ sel_get_type (SEL selector)
     return 0;
 }
 
-/* The uninstalled dispatch table */
-extern struct sarray__objc_uninstalled_dtable;
+/* The uninstalled dispatch table */
+extern struct sarray *__objc_uninstalled_dtable;
 
-/* Store the passed selector name in the selector record and return its
-   selector value (value returned by sel_get_uid).
-   Assumes that the calling function has locked down __objc_runtime_mutex. */
-/* is_const parameter tells us if the name and types parameters
-   are 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 because the pointers may disappear later on. */
-SEL
+/* __sel_register_typed_name allocates lots of struct objc_selector:s
+   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.  */
+#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];
+}
+
+/* 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
+   'is_const' parameter tells us if the name and types parameters are
+   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
+   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
 __sel_register_typed_name (const char *name, const char *types, 
                           struct objc_selector *orig, BOOL is_const)
 {
-  struct objc_selectorj;
+  struct objc_selector *j;
   sidx i;
   struct objc_list *l;
 
-  i = (sidx) hash_value_for_key (__objc_selector_hash, name);
+  i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
   if (soffset_decode (i) != 0)
     {
-      for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
+      /* 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);
           l; l = l->tail)
        {
          SEL s = (SEL)l->head;
@@ -348,111 +498,144 @@ __sel_register_typed_name (const char *name, const char *types,
                {
                  if (orig)
                    {
-                     orig->sel_id = (void*)i;
+                     orig->sel_id = (void *)i;
                      return orig;
                    }
                  else
                    return s;
                }
            }
-         else if (!strcmp (s->sel_types, types))
+         else if (sel_types_match (s->sel_types, types))
            {
              if (orig)
                {
-                 orig->sel_id = (void*)i;
+                 orig->sel_id = (void *)i;
                  return orig;
                }
              else
                return s;
            }
        }
+      /* A selector with this specific name/type combination does not
+        exist yet.  We need to register it.  */
       if (orig)
        j = orig;
       else
-       j = objc_malloc (sizeof (struct objc_selector));
-
-      j->sel_id = (void*)i;
-      /* Can we use the pointer or must copy types?  Don't copy if NULL */
+       j = pool_alloc_selector ();
+      
+      j->sel_id = (void *)i;
+      /* Can we use the pointer or must we copy types ?  Don't copy if
+        NULL.  */
       if ((is_const) || (types == 0))
-       j->sel_types = (const char*)types;
-      else {
-       j->sel_types = (char *) objc_malloc(strlen(types)+1);
-       strcpy((char *)j->sel_types, types);
-      }
-      l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
+       j->sel_types = types;
+      else
+       {
+         j->sel_types = (char *)objc_malloc (strlen (types) + 1);
+         strcpy ((char *)j->sel_types, types);
+       }
+      l = (struct objc_list *)sarray_get_safe (__objc_selector_array, i);
     }
   else
     {
+      /* There are no other selectors with this name registered in the
+        runtime tables.  */
+      const char *new_name;
+
+      /* Determine i.  */
       __objc_selector_max_index += 1;
-      i = soffset_encode(__objc_selector_max_index);
+      i = soffset_encode (__objc_selector_max_index);
+
+      /* Prepare the selector.  */
       if (orig)
        j = orig;
       else
-       j = objc_malloc (sizeof (struct objc_selector));
-       
-      j->sel_id = (void*)i;
-      /* Can we use the pointer or must copy types?  Don't copy if NULL */
-      if ((is_const) || (types == 0))
-       j->sel_types = (const char*)types;
-      else {
-       j->sel_types = (char *) objc_malloc(strlen(types)+1);
-       strcpy((char *)j->sel_types, types);
-      }
+       j = pool_alloc_selector ();
+      
+      j->sel_id = (void *)i;
+      /* Can we use the pointer or must we copy types ?  Don't copy if
+        NULL.  */
+      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;
+      else
+       {
+         new_name = (char *)objc_malloc (strlen (name) + 1);
+         strcpy ((char *)new_name, name);
+       }
+      
+      /* 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);
+
       l = 0;
     }
 
   DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", name, types, 
-               soffset_decode (i));
-  
-  {
-    int is_new = (l == 0);
-    const char *new_name;
-
-    /* Can we use the pointer or must copy name?  Don't copy if NULL */
-    if ((is_const) || (name == 0))
-      new_name = name;
-    else {
-      new_name = (char *) objc_malloc(strlen(name)+1);
-      strcpy((char *)new_name, name);
-    }
-
-    l = list_cons ((void*)j, l);
-    sarray_at_put_safe (__objc_selector_names, i, (void *) new_name);
-    sarray_at_put_safe (__objc_selector_array, i, (void *) l);
-    if (is_new)
-      hash_add (&__objc_selector_hash, (void *) new_name, (void *) i);
-  }
+               (long)soffset_decode (i));
 
-  sarray_realloc(__objc_uninstalled_dtable, __objc_selector_max_index+1);
+  /* 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);
 
-  return (SEL) j;
+  sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1);
+  
+  return (SEL)j;
 }
 
 SEL
-sel_register_name (const char *name)
+sel_registerName (const char *name)
 {
   SEL ret;
+
+  if (name == NULL)
+    return NULL;
     
-  objc_mutex_lock(__objc_runtime_mutex);
+  objc_mutex_lock (__objc_runtime_mutex);
   /* Assume that name is not constant static memory and needs to be
-     copied before put into a runtime structure.  is_const == NO */
+     copied before put into a runtime structure.  is_const == NO */
   ret = __sel_register_typed_name (name, 0, 0, NO);
-  objc_mutex_unlock(__objc_runtime_mutex);
+  objc_mutex_unlock (__objc_runtime_mutex);
   
   return ret;
 }
 
 SEL
-sel_register_typed_name (const char *name, const char *type)
+sel_registerTypedName (const char *name, const char *type)
 {
   SEL ret;
-    
-  objc_mutex_lock(__objc_runtime_mutex);
-  /* Assume that name and type are not constant static memory and need to
-     be copied before put into a runtime structure.  is_const == NO */
+
+  if (name == NULL)
+    return NULL;
+
+  objc_mutex_lock (__objc_runtime_mutex);
+  /* Assume that name and type are not constant static memory and need
+     to be copied before put into a runtime structure.  is_const ==
+     NO.  */
   ret = __sel_register_typed_name (name, type, 0, NO);
-  objc_mutex_unlock(__objc_runtime_mutex);
+  objc_mutex_unlock (__objc_runtime_mutex);
   
   return ret;
 }
 
+/* Return the selector representing name.  */
+SEL
+sel_getUid (const char *name)
+{
+  return sel_registerTypedName (name, 0);
+}