diff mbox

=?UTF-8?Q?libobjc=20-=20more=20modern=20Objective-C=20runtime=20API=20(1?= =?UTF-8?Q?2)?=

Message ID 1287264455.5625462@192.168.2.227
State New
Headers show

Commit Message

Nicola Pero Oct. 16, 2010, 9:27 p.m. UTC
This patch adds the last missing bits in the new API - to create new classes and adding ivars and methods.  It also includes two testcases that test all the new API objc_xxx and class_xxx functions. :-)

Committed to trunk.

Thanks

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.

In gcc/testsuite/:
2010-10-16  Nicola Pero  <nicola.pero@meta-innovation.com>

        * objc.dg/gnu-api-2-class.m: New.
        * objc.dg/gnu-api-2-objc.m: New.

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 165562)
+++ ChangeLog	(working copy)
@@ -1,5 +1,10 @@
 2010-10-16  Nicola Pero  <nicola.pero@meta-innovation.com>
 
+	* objc.dg/gnu-api-2-class.m: New.
+	* objc.dg/gnu-api-2-objc.m: New.
+
+2010-10-16  Nicola Pero  <nicola.pero@meta-innovation.com>
+
 	* objc.dg/gnu-api-2-ivar.m: New.
 
 2010-10-15  Nicola Pero  <nicola.pero@meta-innovation.com>
Index: objc.dg/gnu-api-2-objc.m
===================================================================
--- objc.dg/gnu-api-2-objc.m	(revision 0)
+++ objc.dg/gnu-api-2-objc.m	(revision 0)
@@ -0,0 +1,242 @@
+/* Test the Modern GNU Objective-C Runtime API.
+
+  This is test 'objc', covering all functions starting with 'objc'.  */
+
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
+
+/* To get the modern GNU Objective-C Runtime API, you include
+   objc/runtime.h.  */
+#include <objc/runtime.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+@interface MyRootClass
+{ Class isa; }
++ alloc;
+- init;
+@end
+
+@implementation MyRootClass
++ alloc { return class_createInstance (self, 0); }
+- init  { return self; }
+@end
+
+@protocol MyProtocol
+- (id) variable;
+@end
+
+@protocol MySecondProtocol
+- (id) setVariable: (id)value;
+@end
+
+@interface MySubClass : MyRootClass <MyProtocol>
+{ id variable_ivar; }
+- (void) setVariable: (id)value;
+- (id) variable;
+@end
+
+@implementation MySubClass
+- (void) setVariable: (id)value { variable_ivar = value; }
+- (id) variable { return variable_ivar; }
+@end
+
+
+int main(int argc, void **args)
+{
+  /* Functions are tested in alphabetical order.  */
+
+  printf ("Testing objc_allocateClassPair ()...\n");
+  {
+    Class new_root_class = objc_allocateClassPair (Nil, "MyNewRootClass", 0);
+    Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass", 0);
+
+    /* A new root class would obviously need at least an 'isa'
+       instance variable.  We don't add it so we never actually
+       instantiate an instance of the class, which wouldn't work.  */
+
+    objc_registerClassPair (new_root_class);
+    objc_registerClassPair (new_class);
+
+    if (strcmp (class_getName (new_class), "MyNewSubClass") != 0)
+      abort ();
+
+    if (class_getSuperclass (new_class) != objc_getClass ("MyRootClass"))
+      abort ();
+
+    if (strcmp (class_getName (new_root_class), "MyNewRootClass") != 0)
+      abort ();
+
+    if (class_getSuperclass (new_root_class) != Nil)
+      abort ();
+
+    {
+      MySubClass *o = [[objc_getClass ("MyNewSubClass") alloc] init];
+      
+      if (object_getClass (o) != objc_getClass ("MyNewSubClass"))
+	abort ();
+    }
+  }
+
+  printf ("Testing objc_copyProtocolList ()...\n");
+  {
+    /* Make sure both our two protocols are known to the runtime.  */
+    id my_protocol = @protocol (MyProtocol);
+    id my_second_protocol = @protocol (MySecondProtocol);
+    unsigned int count;
+    Protocol ** list = objc_copyProtocolList (&count);
+
+    if (count != 2)
+      abort ();
+
+    if (! ((strcmp (protocol_getName (list[0]), "MyProtocol") == 0
+	    && strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0)
+	   || (strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0
+	       && strcmp (protocol_getName (list[1]), "MyProtocol") == 0)))
+      abort ();
+    
+    if (list[2] != NULL)
+      abort ();
+  }
+
+  printf ("Testing objc_disposeClassPair ()...\n");
+  {
+    Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:));
+    Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass", 0);
+
+    /* Add a bit of everything to the class to exercise undoing all these changes.  */
+
+    /* Instance variable.  */
+    class_addIvar (new_class, "my_variable", sizeof (float), __alignof__ (float), @encode (float));
+
+    /* Instance method.  */
+    class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method),
+		     method_getTypeEncoding (method));
+
+    /* Class method.  */
+    class_addMethod (object_getClass (new_class), @selector (setVariable:), method_getImplementation (method),
+		     method_getTypeEncoding (method));
+
+    /* Protocol.  */
+    class_addProtocol (new_class, @protocol (MyProtocol));
+
+    objc_disposeClassPair (new_class);
+  }
+
+  /* This function currently does not exist with the GNU runtime.  */
+  /* printf ("Testing objc_duplicateClass ()...\n"); */
+
+  /* TODO - Test it when implemented in the GNU Runtime */
+  /*  printf ("Testing objc_getAssociatedObject ()...\n");  */
+
+  printf ("Testing objc_getClass ()...\n");
+  {
+    if (strcmp (class_getName (objc_getClass ("MySubClass")),
+		"MySubClass") != 0)
+      abort ();
+  }
+
+  printf ("Testing objc_getClassList ()...\n");
+  {
+    Class *list;
+    int i, count, other_count;
+    count = objc_getClassList (NULL, 0);
+
+    /* count most likely will be 5, (MyRootClass, MySubClass,
+       Protocol, Object, NXConstantString).  */
+    if (count < 3)
+      abort ();
+    
+    list = malloc (sizeof (Class) * count);
+    other_count = objc_getClassList (list, count);
+
+    if (other_count != count)
+      abort ();
+
+    /* Spot-check: search for class 'MyRootClass' in the list.  */
+    for (i = 0; i < count; i++)
+      {
+	if (strcmp (class_getName (list[i]), "MyRootClass") == 0)
+	  break;
+      }
+    if (i == count)
+      abort ();
+
+    /* Spot-check: search for class 'MySubClass' in the list.  */
+    for (i = 0; i < count; i++)
+      {
+	if (strcmp (class_getName (list[i]), "MySubClass") == 0)
+	  break;
+      }
+    if (i == count)
+      abort ();
+
+    /* Spot-check: search for class 'Protocol' in the list.  */
+    for (i = 0; i < count; i++)
+      {
+	if (strcmp (class_getName (list[i]), "Protocol") == 0)
+	  break;
+      }
+    if (i == count)
+      abort ();
+  }
+
+  /* This function does not exist with the GNU runtime.  */
+  /* printf ("Testing objc_getFutureClass ()...\n"); */
+
+  printf ("Testing objc_getMetaClass ()...\n");
+  {
+    if (! class_isMetaClass (objc_getMetaClass ("MyRootClass")))
+      abort ();
+  }
+
+  printf ("Testing objc_getProtocol ()...\n");
+  {
+    if (! protocol_isEqual (objc_getProtocol ("MyProtocol"), @protocol (MyProtocol)))
+      abort ();
+  }
+
+  printf ("Testing objc_getRequiredClass ()...\n");
+  {
+    if (strcmp (class_getName (objc_getRequiredClass ("MyRootClass")),
+		"MyRootClass") != 0)
+      abort ();
+  }
+
+  printf ("Testing objc_lookupClass ()...\n");
+  {
+    if (strcmp (class_getName (objc_lookupClass ("MyRootClass")),
+		"MyRootClass") != 0)
+      abort ();
+  }
+
+  /* This function does not exist with the GNU runtime.  */
+  /* printf ("Testing objc_setFutureClass ()...\n"); */
+
+  printf ("Testing objc_registerClassPair ()...\n");
+  {
+    Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0);
+
+    class_addProtocol (new_class, @protocol (MySecondProtocol));
+    
+    objc_registerClassPair (new_class);
+    
+    if (strcmp (class_getName (new_class), "MySubSubClass") != 0)
+      abort ();
+
+    if (class_getSuperclass (new_class) != objc_getClass ("MySubClass"))
+      abort ();
+
+    if (! class_conformsToProtocol (new_class, @protocol (MySecondProtocol)))
+      abort ();
+  }
+
+  /* TODO - Test it when implemented in the GNU Runtime */
+  /*  printf ("Testing objc_removeAssociatedObjects ()...\n");  */
+
+  /* TODO - Test it when implemented in the GNU Runtime */
+  /*  printf ("Testing objc_setAssociatedObject ()...\n");  */
+
+  return 0;
+}
Index: objc.dg/gnu-api-2-class.m
===================================================================
--- objc.dg/gnu-api-2-class.m	(revision 0)
+++ objc.dg/gnu-api-2-class.m	(revision 0)
@@ -0,0 +1,441 @@
+/* Test the Modern GNU Objective-C Runtime API.
+
+  This is test 'class', covering all functions starting with 'class'.  */
+
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
+
+/* To get the modern GNU Objective-C Runtime API, you include
+   objc/runtime.h.  */
+#include <objc/runtime.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+@interface MyRootClass
+{ Class isa; }
++ alloc;
+- init;
+@end
+
+@implementation MyRootClass
++ alloc { return class_createInstance (self, 0); }
+- init  { return self; }
+@end
+
+@protocol MyProtocol
+- (id) variable;
+@end
+
+@protocol MySecondProtocol
+- (id) setVariable: (id)value;
+@end
+
+@interface MySubClass : MyRootClass <MyProtocol>
+{ id variable_ivar; }
+- (void) setVariable: (id)value;
+- (id) variable;
+@end
+
+@implementation MySubClass
+- (void) setVariable: (id)value { variable_ivar = value; }
+- (id) variable { return variable_ivar; }
+@end
+
+@interface DifferentClass : MyRootClass
+- (id) myClass;
+- (id) self;
+@end
+
+@implementation DifferentClass
+- (id) myClass { return object_getClass (self); }
+- (id) self { return self; }
+@end
+
+@interface MySubClass (MySelf)
+- (id) mySelf;
+@end
+
+int main(int argc, void **args)
+{
+  /* Functions are tested in alphabetical order.  */
+
+  printf ("Testing class_addIvar ()...\n");
+  {
+    Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0);
+
+    if (new_class == Nil)
+      abort ();
+    
+    if (! class_addIvar (new_class, "variable2_ivar", sizeof (id),
+			 __alignof__ (id), @encode (id)))
+      abort ();
+
+    if (! class_addIvar (new_class, "variable3_ivar", sizeof (unsigned char),
+			 __alignof__ (unsigned char), @encode (unsigned char)))
+      abort ();
+
+    if (! class_addIvar (new_class, "variable4_ivar", sizeof (unsigned long),
+			 __alignof__ (unsigned long), @encode (unsigned long)))
+      abort ();
+
+    objc_registerClassPair (new_class);    
+
+    {
+      MySubClass *o = [[objc_getClass ("MySubSubClass") alloc] init];
+      Ivar variable2 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable2_ivar");
+      Ivar variable3 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable3_ivar");
+      Ivar variable4 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable4_ivar");
+
+      if (variable2 == NULL  || variable3 == NULL  ||  variable4 == NULL)
+	abort ();
+      
+      if (strcmp (ivar_getName (variable2), "variable2_ivar") != 0)
+	abort ();
+
+      if (strcmp (ivar_getName (variable3), "variable3_ivar") != 0)
+	abort ();
+
+      if (strcmp (ivar_getName (variable4), "variable4_ivar") != 0)
+	abort ();
+
+      {
+	unsigned char *var3 = (unsigned char *)((char *)o + ivar_getOffset (variable3));
+	unsigned long *var4 = (unsigned long *)((char *)o + ivar_getOffset (variable4));
+
+	object_setIvar (o, variable2, new_class);
+	*var3 = 230;
+	*var4 = 89000L;
+
+	if (object_getIvar (o, variable2) != new_class)
+	  abort ();
+
+	if (*var3 != 230)
+	  abort ();
+
+	if (*var4 != 89000L)
+	  abort ();
+      }
+    }
+  }
+
+  printf ("Testing class_addMethod ()...\n");
+  {
+    Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass2", 0);
+    Method method1 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:));
+    Method method2 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (variable));
+
+    if (new_class == Nil)
+      abort ();
+    
+    if (! class_addIvar (new_class, "variable_ivar", sizeof (id),
+			 __alignof__ (id), @encode (id)))
+      abort ();
+
+    if (! class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method1),
+			   method_getTypeEncoding (method1)))
+      abort ();
+
+    if (! class_addMethod (new_class, @selector (variable), method_getImplementation (method2),
+			   method_getTypeEncoding (method2)))
+      abort ();
+
+    objc_registerClassPair (new_class);    
+
+    /* Now, MySubClass2 is basically the same as MySubClass!  We'll
+       use the variable and setVariable: methods on it.  */
+    {
+      MySubClass *o = (MySubClass *)[[objc_getClass ("MySubClass2") alloc] init];
+
+      [o setVariable: o];
+
+      if ([o variable] != o)
+	abort ();
+    }
+  }
+
+  printf ("Testing class_addProtocol ()...\n");
+  {
+    if (!class_addProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol)))
+      abort ();
+    
+    if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol)))
+      abort ();
+
+    if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol)))
+      abort ();
+  }
+
+  printf ("Testing class_conformsToProtocol ()...\n");
+  {
+    if (class_conformsToProtocol (objc_getClass ("MyRootClass"), @protocol (MyProtocol)))
+      abort ();
+
+    if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol)))
+      abort ();
+  }
+
+  printf ("Testing class_copyIvarList ()...\n");
+  {
+    unsigned int count;
+    Ivar * list = class_copyIvarList (objc_getClass ("MySubClass"), &count);
+
+    if (count != 1)
+      abort ();
+
+    if (strcmp (ivar_getName (list[0]), "variable_ivar") != 0)
+      abort ();
+    
+    if (list[1] != NULL)
+      abort ();
+  }
+
+  printf ("Testing class_copyMethodList ()...\n");
+  {
+    unsigned int count;
+    Method * list = class_copyMethodList (objc_getClass ("MySubClass"), &count);
+
+    if (count != 2)
+      abort ();
+    
+    if (! ((strcmp (sel_getName (method_getName (list[0])), "variable") == 0
+	    && strcmp (sel_getName (method_getName (list[1])), "setVariable:") == 0)
+	   || (strcmp (sel_getName (method_getName (list[0])), "setVariable:") == 0
+	       && strcmp (sel_getName (method_getName (list[1])), "variable") == 0)))
+      abort ();
+    
+    if (list[2] != NULL)
+      abort ();
+  }
+
+  /* TODO: Test new ABI (when available).  */
+  printf ("Testing class_copyPropertyList ()...\n");
+  {
+    unsigned int count;
+    Property * list = class_copyPropertyList (objc_getClass ("MySubClass"), &count);
+
+    if (count != 0  ||  list != NULL)
+      abort ();
+  }
+
+  printf ("Testing class_copyProtocolList ()...\n");
+  {
+    unsigned int count;
+    Protocol ** list = class_copyProtocolList (objc_getClass ("MySubClass"), &count);
+
+    /* Remember that we added MySecondProtocol in the test above.  */
+    if (count != 2)
+      abort ();
+
+    if (! ((strcmp (protocol_getName (list[0]), "MyProtocol") == 0
+	    && strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0)
+	   || (strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0
+	       && strcmp (protocol_getName (list[1]), "MyProtocol") == 0)))
+      abort ();
+    
+    if (list[2] != NULL)
+      abort ();
+  }
+
+  printf ("Testing class_createInstance ()...\n");
+  {
+    MySubClass *object = [[MySubClass alloc] init];
+
+    [object setVariable: object];
+    if ([object variable] != object)
+      abort ();
+  }
+
+  printf ("Testing class_getClassMethod ()...\n");
+  {
+    Method method = class_getClassMethod (objc_getClass ("MySubClass"),
+					  @selector(alloc));
+
+    if (method == NULL)
+      abort ();
+
+    if (strcmp (sel_getName (method_getName (method)), "alloc") != 0)
+      abort ();
+
+    if (class_getClassMethod (objc_getClass ("MySubClass"), 
+			      @selector(variable)))
+      abort ();
+  }
+
+  printf ("Testing class_getClassVariable ()...\n");
+  {
+    if (class_getClassVariable (objc_getClass ("MySubClass"), "variable_ivar"))
+      abort ();
+  }
+
+  printf ("Testing class_getInstanceMethod ()...\n");
+  {
+    Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), 
+					     @selector(variable));
+
+    if (method == NULL)
+      abort ();
+
+    if (strcmp (sel_getName (method_getName (method)), "variable") != 0)
+      abort ();
+
+    if (class_getInstanceMethod (objc_getClass ("MySubClass"), 
+				 @selector(alloc)))
+      abort ();
+  }
+
+  printf ("Testing class_getInstanceSize ()...\n");
+  {
+    if (class_getInstanceSize (objc_getClass ("MyRootClass")) != sizeof (struct objc_object))
+      abort ();
+  }
+
+  printf ("Testing class_getInstanceVariable ()...\n");
+  {
+    Ivar variable = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar");
+
+    if (variable == NULL)
+      abort ();
+
+    if (strcmp (ivar_getName (variable), "variable_ivar") != 0)
+      abort ();
+
+    if (class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar_no"))
+      abort ();
+  }
+
+  printf ("Testing class_getIvarLayout ()...\n");
+  {
+    if (class_getIvarLayout (objc_getClass ("MyRootClass")) != NULL)
+      abort ();
+  }
+
+  printf ("Testing class_getMethodImplementation ()...\n");
+  {
+    MySubClass *object = [[MySubClass alloc] init];
+    IMP imp = class_getMethodImplementation (objc_getClass ("MySubClass"), 
+					     @selector(variable));
+
+    if (imp == NULL)
+      abort ();
+
+    [object setVariable: object];
+
+    if ((*imp)(object, @selector(variable)) != object)
+      abort ();
+  }
+
+  /* This function does not exist with the GNU runtime.  */
+  /* printf ("Testing class_getMethodImplementation_stret ()...\n"); */
+
+  printf ("Testing class_getName ()...\n");
+  {
+    if (strcmp (class_getName (objc_getClass ("MyRootClass")),
+		"MyRootClass") != 0)
+      abort ();
+  }
+
+  /* TODO: Test new ABI (when available).  */
+  printf ("Testing class_getProperty ()...\n");
+  {
+    if (class_getProperty (objc_getClass ("MyRootClass"), "property") != NULL)
+      abort ();
+  }
+
+  printf ("Testing class_getSuperclass ()...\n");
+  {
+    MySubClass *object = [[MySubClass alloc] init];
+    if (class_getSuperclass (object_getClass (object)) != objc_getClass ("MyRootClass"))
+      abort ();
+  }
+
+  printf ("Testing class_getVersion ()...\n");
+  {
+    if (class_getVersion (objc_getClass ("MySubClass")) != 0)
+      abort ();
+  }
+
+   printf ("Testing class_getWeakIvarLayout ()...\n");
+  {
+    if (class_getWeakIvarLayout (objc_getClass ("MyRootClass")) != NULL)
+      abort ();
+  }
+
+  printf ("Testing class_isMetaClass ()...\n");
+  {
+    MySubClass *object = [[MySubClass alloc] init];
+    if (class_isMetaClass (object_getClass (object)) 
+	|| ! class_isMetaClass (object_getClass (object_getClass (object))))
+      abort ();
+  }
+
+  printf ("Testing class_replaceMethod ()...\n");
+  {
+    Method new_method = class_getInstanceMethod (objc_getClass ("DifferentClass"),
+						 @selector (myClass));
+    Method old_method = class_getInstanceMethod (objc_getClass ("MySubClass"),
+						 @selector (variable));
+    const char *new_types = method_getTypeEncoding (new_method);
+    IMP new_imp = method_getImplementation (new_method);
+    const char *old_types = method_getTypeEncoding (old_method);
+    IMP old_imp = class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable),
+				       method_getImplementation (new_method),
+				       method_getTypeEncoding (new_method));
+    MySubClass *o = [[MySubClass alloc] init];
+
+    [o setVariable: o];
+
+    /* Try the new method implementation.  */
+    if ([o variable] != objc_getClass ("MySubClass"))
+      abort ();
+
+    /* Put the original method back.  */
+    class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable),
+			 old_imp, old_types);
+
+    /* Test it's back to what it was.  */
+    if ([o variable] != o)
+      abort ();    
+
+    {
+      DifferentClass *o = [[DifferentClass alloc] init];
+
+      /* Finally, try adding a new method.  */
+      class_replaceMethod (objc_getClass ("DifferentClass"), @selector (mySelf),
+			   new_imp, new_types);
+      
+      if ([(MySubClass*)o mySelf] != objc_getClass ("DifferentClass"))
+	abort ();
+    }
+  }
+
+  printf ("Testing class_respondsToSelector ()...\n");
+  {
+    if (! class_respondsToSelector (objc_getClass ("MySubClass"), @selector(setVariable:)))
+      abort ();
+
+    if (class_respondsToSelector (objc_getClass ("MyRootClass"), @selector(setVariable:)))
+      abort ();
+  }
+
+  /* This is not really implemented with the GNU runtime.  */
+  /* printf ("Testing class_setIvarLayout ()...\n"); */
+
+  printf ("Testing class_setVersion ()...\n");
+  {
+    class_setVersion (objc_getClass ("MySubClass"), 45);
+    
+    if (class_getVersion (objc_getClass ("MySubClass")) != 45)
+      abort ();
+
+    class_setVersion (objc_getClass ("MySubClass"), 46);
+
+    if (class_getVersion (objc_getClass ("MySubClass")) != 46)
+      abort ();
+  }
+
+  /* This is not really implemented with the GNU runtime.  */
+  /* printf ("Testing class_setWeakIvarLayout ()...\n"); */
+
+  return 0;
+}
diff mbox

Patch

Index: sendmsg.c
===================================================================
--- sendmsg.c	(revision 165524)
+++ sendmsg.c	(working copy)
@@ -42,6 +42,10 @@  see the files COPYING3 and COPYING.RUNTIME respect
 #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. */   
Index: init.c
===================================================================
--- init.c	(revision 165524)
+++ init.c	(working copy)
@@ -623,24 +623,8 @@  __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);
+      __objc_init_class (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);
-
       /* Check to see if the superclass is known in this point. If it's not
 	 add the class to the unresolved_classes list.  */
       if (superclass && ! objc_lookup_class (superclass))
@@ -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: objc-private/module-abi-8.h
===================================================================
--- objc-private/module-abi-8.h	(revision 165524)
+++ objc-private/module-abi-8.h	(working copy)
@@ -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_protocol_list
 #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_protocol_list
 #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: objc-private/runtime.h
===================================================================
--- objc-private/runtime.h	(revision 165525)
+++ objc-private/runtime.h	(working copy)
@@ -67,7 +67,7 @@  extern void __objc_update_dispatch_table_for_class
 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: class.c
===================================================================
--- class.c	(revision 165542)
+++ class.c	(working copy)
@@ -570,6 +570,199 @@  objc_getClassList (Class *returnValue, int maxNumb
   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: ChangeLog
===================================================================
--- ChangeLog	(revision 165542)
+++ ChangeLog	(working copy)
@@ -1,5 +1,34 @@ 
 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
 	if the class is not resolved yet.
 	* ivars.c (class_getInstanceVariable): Use class_getSuperclass.
Index: ivars.c
===================================================================
--- ivars.c	(revision 165542)
+++ ivars.c	(working copy)
@@ -32,9 +32,8 @@  see the files COPYING3 and COPYING.RUNTIME respect
 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 cha
 		  
 		  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 clas
   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 clas
       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: objc/runtime.h
===================================================================
--- objc/runtime.h	(revision 165533)
+++ objc/runtime.h	(working copy)
@@ -302,9 +302,36 @@  objc_EXPORT const char * ivar_getTypeEncoding (Iva
    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)(co
 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 clas
    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,7 +522,65 @@  method_setImplementation (Method method, IMP imple
 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.  */
 
 /* Return the instance method with selector 'selector' of class
@@ -534,7 +618,34 @@  objc_EXPORT IMP class_getMethodImplementation (Cla
    (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.  */
 
 /* Return the selector for method 'method'.  Return NULL if 'method'