[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: problems with forward invocation (gcc bug?)
From: |
Wim Oudshoorn |
Subject: |
Re: problems with forward invocation (gcc bug?) |
Date: |
Tue, 31 Jul 2001 10:12:19 +0200 |
You wrote:
> The forwarding in GNUstep does not work the way I expected.
> I expected that the line
>
> [objectinstance method: argument];
>
Problems with forwarding.
Looking somewhat deeper in the problem I encountered
with forwarding it seems there are few problems
with the GNUstep forwarding mechanism.
(A) Finding type information of the selector.
(B) Thread safety.
Besides these issues I wonder why the method
- forward::
is never called anymore? Is this done deliberatily?
If so, why does NSObject still contain the method
- forward:: (which turns it into - forwardInvocation:)?
Also I think that (A) will also creates problems with
other parts of GNUstep that rely on type information
of the selector, e.g. `methodSignatureForSelector:' etc.
Ok, now the issues I am struggling with.
(There also exists the possibility
that I screwed up the GNUstep + GCC configuration.)
A. Type info
=========================================================
The problem is best illustrated with two little programs:
--- testforward1.m ----
#include <Foundation/Foundation.h>
@implementation Test: NSObject
@end
int main (void)
{
Test* x = [Test new];
[x cString];
}
--- testforward2.m ----
#include <Foundation/Foundation.h>
@implementation Test: NSObject
@end
int main (void)
{
id x = [Test new];
[x cString];
}
------------------------
The only difference between the two programs is that
the variable `x' is typed `Test *' in the first program
and `id' in the second. If you execute these programs they
both exit with an exception:
testforward1:
Uncaught exception
NSInvalidArgumentException,
reason: Invalid selector cString (no type information)
testforward2:
Uncaught exception
NSInvalidArgumentException,
reason: Test does not recognize cString
As far as I can see testforward2 generates the correct exception.
The reason for the difference is that in the first program
gcc KNOWS that `x' is of type `Test *' and this class does
not implement `cString'.
Therefore the selector generated by the compiler has
NO type information associated with it.
In the second program the compiler does NOT KNOW to which
class `x' belongs and (probably during linking) merges
this selector with the selector of `NSString'.
For this problem there is a rather trivial fix, namely
in the function `GSInvocationCallback' refetch
the selector if it has no type information.
(the GNU objc runtime provides methods to
get a selector with type information)
[Patch available on request]
B. Thread safety
=========================================================
While debugging problem (A) I found that the basic
forwarding mechanism does the following:
objc runtime GSFFCallInvocation
<gs_objc_msg_forward>
|-------1. get forward implementation ---> |
. |
. Store selector in
. global variable.
. |
|<-----------------------------------------
|
|
| <GSInvocationCallback>
| -----2. call forward implementation ---->|
|
Retrieve selector
from the global
variable.
|
Forward the call
to -forwardInvocation
And because the selector is in the `va_list'
argument of the second call anyway it seems that we can dispose
of the global variable. But in order to retrieve the selector
from the `va_list' we need to initialize the `va_list' with
the return type of the method and to figure out the return
type we need the selector. So we have chicken and egg problem.
Note: As far as I can see the va_list only looks if the
return type is a struct or something else.
(When a struct is returned gcc adds an
extra hidden parameter at the beginning of
the argument list. The hidden parameter
is the adress of the return struct).
For this I can see basically three solutions.
Sol 1. Add lock around message forwarding in the
objc runtime.
Disadvantages:
1. changes the runtime
2. locks until the GSinvocationCallback is
finished.
Sol 2. Add lock in GSFFCallInvocation.
That is, lock in gs_objc_msg_forward and
unlock in GSInvocationCallback
Disadvantages:
1. It is very bad to assume that
code that calls gs_objc_msg_forward will
really execute the returned function.
Sol 3. Make a pool of callback wrappers of
GSInvocation callback's and let
the function gs_objc_msg_forward return the correct
version, or create one if no suitable version exist.
Disadvantages:
1. Is more complicated.
As you can probably tell, Sol 3 has my vote.
[I have not implemented this yet.]
- Re: problems with forward invocation (gcc bug?),
Wim Oudshoorn <=