+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
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
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
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. */
}
}
+/* __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
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;
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;
}
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;
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__)))
{
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
#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
#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))
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 */
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);
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
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
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. */
(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. */
#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
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. */