This is the mail archive of the java@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Bug 9861 and Java 5 Generics


>>>>> "Per" == Per Bothner <per@bothner.com> writes:

Per> If it is for co-variant return types, then C++ supports those, so
Per> why can't we use the ABI it uses?

Short answer: I think we can do this in some cases, but not all cases.
For the BC ABI it will require an extra type assertion to be emitted,
and for the interpreter it will require a link-time type check.

First a long digression into some examples.  Hopefully this will make
it easier for people to check my reasoning and see if I've made a
mistake.


For bridge methods introduced for generics, I think we still need the
bridge methods for runtime type safety.  Here is an example:

    class Container<T>
    {
       T val;
       T getAndSet(T v) { T ret = val; val = v; return ret; }
    }

    class Derived extends Container<String>
    {
       String getAndSet(String v) { return super.getAndSet(v); }
    }

In this case the compiler has to insert a bridge method into Derived
which looks like;

    /* bridge */ Object getAndSet(Object v) {
       return getAndSet((String) v);
    }

Here's the attempt to circumvent type safety:

   Derived d = new Derived();
   Container c = d;
   c.getAndSet(new Object());
   String whoops = d.getAndSet(null);

If we omit the bridge method, this will not cause any errors (which is
bad).

So, I think when we have a bridge method whose argument types differ
from the method to which it delegates, we must keep the bridge around.
And, I think we have to do this regardless of the ABI.


Now consider this case:

    class Base {}
    class Derived extends Base {}

    class b {
      Base m() { return null; }
    }

    class c extends b {
       Derived m() { return null; }
    }

In this case eclipse generates an interesting bridge method:

    c.m ()Base:
    aload_0
    invokevirtual c.m ()Derived
    checkcast Base
    areturn

Here the checkcast is to ensure that the c.m really does override
b.m.

Suppose this checkcast were not generated, and suppose furthermore
that we still ignored the bridge and let c.m override b.m.  An
attacker could then redefine Derived and an unsafe cast would result.

I think this situation could be handled with type assertions.  We
could just assert 'Derived extends Base' when (runtime) linking.  For
the C++ ABI case, I think we can simply not care, since we already
don't promise to do the right thing if the user changes the typer
hierarchy after compiling some module.


To sum up here, I think we can only do this optimization when all the
argument types of the bridge method are identical to the types of the
method to which it delegates.  I haven't thought this through but one
possibility is that we would have to scan the body of the method to
determine this.


Andrew pointed out to me on irc that we may not need to solve every
problem at once.  For instance until we have generic classes in the
core library, the need to solve the CNI problems aren't as urgent.

Also, I think for cases where the bytecode is generated by something
other than a java compiler, we don't need to worry much about CNI
header generation (or name mangling in g++).  This is sufficiently
obscure that I don't remember us ever running into it.

One final note about the symbol naming.  Couldn't we only put the
return type into the mangling in those cases where there actually is a
clash?

Tom


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]