summaryrefslogtreecommitdiffstats
path: root/libobjc/sendmsg.c
diff options
context:
space:
mode:
authornicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>2010-12-11 19:43:21 +0000
committernicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>2010-12-11 19:43:21 +0000
commit101978acaa779540c14c366687226ade41c471f7 (patch)
treec50ecdee614fbdc518483d8012362f18adfbe922 /libobjc/sendmsg.c
parent609b9937816df81c4bf275b5d470fa1bc7fb75e5 (diff)
downloadppe42-gcc-101978acaa779540c14c366687226ade41c471f7.tar.gz
ppe42-gcc-101978acaa779540c14c366687226ade41c471f7.zip
In libobjc/:
2010-12-11 Nicola Pero <nicola.pero@meta-innovation.com> * sendmsg.c (selector_resolveClassMethod): New. (selector_resolveInstanceMethod): New. (__objc_resolve_class_method): New. (__objc_resolve_instance_method): New. (get_imp): Call __objc_resolve_class_method or __objc_resolve_instance_method at the appropriate time. (objc_msg_lookup): Same. (class_getClassMethod): Same. (class_getInstanceMethod): Same. (__objc_init_dispatch_tables): Initialize selector_resolveClassMethod and selector_resolveInstanceMethod. * objc/runtime.h: Updated documentation of class_getClassMethod, class_getInstanceMethod and class_getMethodImplementation. In gcc/testsuite/: 2010-12-11 Nicola Pero <nicola.pero@meta-innovation.com> * objc.dg/gnu-api-2-resolve-method.m: New. * obj-c++.dg/gnu-api-2-resolve-method.mm: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@167712 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libobjc/sendmsg.c')
-rw-r--r--libobjc/sendmsg.c183
1 files changed, 169 insertions, 14 deletions
diff --git a/libobjc/sendmsg.c b/libobjc/sendmsg.c
index 7f7024c275a..4748695938d 100644
--- a/libobjc/sendmsg.c
+++ b/libobjc/sendmsg.c
@@ -138,6 +138,102 @@ __objc_get_forward_imp (id rcv, SEL sel)
}
}
+/* Selectors for +resolveClassMethod: and +resolveInstanceMethod:.
+ These are set up at startup. */
+static SEL selector_resolveClassMethod = NULL;
+static SEL selector_resolveInstanceMethod = NULL;
+
+/* Internal routines use to resolve a class method using
+ +resolveClassMethod:. 'class' is always a non-Nil class (*not* a
+ meta-class), and 'sel' is the selector that we are trying to
+ resolve. This must be called when class is not Nil, and the
+ dispatch table for class methods has already been installed.
+
+ This routine tries to call +resolveClassMethod: to give an
+ opportunity to resolve the method. If +resolveClassMethod: returns
+ YES, it tries looking up the method again, and if found, it returns
+ it. Else, it returns NULL. */
+static inline
+IMP
+__objc_resolve_class_method (Class class, SEL sel)
+{
+ /* We need to lookup +resolveClassMethod:. */
+ BOOL (*resolveMethodIMP) (id, SEL, SEL);
+
+ /* The dispatch table for class methods is already installed and we
+ don't want any forwarding to happen when looking up this method,
+ so we just look it up directly. Note that if 'sel' is precisely
+ +resolveClassMethod:, this would look it up yet again and find
+ nothing. That's no problem and there's no recursion. */
+ resolveMethodIMP = (BOOL (*) (id, SEL, SEL))sarray_get_safe
+ (class->class_pointer->dtable, (size_t) selector_resolveClassMethod->sel_id);
+
+ if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveClassMethod, sel))
+ {
+ /* +resolveClassMethod: returned YES. Look the method up again.
+ We already know the dtable is installed. */
+
+ /* TODO: There is the case where +resolveClassMethod: is buggy
+ and returned YES without actually adding the method. We
+ could maybe print an error message. */
+ return sarray_get_safe (class->class_pointer->dtable, (size_t) sel->sel_id);
+ }
+
+ return NULL;
+}
+
+/* Internal routines use to resolve a instance method using
+ +resolveInstanceMethod:. 'class' is always a non-Nil class, and
+ 'sel' is the selector that we are trying to resolve. This must be
+ called when class is not Nil, and the dispatch table for instance
+ methods has already been installed.
+
+ This routine tries to call +resolveInstanceMethod: to give an
+ opportunity to resolve the method. If +resolveInstanceMethod:
+ returns YES, it tries looking up the method again, and if found, it
+ returns it. Else, it returns NULL. */
+static inline
+IMP
+__objc_resolve_instance_method (Class class, SEL sel)
+{
+ /* We need to lookup +resolveInstanceMethod:. */
+ BOOL (*resolveMethodIMP) (id, SEL, SEL);
+
+ /* The dispatch table for class methods may not be already installed
+ so we have to install it if needed. */
+ resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
+ (size_t) selector_resolveInstanceMethod->sel_id);
+ if (resolveMethodIMP == 0)
+ {
+ /* Try again after installing the dtable. */
+ if (class->class_pointer->dtable == __objc_uninstalled_dtable)
+ {
+ objc_mutex_lock (__objc_runtime_mutex);
+ if (class->class_pointer->dtable == __objc_uninstalled_dtable)
+ __objc_install_dispatch_table_for_class (class->class_pointer);
+ objc_mutex_unlock (__objc_runtime_mutex);
+ }
+ resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
+ (size_t) selector_resolveInstanceMethod->sel_id);
+ }
+
+ if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveInstanceMethod, sel))
+ {
+ /* +resolveInstanceMethod: returned YES. Look the method up
+ again. We already know the dtable is installed. */
+
+ /* TODO: There is the case where +resolveInstanceMethod: is
+ buggy and returned YES without actually adding the method.
+ We could maybe print an error message. */
+ return sarray_get_safe (class->dtable, (size_t) sel->sel_id);
+ }
+
+ return NULL;
+}
+
+/* Temporary definition until we include objc/runtime.h. */
+objc_EXPORT Class objc_lookupClass (const char *name);
+
/* Given a class and selector, return the selector's implementation. */
inline
IMP
@@ -188,14 +284,35 @@ get_imp (Class class, SEL sel)
{
/* The dispatch table has been installed, and the method
is not in the dispatch table. So the method just
- doesn't exist for the class. Return the forwarding
- implementation. We don't know the receiver (only its
- class), so we have to pass 'nil' as the first
- argument. Passing the class as first argument is
- wrong because the class is not the receiver; it can
- result in us calling a class method when we want an
- instance method of the same name. */
- res = __objc_get_forward_imp (nil, sel);
+ doesn't exist for the class. */
+
+ /* Try going through the +resolveClassMethod: or
+ +resolveInstanceMethod: process. */
+ if (CLS_ISMETA (class))
+ {
+ /* We have the meta class, but we need to invoke the
+ +resolveClassMethod: method on the class. So, we
+ need to obtain the class from the meta class,
+ which we do using the fact that both the class
+ and the meta-class have the same name. */
+ Class realClass = objc_lookupClass (class->name);
+ if (realClass)
+ res = __objc_resolve_class_method (realClass, sel);
+ }
+ else
+ res = __objc_resolve_instance_method (class, sel);
+
+ if (res == 0)
+ {
+ /* If that fails, then return the forwarding
+ implementation. We don't know the receiver (only its
+ class), so we have to pass 'nil' as the first
+ argument. Passing the class as first argument is
+ wrong because the class is not the receiver; it can
+ result in us calling a class method when we want an
+ instance method of the same name. */
+ res = __objc_get_forward_imp (nil, sel);
+ }
}
}
}
@@ -304,9 +421,20 @@ objc_msg_lookup (id receiver, SEL op)
(sidx)op->sel_id);
if (result == 0)
{
- /* If the method still just doesn't exist for the
- class, attempt to forward the method. */
- result = __objc_get_forward_imp (receiver, op);
+ /* Try going through the +resolveClassMethod: or
+ +resolveInstanceMethod: process. */
+ if (CLS_ISMETA (receiver->class_pointer))
+ result = __objc_resolve_class_method ((Class)receiver, op);
+ else
+ result = __objc_resolve_instance_method (receiver->class_pointer,
+ op);
+
+ if (result == 0)
+ {
+ /* If the method still just doesn't exist for
+ the class, attempt to forward the method. */
+ result = __objc_get_forward_imp (receiver, op);
+ }
}
}
}
@@ -343,6 +471,10 @@ void
__objc_init_dispatch_tables ()
{
__objc_uninstalled_dtable = sarray_new (200, 0);
+
+ /* TODO: It would be cool to register typed selectors here. */
+ selector_resolveClassMethod = sel_register_name ("resolveClassMethod:");
+ selector_resolveInstanceMethod =sel_register_name ("resolveInstanceMethod:");
}
/* This function is called by objc_msg_lookup when the
@@ -566,20 +698,43 @@ class_get_class_method (MetaClass class, SEL op)
struct objc_method *
class_getInstanceMethod (Class class_, SEL selector)
{
+ struct objc_method *m;
+
if (class_ == Nil || selector == NULL)
return NULL;
- return search_for_method_in_hierarchy (class_, selector);
+ m = search_for_method_in_hierarchy (class_, selector);
+ if (m)
+ return m;
+
+ /* Try going through +resolveInstanceMethod:, and do
+ the search again if successful. */
+ if (__objc_resolve_instance_method (class_, selector))
+ return search_for_method_in_hierarchy (class_, selector);
+
+ return NULL;
}
struct objc_method *
class_getClassMethod (Class class_, SEL selector)
{
+ struct objc_method *m;
+
if (class_ == Nil || selector == NULL)
return NULL;
- return search_for_method_in_hierarchy (class_->class_pointer,
- selector);
+ m = search_for_method_in_hierarchy (class_->class_pointer,
+ selector);
+ if (m)
+ return m;
+
+ /* Try going through +resolveClassMethod:, and do the search again
+ if successful. */
+ if (__objc_resolve_class_method (class_, selector))
+ return search_for_method_in_hierarchy (class_->class_pointer,
+ selector);
+
+ return NULL;
}
BOOL
OpenPOWER on IntegriCloud