discuss-gnustep
[Top][All Lists]
Advanced

[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.]





reply via email to

[Prev in Thread] Current Thread [Next in Thread]