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:
Nicola Pero 2010-10-15 22:27:39 +00:00 committed by Nicola Pero
parent ef7659966d
commit 51194e8eb5
5 changed files with 140 additions and 4 deletions

View File

@ -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>
* Protocol.m: Include objc/runtime.h and

View File

@ -93,6 +93,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include "objc/thr.h"
#include "objc-private/module-abi-8.h" /* For CLS_ISCLASS and similar. */
#include "objc-private/runtime.h" /* the kitchen sink */
#include "objc-private/sarray.h" /* For sarray_put_at_safe. */
#include <string.h> /* For memset */
/* 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. */
int hash, count = 0;
objc_mutex_lock (__class_table_lock);
for (hash = 0; hash < CLASS_TABLE_SIZE; hash++)
{
class_node_ptr node = class_table_array[hash];
@ -560,7 +559,6 @@ objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn)
returnValue[count] = node->pointer;
else
{
objc_mutex_unlock (__class_table_lock);
return count;
}
}
@ -569,7 +567,6 @@ objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn)
}
}
objc_mutex_unlock (__class_table_lock);
return count;
}
@ -647,6 +644,62 @@ objc_next_class (void **enum_state)
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
can be sure of is that the class_pointer for class objects point to
the right meta class objects. */

View File

@ -124,3 +124,54 @@ class_copyMethodList (Class class_, unsigned int *numberOfReturnedMethods)
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);
}

View File

@ -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 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 */
extern BOOL __objc_class_links_resolved;

View File

@ -545,7 +545,26 @@ objc_EXPORT void method_getReturnType (Method method, char *returnValue,
objc_EXPORT void method_getArgumentType (Method method, unsigned int argumentNumber,
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. */