mirror of git://gcc.gnu.org/git/gcc.git
In libobjc/: 2010-10-15 Nicola Pero <nicola.pero@meta-innovation.com>
In libobjc/: 2010-10-15 Nicola Pero <nicola.pero@meta-innovation.com> * objc-private/runtime.h (__objc_update_classes_with_methods): New. * class.c (__objc_update_classes_with_methods): New. (objc_getClassList): Do not lock the class lock. * methods.c (method_exchangeImplementations): New. (method_setImplementation): New. * objc/runtime.h (method_setImplementation): New. (method_exchangeImplementations): New. From-SVN: r165525
This commit is contained in:
parent
ef7659966d
commit
51194e8eb5
|
@ -1,3 +1,13 @@
|
||||||
|
2010-10-15 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||||
|
|
||||||
|
* objc-private/runtime.h (__objc_update_classes_with_methods): New.
|
||||||
|
* class.c (__objc_update_classes_with_methods): New.
|
||||||
|
(objc_getClassList): Do not lock the class lock.
|
||||||
|
* methods.c (method_exchangeImplementations): New.
|
||||||
|
(method_setImplementation): New.
|
||||||
|
* objc/runtime.h (method_setImplementation): New.
|
||||||
|
(method_exchangeImplementations): New.
|
||||||
|
|
||||||
2010-10-15 Nicola Pero <nicola.pero@meta-innovation.com>
|
2010-10-15 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||||
|
|
||||||
* Protocol.m: Include objc/runtime.h and
|
* Protocol.m: Include objc/runtime.h and
|
||||||
|
|
|
@ -93,6 +93,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||||
#include "objc/thr.h"
|
#include "objc/thr.h"
|
||||||
#include "objc-private/module-abi-8.h" /* For CLS_ISCLASS and similar. */
|
#include "objc-private/module-abi-8.h" /* For CLS_ISCLASS and similar. */
|
||||||
#include "objc-private/runtime.h" /* the kitchen sink */
|
#include "objc-private/runtime.h" /* the kitchen sink */
|
||||||
|
#include "objc-private/sarray.h" /* For sarray_put_at_safe. */
|
||||||
#include <string.h> /* For memset */
|
#include <string.h> /* For memset */
|
||||||
|
|
||||||
/* We use a table which maps a class name to the corresponding class
|
/* We use a table which maps a class name to the corresponding class
|
||||||
|
@ -546,8 +547,6 @@ objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn)
|
||||||
/* Iterate over all entries in the table. */
|
/* Iterate over all entries in the table. */
|
||||||
int hash, count = 0;
|
int hash, count = 0;
|
||||||
|
|
||||||
objc_mutex_lock (__class_table_lock);
|
|
||||||
|
|
||||||
for (hash = 0; hash < CLASS_TABLE_SIZE; hash++)
|
for (hash = 0; hash < CLASS_TABLE_SIZE; hash++)
|
||||||
{
|
{
|
||||||
class_node_ptr node = class_table_array[hash];
|
class_node_ptr node = class_table_array[hash];
|
||||||
|
@ -560,7 +559,6 @@ objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn)
|
||||||
returnValue[count] = node->pointer;
|
returnValue[count] = node->pointer;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
objc_mutex_unlock (__class_table_lock);
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -569,7 +567,6 @@ objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
objc_mutex_unlock (__class_table_lock);
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,6 +644,62 @@ objc_next_class (void **enum_state)
|
||||||
return class;
|
return class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is used when the implementation of a method changes. It goes
|
||||||
|
through all classes, looking for the ones that have these methods
|
||||||
|
(either method_a or method_b; method_b can be NULL), and reloads
|
||||||
|
the implementation for these. You should call this with the
|
||||||
|
runtime mutex already locked. */
|
||||||
|
void
|
||||||
|
__objc_update_classes_with_methods (struct objc_method *method_a, struct objc_method *method_b)
|
||||||
|
{
|
||||||
|
int hash;
|
||||||
|
|
||||||
|
/* Iterate over all classes. */
|
||||||
|
for (hash = 0; hash < CLASS_TABLE_SIZE; hash++)
|
||||||
|
{
|
||||||
|
class_node_ptr node = class_table_array[hash];
|
||||||
|
|
||||||
|
while (node != NULL)
|
||||||
|
{
|
||||||
|
/* Iterate over all methods in the class. */
|
||||||
|
Class class = node->pointer;
|
||||||
|
struct objc_method_list * method_list = class->methods;
|
||||||
|
|
||||||
|
while (method_list)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < method_list->method_count; ++i)
|
||||||
|
{
|
||||||
|
struct objc_method *method = &method_list->method_list[i];
|
||||||
|
|
||||||
|
/* If the method is one of the ones we are looking
|
||||||
|
for, update the implementation. */
|
||||||
|
if (method == method_a)
|
||||||
|
{
|
||||||
|
sarray_at_put_safe (class->dtable,
|
||||||
|
(sidx) method_a->method_name->sel_id,
|
||||||
|
method_a->method_imp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method == method_b)
|
||||||
|
{
|
||||||
|
if (method_b != NULL)
|
||||||
|
{
|
||||||
|
sarray_at_put_safe (class->dtable,
|
||||||
|
(sidx) method_b->method_name->sel_id,
|
||||||
|
method_b->method_imp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
method_list = method_list->method_next;
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Resolve super/subclass links for all classes. The only thing we
|
/* Resolve super/subclass links for all classes. The only thing we
|
||||||
can be sure of is that the class_pointer for class objects point to
|
can be sure of is that the class_pointer for class objects point to
|
||||||
the right meta class objects. */
|
the right meta class objects. */
|
||||||
|
|
|
@ -124,3 +124,54 @@ class_copyMethodList (Class class_, unsigned int *numberOfReturnedMethods)
|
||||||
|
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IMP
|
||||||
|
method_setImplementation (struct objc_method * method, IMP implementation)
|
||||||
|
{
|
||||||
|
IMP old_implementation;
|
||||||
|
|
||||||
|
if (method == NULL || implementation == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* We lock the runtime mutex so that concurrent calls to change the
|
||||||
|
same method won't conflict with each other. */
|
||||||
|
objc_mutex_lock (__objc_runtime_mutex);
|
||||||
|
|
||||||
|
old_implementation = method->method_imp;
|
||||||
|
method->method_imp = implementation;
|
||||||
|
|
||||||
|
/* That was easy :-). But now we need to find all classes that use
|
||||||
|
this method, and update the IMP in the dispatch tables. */
|
||||||
|
__objc_update_classes_with_methods (method, NULL);
|
||||||
|
|
||||||
|
objc_mutex_unlock (__objc_runtime_mutex);
|
||||||
|
|
||||||
|
return old_implementation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
method_exchangeImplementations (struct objc_method * method_a, struct objc_method * method_b)
|
||||||
|
{
|
||||||
|
IMP old_implementation_a;
|
||||||
|
IMP old_implementation_b;
|
||||||
|
|
||||||
|
if (method_a == NULL || method_b == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* We lock the runtime mutex so that concurrent calls to exchange
|
||||||
|
similar methods won't conflict with each other. Each of them
|
||||||
|
should be atomic. */
|
||||||
|
objc_mutex_lock (__objc_runtime_mutex);
|
||||||
|
|
||||||
|
old_implementation_a = method_a->method_imp;
|
||||||
|
old_implementation_b = method_b->method_imp;
|
||||||
|
|
||||||
|
method_a->method_imp = old_implementation_b;
|
||||||
|
method_b->method_imp = old_implementation_a;
|
||||||
|
|
||||||
|
/* That was easy :-). But now we need to find all classes that use
|
||||||
|
these methods, and update the IMP in the dispatch tables. */
|
||||||
|
__objc_update_classes_with_methods (method_a, method_b);
|
||||||
|
|
||||||
|
objc_mutex_unlock (__objc_runtime_mutex);
|
||||||
|
}
|
||||||
|
|
|
@ -74,6 +74,9 @@ extern void class_add_method_list(Class, struct objc_method_list *);
|
||||||
extern void __objc_register_instance_methods_to_class(Class);
|
extern void __objc_register_instance_methods_to_class(Class);
|
||||||
extern struct objc_method * search_for_method_in_list(struct objc_method_list * list, SEL op);
|
extern struct objc_method * search_for_method_in_list(struct objc_method_list * list, SEL op);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
__objc_update_classes_with_methods (struct objc_method *method_a, struct objc_method *method_b); /* class.c */
|
||||||
|
|
||||||
/* True when class links has been resolved */
|
/* True when class links has been resolved */
|
||||||
extern BOOL __objc_class_links_resolved;
|
extern BOOL __objc_class_links_resolved;
|
||||||
|
|
||||||
|
|
|
@ -545,7 +545,26 @@ objc_EXPORT void method_getReturnType (Method method, char *returnValue,
|
||||||
objc_EXPORT void method_getArgumentType (Method method, unsigned int argumentNumber,
|
objc_EXPORT void method_getArgumentType (Method method, unsigned int argumentNumber,
|
||||||
char *returnValue, size_t returnValueSize);
|
char *returnValue, size_t returnValueSize);
|
||||||
|
|
||||||
|
/* Change the implementation of the method. It also searches all
|
||||||
|
classes for any class implementing the method, and replaces the
|
||||||
|
existing implementation with the new one. For that to work,
|
||||||
|
'method' must be a method returned by class_getInstanceMethod() or
|
||||||
|
class_getClassMethod() as the matching is done by comparing the
|
||||||
|
pointers; in that case, only the implementation in the class is
|
||||||
|
modified. Return the previous implementation that has been
|
||||||
|
replaced. If method or implementation is NULL, do nothing and
|
||||||
|
return NULL. */
|
||||||
|
objc_EXPORT IMP
|
||||||
|
method_setImplementation (Method method, IMP implementation);
|
||||||
|
|
||||||
|
/* Swap the implementation of two methods in a single, atomic
|
||||||
|
operation. This is equivalent to getting the implementation of
|
||||||
|
each method and then calling method_setImplementation() on the
|
||||||
|
other one. For this to work, the two methods must have been
|
||||||
|
returned by class_getInstanceMethod() or class_getClassMethod().
|
||||||
|
If 'method_a' or 'method_b' is NULL, do nothing. */
|
||||||
|
objc_EXPORT void
|
||||||
|
method_exchangeImplementations (Method method_a, Method method_b);
|
||||||
|
|
||||||
/** Implementation: the following functions are in protocols.c. */
|
/** Implementation: the following functions are in protocols.c. */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue