Commit e97cfd97 by Nicola Pero Committed by Nicola Pero

In libobjc/: 2010-12-11 Nicola Pero <nicola.pero@meta-innovation.com>

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.

From-SVN: r167712
parent 375d1239
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.
2010-12-10 Ahmad Sharif <asharif@google.com>
* gcc.target/i386/max-stack-align.c: New testcase.
......
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.
2010-12-11 Nicola Pero <nicola.pero@meta-innovation.com>
* objc-private/module-abi-8.h (struct objc_symtab): Updated
description of sel_ref_cnt and refs.
* objc/deprecated/struct_objc_symtab.h (objc_symtab): Same change.
......
......@@ -590,13 +590,17 @@ objc_disposeClassPair (Class class_);
/* Return the instance method with selector 'selector' of class
'class_', or NULL if the class (or one of its superclasses) does
not implement the method. Return NULL if class_ is Nil or selector
is NULL. */
is NULL. Calling this function may trigger a call to
+resolveInstanceMethod:, but does not return a forwarding
function. */
objc_EXPORT Method class_getInstanceMethod (Class class_, SEL selector);
/* Return the class method with selector 'selector' of class 'class_',
or NULL if the class (or one of its superclasses) does not
implement the method. Return NULL if class_ is Nil or selector is
NULL. */
NULL. Calling this function may trigger a call to
+resolveClassMethod:, but does not return a forwarding
function. */
objc_EXPORT Method class_getClassMethod (Class class_, SEL selector);
/* Return the IMP (pointer to the function implementing a method) for
......@@ -607,7 +611,15 @@ objc_EXPORT Method class_getClassMethod (Class class_, SEL selector);
arguments and return type before calling it. To get a class
method, you can pass the meta-class as the class_ argument (ie, use
class_getMethodImplementation (object_getClass (class_),
selector)). Return NULL if class_ is Nil or selector is NULL. */
selector)). Return NULL if class_ is Nil or selector is NULL.
This function first looks for an existing method; if it is not
found, it calls +resolveClassMethod: or +resolveInstanceMethod:
(depending on whether a class or instance method is being looked
up) if it is implemented. If the method returns YES, then it tries
the look up again (the assumption being that +resolveClassMethod:
or resolveInstanceMethod: will add the method using
class_addMethod()). If it is still not found, it returns a
forwarding function. */
objc_EXPORT IMP class_getMethodImplementation (Class class_, SEL selector);
/* Compatibility Note: the Apple/NeXT runtime has the function
......
......@@ -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
......
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