]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
In libobjc/: 2010-10-16 Nicola Pero <nicola.pero@meta-innovation.com>
authorNicola Pero <nicola.pero@meta-innovation.com>
Sat, 16 Oct 2010 21:26:59 +0000 (21:26 +0000)
committerNicola Pero <nicola@gcc.gnu.org>
Sat, 16 Oct 2010 21:26:59 +0000 (21:26 +0000)
In libobjc/:
2010-10-16  Nicola Pero  <nicola.pero@meta-innovation.com>

        * objc/runtime.h: Updated comments.
        (class_addMethod): New.
        (class_addIvar): New.
        (class_replaceMethod): New.
        (objc_allocateClassPair): New.
        (objc_registerClassPair): New.
        (objc_disposeClassPair): New.
        * class.c (objc_allocateClassPair): New.
        (objc_registerClassPair): New.
        (objc_disposeClassPair): New.
        (class_getSuperclass): Return Nil if a class is in construction.
        * init.c (__objc_exec_class): Call __objc_init_class.
        (__objc_init_class): New.
        * ivars.c (class_copyIvarList): Return NULL if class is in
        construction.  Do not lock the runtime mutex.
        (class_getInstanceVariable): Return NULL if class is in
        construction.  Do not lock the runtime mutex.
        (class_addIvar): New.
        * sendmsg.c (class_addMethod): New.
        (class_replaceMethod): New.
        * objc-private/module-abi-8.h (__CLS_SETNOTINFO): New.
        (_CLS_IN_CONSTRUCTION): New.
        (CLS_IS_IN_CONSTRUCTION): New.
        (CLS_SET_IN_CONSTRUCTION): New.
        (CLS_SET_NOT_IN_CONSTRUCTION): New.
        * objc-private/runtime.h (__objc_init_class): New.

From-SVN: r165563

libobjc/ChangeLog
libobjc/class.c
libobjc/init.c
libobjc/ivars.c
libobjc/objc-private/module-abi-8.h
libobjc/objc-private/runtime.h
libobjc/objc/runtime.h
libobjc/sendmsg.c

index 2142b893c18758cb5a1eb060ba928effb56befc2..1d2b2948605c34cdf2f4d11ce111329d2796cc05 100644 (file)
@@ -1,3 +1,32 @@
+2010-10-16  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       * objc/runtime.h: Updated comments.
+       (class_addMethod): New.
+       (class_addIvar): New.
+       (class_replaceMethod): New.
+       (objc_allocateClassPair): New.
+       (objc_registerClassPair): New.
+       (objc_disposeClassPair): New.
+       * class.c (objc_allocateClassPair): New.
+       (objc_registerClassPair): New.
+       (objc_disposeClassPair): New.
+       (class_getSuperclass): Return Nil if a class is in construction.
+       * init.c (__objc_exec_class): Call __objc_init_class.
+       (__objc_init_class): New.
+       * ivars.c (class_copyIvarList): Return NULL if class is in
+       construction.  Do not lock the runtime mutex.
+       (class_getInstanceVariable): Return NULL if class is in
+       construction.  Do not lock the runtime mutex.
+       (class_addIvar): New.
+       * sendmsg.c (class_addMethod): New.
+       (class_replaceMethod): New.
+       * objc-private/module-abi-8.h (__CLS_SETNOTINFO): New.
+       (_CLS_IN_CONSTRUCTION): New.
+       (CLS_IS_IN_CONSTRUCTION): New.
+       (CLS_SET_IN_CONSTRUCTION): New.
+       (CLS_SET_NOT_IN_CONSTRUCTION): New.
+       * objc-private/runtime.h (__objc_init_class): New.
+
 2010-10-16  Nicola Pero  <nicola.pero@meta-innovation.com>
 
        * class.c (class_getSuperclass): Call __objc_resolve_class_links
index 71483457e257038755913ac9f7a79274ab46e64d..ade5a71f453e004d34ed1093b493b8e5d5ae46ed 100644 (file)
@@ -570,6 +570,199 @@ objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn)
   return count;
 }
 
+Class
+objc_allocateClassPair (Class super_class, const char *class_name, size_t extraBytes)
+{
+  Class new_class;
+  Class new_meta_class;
+
+  if (class_name == NULL)
+    return Nil;
+
+  if (objc_getClass (class_name))
+    return Nil;
+
+  if (super_class)
+    {
+      /* If you want to build a hierarchy of classes, you need to
+        build and register them one at a time.  The risk is that you
+        are able to cause confusion by registering a subclass before
+        the superclass or similar.  */
+      if (CLS_IS_IN_CONSTRUCTION (super_class))
+       return Nil;
+    }
+
+  /* Technically, we should create the metaclass first, then use
+     class_createInstance() to create the class.  That complication
+     would be relevant if we had class variables, but we don't, so we
+     just ignore it and create everything directly and assume all
+     classes have the same size.  */
+  new_class = objc_calloc (1, sizeof (struct objc_class) + extraBytes);
+  new_meta_class = objc_calloc (1, sizeof (struct objc_class) + extraBytes);
+
+  /* We create an unresolved class, similar to one generated by the
+     compiler.  It will be resolved later when we register it.
+
+     Note how the metaclass details are not that important; when the
+     class is resolved, the ones that matter will be fixed up.  */
+  new_class->class_pointer = new_meta_class;
+  new_meta_class->class_pointer = 0;
+
+  if (super_class)
+    {
+      /* Force the name of the superclass in place of the link to the
+        actual superclass, which will be put there when the class is
+        resolved.  */
+      const char *super_class_name = class_getName (super_class);
+      new_class->super_class = (void *)super_class_name;
+      new_meta_class->super_class = (void *)super_class_name;
+    }
+  else
+    {
+      new_class->super_class = (void *)0;
+      new_meta_class->super_class = (void *)0;
+    }
+
+  new_class->name = objc_malloc (strlen (class_name) + 1);
+  strcpy ((char*)new_class->name, class_name);
+  new_meta_class->name = new_class->name;
+
+  new_class->version = 0;
+  new_meta_class->version = 0;
+
+  new_class->info = _CLS_CLASS | _CLS_IN_CONSTRUCTION;
+  new_meta_class->info = _CLS_META | _CLS_IN_CONSTRUCTION;
+
+  if (super_class)
+    new_class->instance_size = super_class->instance_size;
+  else
+    new_class->instance_size = 0;
+  new_meta_class->instance_size = sizeof (struct objc_class);
+
+  return new_class;
+}
+
+void
+objc_registerClassPair (Class class_)
+{
+  if (class_ == Nil)
+    return;
+
+  if ((! CLS_ISCLASS (class_)) || (! CLS_IS_IN_CONSTRUCTION (class_)))
+    return;
+
+  if ((! CLS_ISMETA (class_->class_pointer)) || (! CLS_IS_IN_CONSTRUCTION (class_->class_pointer)))
+    return;
+
+  objc_mutex_lock (__objc_runtime_mutex);
+
+  if (objc_getClass (class_->name))
+    {
+      objc_mutex_unlock (__objc_runtime_mutex);
+      return;
+    }
+
+  CLS_SET_NOT_IN_CONSTRUCTION (class_);
+  CLS_SET_NOT_IN_CONSTRUCTION (class_->class_pointer);
+
+  __objc_init_class (class_);
+
+  /* Resolve class links immediately.  No point in waiting.  */
+  __objc_resolve_class_links ();
+
+  objc_mutex_unlock (__objc_runtime_mutex);
+}
+
+void
+objc_disposeClassPair (Class class_)
+{
+  if (class_ == Nil)
+    return;
+
+  if ((! CLS_ISCLASS (class_)) || (! CLS_IS_IN_CONSTRUCTION (class_)))
+    return;
+
+  if ((! CLS_ISMETA (class_->class_pointer)) || (! CLS_IS_IN_CONSTRUCTION (class_->class_pointer)))
+    return;
+
+  /* Undo any class_addIvar().  */
+  if (class_->ivars)
+    {
+      int i;
+      for (i = 0; i < class_->ivars->ivar_count; i++)
+       {
+         struct objc_ivar *ivar = &(class_->ivars->ivar_list[i]);
+
+         objc_free ((char *)ivar->ivar_name);
+         objc_free ((char *)ivar->ivar_type);
+       }
+      
+      objc_free (class_->ivars);
+    }
+
+  /* Undo any class_addMethod().  */
+  if (class_->methods)
+    {
+      struct objc_method_list *list = class_->methods;
+      while (list)
+       {
+         int i;
+         struct objc_method_list *next = list->method_next;
+
+         for (i = 0; i < list->method_count; i++)
+           {
+             struct objc_method *method = &(list->method_list[i]);
+
+             objc_free ((char *)method->method_name);
+             objc_free ((char *)method->method_types);
+           }
+
+         objc_free (list);
+         list = next;
+       }
+    }
+
+  /* Undo any class_addProtocol().  */
+  if (class_->protocols)
+    {
+      struct objc_protocol_list *list = class_->protocols;
+      while (list)
+       {
+         struct objc_protocol_list *next = list->next;
+
+         objc_free (list);
+         list = next;
+       }
+    }
+  
+  /* Undo any class_addMethod() on the meta-class.  */
+  if (class_->class_pointer->methods)
+    {
+      struct objc_method_list *list = class_->class_pointer->methods;
+      while (list)
+       {
+         int i;
+         struct objc_method_list *next = list->method_next;
+
+         for (i = 0; i < list->method_count; i++)
+           {
+             struct objc_method *method = &(list->method_list[i]);
+
+             objc_free ((char *)method->method_name);
+             objc_free ((char *)method->method_types);
+           }
+
+         objc_free (list);
+         list = next;
+       }
+    }
+
+  /* Undo objc_allocateClassPair().  */
+  objc_free ((char *)(class_->name));
+  objc_free (class_->class_pointer);
+  objc_free (class_);
+}
+
 /* Traditional GNU Objective-C Runtime API.  */
 /* Get the class object for the class named NAME.  If NAME does not
    identify a known class, the hook _objc_lookup_class is called.  If
@@ -807,6 +1000,11 @@ class_getSuperclass (Class class_)
   if (class_ == Nil)
     return Nil;
 
+  /* Classes that are in construction are not resolved and can not be
+     resolved!  */
+  if (CLS_IS_IN_CONSTRUCTION (class_))
+    return Nil;
+
   /* If the class is not resolved yet, super_class would point to a
      string (the name of the super class) as opposed to the actual
      super class.  In that case, we need to resolve the class links
index 33fb7979ef7b32d928fa07f50a118d78717ba448..dd8789c9cac04aa3b2629b5f18f444a59073aece 100644 (file)
@@ -623,23 +623,7 @@ __objc_exec_class (Module_t module)
         In some cases it isn't and this crashes the program.  */
       class->subclass_list = NULL;
 
-      /* Store the class in the class table and assign class numbers.  */
-      __objc_add_class_to_hash (class);
-
-      /* Register all of the selectors in the class and meta class.  */
-      __objc_register_selectors_from_class (class);
-      __objc_register_selectors_from_class ((Class) class->class_pointer);
-
-      /* Install the fake dispatch tables */
-      __objc_install_premature_dtable (class);
-      __objc_install_premature_dtable (class->class_pointer);
-
-      /* Register the instance methods as class methods, this is
-        only done for root classes.  */
-      __objc_register_instance_methods_to_class (class);
-
-      if (class->protocols)
-       __objc_init_protocols (class->protocols);
+      __objc_init_class (class);
 
       /* Check to see if the superclass is known in this point. If it's not
         add the class to the unresolved_classes list.  */
@@ -864,6 +848,29 @@ init_check_module_version (Module_t module)
     }
 }
 
+/* __objc_init_class must be called with __objc_runtime_mutex already locked.  */
+void
+__objc_init_class (Class class)
+{
+  /* Store the class in the class table and assign class numbers.  */
+  __objc_add_class_to_hash (class);
+  
+  /* Register all of the selectors in the class and meta class.  */
+  __objc_register_selectors_from_class (class);
+  __objc_register_selectors_from_class ((Class) class->class_pointer);
+
+  /* Install the fake dispatch tables */
+  __objc_install_premature_dtable (class);
+  __objc_install_premature_dtable (class->class_pointer);
+
+  /* Register the instance methods as class methods, this is only done
+     for root classes.  */
+  __objc_register_instance_methods_to_class (class);
+
+  if (class->protocols)
+    __objc_init_protocols (class->protocols);
+}
+
 /* __objc_init_protocol must be called with __objc_runtime_mutex
    already locked, and the "Protocol" class already registered.  */
 static void
index 9e9a84b068e99d8ea7fb0647e72303744ecdd29f..8d5f4abdd393bb2f4436b00df46a10594df08afe 100644 (file)
@@ -32,9 +32,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 struct objc_ivar *
 class_getInstanceVariable (Class class_, const char *name)
 {
-  if (class_ != Nil  &&  name != NULL)
+  if (class_ != Nil  &&  name != NULL  &&  ! CLS_IS_IN_CONSTRUCTION (class_))
     {
-      objc_mutex_lock (__objc_runtime_mutex);
       while (class_ != Nil)
        {
          struct objc_ivar_list *ivars = class_->ivars;
@@ -48,14 +47,12 @@ class_getInstanceVariable (Class class_, const char *name)
                  
                  if (!strcmp (ivar->ivar_name, name))
                    {
-                     objc_mutex_unlock (__objc_runtime_mutex);
                      return ivar;
                    }
                }
            }
          class_ = class_getSuperclass (class_);
        }
-      objc_mutex_unlock (__objc_runtime_mutex);
     }
   return NULL;
 }
@@ -185,22 +182,13 @@ struct objc_ivar ** class_copyIvarList (Class class_, unsigned int *numberOfRetu
   struct objc_ivar **returnValue = NULL;
   struct objc_ivar_list* ivar_list;
 
-  if (class_ == Nil)
+  if (class_ == Nil  ||  CLS_IS_IN_CONSTRUCTION (class_))
     {
       if (numberOfReturnedIvars)
        *numberOfReturnedIvars = 0;
       return NULL;
     }
-
-  /* TODO: We do not need to lock the runtime mutex if the class has
-     been registered with the runtime, since the instance variable
-     list can not change after the class is registered.  The only case
-     where the lock may be useful if the class is still being created
-     using objc_allocateClassPair(), but has not been registered using
-     objc_registerClassPair() yet.  I'm not even sure that is
-     allowed.  */
-  objc_mutex_lock (__objc_runtime_mutex);
-
+    
   /* Count how many ivars we have.  */
   ivar_list = class_->ivars;
   count = ivar_list->ivar_count;
@@ -221,14 +209,99 @@ struct objc_ivar ** class_copyIvarList (Class class_, unsigned int *numberOfRetu
       returnValue[i] = NULL;
     }
   
-  objc_mutex_unlock (__objc_runtime_mutex);
-
   if (numberOfReturnedIvars)
     *numberOfReturnedIvars = count;
 
   return returnValue;
 }
 
+BOOL
+class_addIvar (Class class_, const char * ivar_name, size_t size,
+              unsigned char alignment, const char *type)
+{
+  struct objc_ivar_list *ivars;
+
+  if (class_ == Nil
+      || (! CLS_IS_IN_CONSTRUCTION (class_))  
+      || ivar_name == NULL  
+      || (strcmp (ivar_name, "") == 0)
+      || size == 0
+      || type == NULL)
+    return NO;
+
+  /* Check if the class has an instance variable with that name
+     already.  */
+  ivars = class_->ivars;
+
+  if (ivars != NULL)
+    {
+      int i;
+      
+      for (i = 0; i < ivars->ivar_count; i++)
+       {
+         struct objc_ivar *ivar = &(ivars->ivar_list[i]);
+         
+         if (strcmp (ivar->ivar_name, ivar_name) == 0)
+           {
+             return NO;
+           }
+       }
+    }
+
+  /* Ok, no direct ivars.  Check superclasses.  */
+  if (class_getInstanceVariable (objc_getClass ((char *)(class_->super_class)),
+                                ivar_name))
+    return NO;
+
+  /* Good.  Create space for the new instance variable.  */
+  if (ivars)
+    {
+      int ivar_count = ivars->ivar_count + 1;
+      int new_size = sizeof (struct objc_ivar_list) 
+       + (ivar_count - 1) * sizeof (struct objc_ivar);
+      
+      ivars = (struct objc_ivar_list*) objc_realloc (ivars, new_size);
+      ivars->ivar_count = ivar_count;
+      class_->ivars = ivars;
+    }
+  else
+    {
+      int new_size = sizeof (struct objc_ivar_list);
+      
+      ivars = (struct objc_ivar_list*) objc_malloc (new_size);
+      ivars->ivar_count = 1;
+      class_->ivars = ivars;
+    }
+    
+  /* Now ivars is set to a list of instance variables of the right
+     size. */
+  {
+    struct objc_ivar *ivar = &(ivars->ivar_list[ivars->ivar_count - 1]);
+    int misalignment;
+    
+    ivar->ivar_name = objc_malloc (strlen (ivar_name) + 1);
+    strcpy ((char *)ivar->ivar_name, ivar_name);
+
+    ivar->ivar_type = objc_malloc (strlen (type) + 1);
+    strcpy ((char *)ivar->ivar_type, type);
+
+    /* The new instance variable is placed at the end of the existing
+       instance_size, at the first byte that is aligned with
+       alignment.  */
+    misalignment = class_->instance_size % alignment;
+    
+    if (misalignment == 0)
+      ivar->ivar_offset = class_->instance_size;
+    else
+      ivar->ivar_offset = class_->instance_size - misalignment + alignment;
+    
+    class_->instance_size = ivar->ivar_offset + objc_sizeof_type (ivar->ivar_type);
+  }
+  
+  return YES;
+}
+
+
 const char *
 property_getName (struct objc_property * property __attribute__ ((__unused__)))
 {
index 7505a6b0bf3f89ae93339718f7ea704e9ded71bd..bad547834ffda25c8c21e33e4932a66585a02e4b 100644 (file)
@@ -181,7 +181,7 @@ struct objc_protocol_list
   places a string in the following member variables: super_class.
 */
 #ifndef __objc_STRUCT_OBJC_CLASS_defined
-struct objc_class {     
+struct objc_class {
   struct objc_class*  class_pointer;    /* Pointer to the class's meta
                                           class. */
   struct objc_class*  super_class;      /* Pointer to the super
@@ -234,6 +234,7 @@ struct objc_class {
 #define __CLS_INFO(cls) ((cls)->info)
 #define __CLS_ISINFO(cls, mask) ((__CLS_INFO(cls)&mask)==mask)
 #define __CLS_SETINFO(cls, mask) (__CLS_INFO(cls) |= mask)
+#define __CLS_SETNOTINFO(cls, mask) (__CLS_INFO(cls) &= ~mask)
 
 /* The structure is of type MetaClass */
 #define _CLS_META 0x2L
@@ -255,6 +256,16 @@ struct objc_class {
 #define CLS_ISINITIALIZED(cls) __CLS_ISINFO(cls, _CLS_INITIALIZED)
 #define CLS_SETINITIALIZED(cls) __CLS_SETINFO(cls, _CLS_INITIALIZED)
 
+/* The class is being constructed; it has been allocated using
+   objc_allocateClassPair(), but has not been registered yet by using
+   objc_registerClassPair().  This means it is possible to freely add
+   instance variables to the class, but it can't be used for anything
+   yet.  */
+#define _CLS_IN_CONSTRUCTION 0x10L
+#define CLS_IS_IN_CONSTRUCTION(cls) __CLS_ISINFO(cls, _CLS_IN_CONSTRUCTION)
+#define CLS_SET_IN_CONSTRUCTION(cls) __CLS_SETINFO(cls, _CLS_IN_CONSTRUCTION)
+#define CLS_SET_NOT_IN_CONSTRUCTION(cls) __CLS_SETNOTINFO(cls, _CLS_IN_CONSTRUCTION)
+
 /* The class number of this class.  This must be the same for both the
    class and its meta class object.  */
 #define CLS_GETNUMBER(cls) (__CLS_INFO(cls) >> (HOST_BITS_PER_LONG/2))
index ff924becd937f74477ac67ee86edf843b5d94aef..4769d0f659291810c0594627da36c685112b23b1 100644 (file)
@@ -67,7 +67,7 @@ extern void __objc_update_dispatch_table_for_class (Class);/* (objc-msg.c) */
 extern int  __objc_init_thread_system(void);    /* thread.c */
 extern int  __objc_fini_thread_system(void);    /* thread.c */
 extern void __objc_print_dtable_stats(void);    /* sendmsg.c */
-
+extern void __objc_init_class (Class class);  /* init.c */
 extern void class_add_method_list(Class, struct objc_method_list *);
 
 /* Registering instance methods as class methods for root classes */
index 0bbd7e9524e665f88934040bb790f99f60b7c926..0b6f3dfc99b30a62a2413fdb4cefdd6257afcb97 100644 (file)
@@ -302,9 +302,36 @@ objc_EXPORT const char * ivar_getTypeEncoding (Ivar variable);
    include instance variables of superclasses.  The list is terminated
    by NULL.  Optionally, if you pass a non-NULL
    'numberOfReturnedIvars' pointer, the unsigned int that it points to
-   will be filled with the number of instance variables returned.  */
+   will be filled with the number of instance variables returned.
+   Return NULL for classes still in construction (ie, allocated using
+   objc_allocatedClassPair() but not yet registered with the runtime
+   using objc_registerClassPair()).  */
 objc_EXPORT Ivar * class_copyIvarList (Class class_, unsigned int *numberOfReturnedIvars);
 
+/* Add an instance variable with name 'ivar_name' to class 'class_',
+   where 'class_' is a class in construction that has been created
+   using objc_allocateClassPair() and has not been registered with the
+   runtime using objc_registerClassPair() yet.  You can not add
+   instance variables to classes already registered with the runtime.
+   'size' is the size of the instance variable, 'alignment' the
+   alignment, and 'type' the type encoding of the variable type.  You
+   can use objc_sizeof_type() (or sizeof()), objc_alignof_type() (or
+   __alignof__()) and @encode() to determine the right 'size',
+   'alignment' and 'type' for your instance variable.  For example, to
+   add an instance variable name "my_variable" and of type 'id', you
+   can use:
+
+   class_addIvar (class, "my_variable", sizeof (id), __alignof__ (id), 
+                  @encode (id));
+
+   Return YES if the variable was added, and NO if not.  In
+   particular, return NO if 'class_' is Nil, or a meta-class or a
+   class not in construction.  Return Nil also if 'ivar_name' or
+   'type' is NULL, or 'size' is 0.
+ */
+objc_EXPORT BOOL class_addIvar (Class class_, const char * ivar_name, size_t size,
+                               unsigned char alignment, const char *type);
+
 /* Return the name of the property.  Return NULL if 'property' is
    NULL.  */
 objc_EXPORT const char * property_getName (Property property);
@@ -383,7 +410,6 @@ typedef Class (*objc_get_unknown_class_handler)(const char *class_name);
 objc_get_unknown_class_handler
 objc_setGetUnknownClassHandler (objc_get_unknown_class_handler new_handler);
 
-
 /* Return the class with name 'name', if it is already registered with
    the runtime.  If it is not registered, and
    objc_setGetUnknownClassHandler() has been called to set a handler
@@ -437,11 +463,11 @@ objc_EXPORT const char * class_getName (Class class_);
    is Nil, return NO.  */
 objc_EXPORT BOOL class_isMetaClass (Class class_);
 
-/* Return the superclass of 'class_'.  If 'class_' is Nil, or it is a root
-   class, return Nil.
-
-   TODO: It may be worth to define this inline, since it is usually
-   used in loops when traversing the class hierarchy.  */
+/* Return the superclass of 'class_'.  If 'class_' is Nil, or it is a
+   root class, return Nil.  If 'class_' is a class being constructed,
+   that is, a class returned by objc_allocateClassPair() but before it
+   has been registered with the runtime using
+   objc_registerClassPair(), return Nil.  */
 objc_EXPORT Class class_getSuperclass (Class class_);
 
 /* Return the 'version' number of the class, which is an integer that
@@ -496,6 +522,64 @@ method_setImplementation (Method method, IMP implementation);
 objc_EXPORT void
 method_exchangeImplementations (Method method_a, Method method_b);
 
+/* Create a new class/meta-class pair.  This function is called to
+   create a new class at runtime.  The class is created with
+   superclass 'superclass' (use 'Nil' to create a new root class) and
+   name 'class_name'.  'extraBytes' can be used to specify some extra
+   space for indexed variables to be added at the end of the class and
+   meta-class objects (it is recommended that you set extraBytes to
+   0).  Once you have created the class, it is not usable yet.  You
+   need to add any instance variables (by using class_addIvar()), any
+   instance methods (by using class_addMethod()) and any class methods
+   (by using class_addMethod() on the meta-class, as in
+   class_addMethod (object_getClass (class), method)) that are
+   required, and then you need to call objc_registerClassPair() to
+   activate the class.  If you need to create a hierarchy of classes,
+   you need to create and register them one at a time.  You can not
+   create a new class using another class in construction as
+   superclass.  Return Nil if 'class-name' is NULL or if a class with
+   that name already exists or 'superclass' is a class still in
+   construction.
+
+   Implementation Note: in the GNU runtime, allocating a class pair
+   only creates the structures for the class pair, but does not
+   register anything with the runtime.  The class is registered with
+   the runtime only when objc_registerClassPair() is called.  In
+   particular, if a class is in construction, objc_getClass() will not
+   find it, the superclass will not know about it,
+   class_getSuperclass() will return Nil and another thread may
+   allocate a class pair with the same name; the conflict will only be
+   detected when the classes are registered with the runtime.
+ */
+objc_EXPORT Class
+objc_allocateClassPair (Class super_class, const char *class_name, 
+                       size_t extraBytes);
+
+/* Register a class pair that was created with
+   objc_allocateClassPair().  After you register a class, you can no
+   longer make changes to its instance variables, but you can start
+   creating instances of it.  Do nothing if 'class_' is NULL or if it
+   is not a class allocated by objc_allocateClassPair() and still in
+   construction.  */
+objc_EXPORT void
+objc_registerClassPair (Class class_);
+
+/* Dispose of a class pair created using objc_allocateClassPair().
+   Call this function if you started creating a new class with
+   objc_allocateClassPair() but then want to abort the process.  You
+   should not access 'class_' after calling this method.  Note that if
+   'class_' has already been registered with the runtime via
+   objc_registerClassPair(), this function does nothing; you can only
+   dispose of class pairs that are still being constructed.  Do
+   nothing if class is 'Nil' or if 'class_' is not a class being
+   constructed.  */
+objc_EXPORT void
+objc_disposeClassPair (Class class_);
+
+/* Compatibility Note: The Apple/NeXT runtime has the function
+   objc_duplicateClass () but it's undocumented.  The GNU runtime does
+   not have it.  */
+
 
 /** Implementation: the following functions are in sendmsg.c.  */
 
@@ -534,6 +618,33 @@ objc_EXPORT IMP class_getMethodImplementation (Class class_, SEL selector);
    (object_getClass (class_), selector)).  */
 objc_EXPORT BOOL class_respondsToSelector (Class class_, SEL selector);
 
+/* Add a method to a class.  Use this function to add a new method to
+   a class (potentially overriding a method with the same selector in
+   the superclass); if you want to modify an existing method, use
+   method_setImplementation() instead (or class_replaceMethod ()).
+   This method adds an instance method to 'class_'; to add a class
+   method, get the meta class first, then add the method to the meta
+   class, that is, use
+
+   class_addMethod (object_getClass (class_), selector,
+   implementation, type);
+
+   Return YES if the method was added, and NO if not.  Do nothing if
+   one of the arguments is NULL.  */
+objc_EXPORT BOOL class_addMethod (Class class_, SEL selector, IMP implementation,
+                                 const char *method_types);
+
+/* Replace a method in a class.  If the class already have a method
+   with this 'selector', find it and use method_setImplementation() to
+   replace the implementation with 'implementation' (method_types is
+   ignored in that case).  If the class does not already have a method
+   with this 'selector', call 'class_addMethod() to add it.
+
+   Return the previous implementation of the method, or NULL if none
+   was found.  Return NULL if any of the arguments is NULL.  */
+objc_EXPORT IMP class_replaceMethod (Class class_, SEL selector, IMP implementation,
+                                    const char *method_types);
+
 
 /** Implementation: the following functions are in methods.c.  */
 
index d68e3040f4f33edbda11facfe51a7293b54c1cd8..ee1f0a36150c6ae0de0987291f02a994bd31cc6d 100644 (file)
@@ -42,6 +42,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #include <assert.h> /* For assert */
 #include <string.h> /* For strlen */
 
+/* Temporarily while we include objc/objc-api.h instead of objc-private/module-abi-8.h.  */
+#define _CLS_IN_CONSTRUCTION 0x10L
+#define CLS_IS_IN_CONSTRUCTION(cls) __CLS_ISINFO(cls, _CLS_IN_CONSTRUCTION)
+
 /* This is how we hack STRUCT_VALUE to be 1 or 0.   */
 #define gen_rtx(args...) 1
 #define gen_rtx_MEM(args...) 1
@@ -573,6 +577,80 @@ class_getClassMethod (Class class_, SEL selector)
                                         selector);
 }
 
+BOOL
+class_addMethod (Class class_, SEL selector, IMP implementation,
+                const char *method_types)
+{
+  struct objc_method_list *method_list;
+  struct objc_method *method;
+  const char *method_name;
+
+  if (class_ == Nil  ||  selector == NULL  ||  implementation == NULL  
+      || method_types == NULL  || (strcmp (method_types, "") == 0))
+    return NO;
+
+  method_name = sel_get_name (selector);
+  if (method_name == NULL)
+    return NO;
+
+  method_list = (struct objc_method_list *)objc_calloc (1, sizeof (struct objc_method_list));
+  method_list->method_count = 1;
+
+  method = &(method_list->method_list[0]);
+  method->method_name = objc_malloc (strlen (method_name) + 1);
+  strcpy ((char *)method->method_name, method_name);
+
+  method->method_types = objc_malloc (strlen (method_types) + 1);
+  strcpy ((char *)method->method_types, method_types);
+  
+  method->method_imp = implementation;
+  
+  if (CLS_IS_IN_CONSTRUCTION (class_))
+    {
+      /* We only need to add the method to the list.  It will be
+        registered with the runtime when the class pair is registered
+        (if ever).  */
+      method_list->method_next = class_->methods;
+      class_->methods = method_list;
+    }
+  else
+    {
+      /* Add the method to a live class.  */
+      objc_mutex_lock (__objc_runtime_mutex);
+      class_add_method_list (class_, method_list);
+      objc_mutex_unlock (__objc_runtime_mutex);
+    }
+
+  return YES;
+}
+
+/* Temporarily, until we include objc/runtime.h.  */
+extern IMP
+method_setImplementation (struct objc_method * method, IMP implementation);
+
+IMP
+class_replaceMethod (Class class_, SEL selector, IMP implementation,
+                    const char *method_types)
+{
+  struct objc_method * method;
+
+  if (class_ == Nil  ||  selector == NULL  ||  implementation == NULL
+      || method_types == NULL)
+    return NULL;
+
+  method = search_for_method_in_hierarchy (class_, selector);
+
+  if (method)
+    {
+      return method_setImplementation (method, implementation);
+    }
+  else
+    {
+      class_addMethod (class_, selector, implementation, method_types);
+      return NULL;
+    }
+}
+
 /* Search for a method starting from the current class up its hierarchy.
    Return a pointer to the method's method structure if found.  NULL
    otherwise. */