aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicola Pero <nicola.pero@meta-innovation.com>2010-10-16 21:26:59 +0000
committerNicola Pero <nicola@gcc.gnu.org>2010-10-16 21:26:59 +0000
commit6c5c7efd6bbca80cb28fffd24600cbb58436f808 (patch)
tree3920a8a13cd2db3193c61dca0c4a3e93ab0c05f5
parentd4d9b0a64193609249caa5db60afc6cb0bf50e2a (diff)
In libobjc/: 2010-10-16 Nicola Pero <nicola.pero@meta-innovation.com>
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
-rw-r--r--libobjc/ChangeLog29
-rw-r--r--libobjc/class.c198
-rw-r--r--libobjc/init.c41
-rw-r--r--libobjc/ivars.c107
-rw-r--r--libobjc/objc-private/module-abi-8.h13
-rw-r--r--libobjc/objc-private/runtime.h2
-rw-r--r--libobjc/objc/runtime.h125
-rw-r--r--libobjc/sendmsg.c78
8 files changed, 550 insertions, 43 deletions
diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog
index 2142b893c18..1d2b2948605 100644
--- a/libobjc/ChangeLog
+++ b/libobjc/ChangeLog
@@ -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.
diff --git a/libobjc/class.c b/libobjc/class.c
index 71483457e25..ade5a71f453 100644
--- a/libobjc/class.c
+++ b/libobjc/class.c
@@ -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
diff --git a/libobjc/init.c b/libobjc/init.c
index 33fb7979ef7..dd8789c9cac 100644
--- a/libobjc/init.c
+++ b/libobjc/init.c
@@ -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
diff --git a/libobjc/ivars.c b/libobjc/ivars.c
index 9e9a84b068e..8d5f4abdd39 100644
--- a/libobjc/ivars.c
+++ b/libobjc/ivars.c
@@ -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__)))
{
diff --git a/libobjc/objc-private/module-abi-8.h b/libobjc/objc-private/module-abi-8.h
index 7505a6b0bf3..bad547834ff 100644
--- a/libobjc/objc-private/module-abi-8.h
+++ b/libobjc/objc-private/module-abi-8.h
@@ -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))
diff --git a/libobjc/objc-private/runtime.h b/libobjc/objc-private/runtime.h
index ff924becd93..4769d0f6592 100644
--- a/libobjc/objc-private/runtime.h
+++ b/libobjc/objc-private/runtime.h
@@ -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 */
diff --git a/libobjc/objc/runtime.h b/libobjc/objc/runtime.h
index 0bbd7e9524e..0b6f3dfc99b 100644
--- a/libobjc/objc/runtime.h
+++ b/libobjc/objc/runtime.h
@@ -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. */
diff --git a/libobjc/sendmsg.c b/libobjc/sendmsg.c
index d68e3040f4f..ee1f0a36150 100644
--- a/libobjc/sendmsg.c
+++ b/libobjc/sendmsg.c
@@ -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. */