Commit 6c5c7efd by Nicola Pero Committed by Nicola Pero

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
parent d4d9b0a6
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.
......
......@@ -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
......
......@@ -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
......
......@@ -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__)))
{
......
......@@ -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))
......
......@@ -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 */
......
......@@ -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. */
......
......@@ -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. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment