Redundant bridge methods in nested classes
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Fri Jul 31 10:18:52 UTC 2015
On 31/07/15 00:55, Liam Miller-Cushon wrote:
> Interesting, thanks Maurizio.
>
> On Wed, Jul 29, 2015 at 4:31 PM, Maurizio Cimadamore
> <maurizio.cimadamore at oracle.com
> <mailto:maurizio.cimadamore at oracle.com>> wrote:
>
> the biggest problem of the current code is that the bridge
> analysis depends on the members that were physically present on
> the superclasses; meaning that your analysis is chronically
> dependent on compilation order issues.
>
>
> As long as the hierarchy is well formed, is it possible to enforce
> that superclasses and interfaces (possibly including enclosing
> classes) are always translated before the current class? I suppose
> there are some cycles that would be tricky to get right: `class C<T
> extends C.N> { static class N extends C {} }`. If that was possible,
> though, the implementation could assert that classes are never
> translated recursively, and catch issues like the one I noticed.
There are many kinds of dependencies - the one in your example involves
tvar bounds, and I believe these are harmless when it comes to bridging;
the bridge generation process depends on the members of
superclasses/superinterfaces, not on the members of their parameter
bounds. That said, I believe it's hard to linearize a hierarchy; in your
original example we have that ('->' means 'should be translated after'):
A -> I
A.Nested -> B
B -> I
B.Nested -> A
If you treat this as a graph, and you do a topological sort of the
nodes, you end up with the following possible translation order:
I, B, A.Nested, A, B.Nested
As you noticed, this order doesn't sit well with a tree visitor, as
there's no way i.e. to visit B without also doing B.Nested - which will
mess up the order completely (as is the case now). What this means is
that TransTypes should probably NOT translate class recursively. I think
that such an approach would have more chances to succeed than the
existing one.
>
> In JDK 8 we had a similar issue when we implemented the logic for
> generating the set of bridges required by a lambda/method
> reference; as I was very aware of the compilation order issues, we
> designed an algorithm that was capable of 'simulating' the bridge
> presence in a given class, simply by looking at overriding
> properties between methods. This solution is, I believe, far
> superior, and should be preferred to the current approach which,
> in fact, adds a lot of convolutedness to the entire compiler
> pipeline, as it forces superclasses to be translated before
> subclasses (hint hint - what about superinterfaces???).
>
>
> That does sound way nicer. Did you consider switching the regular
> bridge implementation over to use the new algorithm?
It's on our radar - but it's also a very very risky change, as you can
appreciate. Realistically, we've been generating code this way for so
long, that I wouldn't be surprised if there were clients out there
relying on current bridge generation bugs - which makes everything a lot
harder (reflection depends on that too - as some bridges are generated
just for that use case :-( ). It's a big knot.
>
> I'm trying to grok functionalInterfaceBridges. Is the presence of
> bridges only simulated for classes that will be translated in the
> current compilation? The implementation appears to deal with classes
> completed from class files that are missing bridges (maybe because
> they were compiled by another compiler, or javac <= 7?).
The idea behind this logic is to compute the set of bridges associated
with a given functional type A. As a functional interface might depend
on superinterfaces that could be coming from both sourcefile and
classfile, the logic must be able to compute the union of the bridges
available in such dependecies; for classfiles we can expect bridges to
be already there (the check is done with binaryImplementation [*]) - for
sourcefile we just can't rely on membership (because of the problem you
mentioned), so we simulate bridge presence by exploiting overriding
properties.
[*] - for this very reason, bridge methods are among the (very) few
synthetic symbols that are preserved at class reading time.
>
> Liam
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20150731/3f77f8e0/attachment.html>
More information about the compiler-dev
mailing list