aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>2010-10-15 22:27:39 +0000
committernicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>2010-10-15 22:27:39 +0000
commitcd9fd8f49ed8d1933887d048b692de11a2247e88 (patch)
tree4a6954b1f7b91675bedaa8e8b7d3351ee0f9d7d7
parent4730466b5737baca4efd606025cb52b019fd6613 (diff)
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@165525 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--libobjc/ChangeLog10
-rw-r--r--libobjc/class.c61
-rw-r--r--libobjc/methods.c51
-rw-r--r--libobjc/objc-private/runtime.h3
-rw-r--r--libobjc/objc/runtime.h21
5 files changed, 141 insertions, 5 deletions
diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog
index 9ae38383ffe..0561f88d15e 100644
--- a/libobjc/ChangeLog
+++ b/libobjc/ChangeLog
@@ -1,5 +1,15 @@
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
objc-private/module-abi-8.h instead of objc/objc-api.h. Do not
repeat Protocol's instance variables.
diff --git a/libobjc/class.c b/libobjc/class.c
index 4eb86761ee8..8c6f989a8e9 100644
--- a/libobjc/class.c
+++ b/libobjc/class.c
@@ -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. */
diff --git a/libobjc/methods.c b/libobjc/methods.c
index 65939a6d5cd..b4faee533c2 100644
--- a/libobjc/methods.c
+++ b/libobjc/methods.c
@@ -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);
+}
diff --git a/libobjc/objc-private/runtime.h b/libobjc/objc-private/runtime.h
index 6794d181513..ff924becd93 100644
--- a/libobjc/objc-private/runtime.h
+++ b/libobjc/objc-private/runtime.h
@@ -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;
diff --git a/libobjc/objc/runtime.h b/libobjc/objc/runtime.h
index 938033148ae..bb241acd5b3 100644
--- a/libobjc/objc/runtime.h
+++ b/libobjc/objc/runtime.h
@@ -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. */