Redundant bridge methods in nested classes

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Jul 29 23:31:46 UTC 2015


Nicely spotted - maybe in this case it's not an issue, but I'd like to 
file a bug and keep track of this, to see if there's something nastier 
that could happen as an outcome. The reality is that the bridge code is 
pretty ancient (dates back to 2001-2002) - and the spec wasn't settled 
back then; 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.

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???).

Maurizio

On 29/07/15 18:30, Liam Miller-Cushon wrote:
> I've been trying to get a better understanding of bridge methods, and 
> noticed that javac seems to emit different bridge methods depending on 
> the order of sources passed to the compilation.
>
> As far as I can tell this occurs because TransTypes.translateClass 
> calls super.visitClassDef before addBridges. The super implementation 
> of visitClassDef processes all declarations (including nested 
> classes), so nested classes get translated before their enclosing 
> classes. If a nested class extends its enclosing class, the enclosing 
> class' bridges won't have been generated, so the nested class ends up 
> with redundant bridge methods.
>
> I don't think it's a correctness issue, but I found it surprising. Do 
> you think this is worth fixing?
>
> Here's the repro:
>
> A and B are symmetric: A's nested class extends B, B's nested class 
> extends A. Depending on the order of compilation a bridge method is 
> generated in A$Nested or B$Nested, but not both.
>
> $ cat I.java
> interface I<T> {
>   void f(T t);
> }
> $ cat A.java
> class A implements I<Number> {
>   public void f(Number x) {}
>   static class Nested extends B {
>   }
> }
> $ cat B.java
> class B implements I<Number> {
>   public void f(Number x) {}
>   static class Nested extends A {
>   }
> }
>
> # pass A.java to javac first, A$Nested has a bridge method
>
> $ rm -f *.class
> $ javac I.java A.java B.java
> $ javap -private 'A$Nested'
> Compiled from "A.java"
> class A$Nested extends B {
>   A$Nested();
>   public void f(java.lang.Object);
> }
> $ javap -private 'B$Nested'
> Compiled from "B.java"
> class B$Nested extends A {
>   B$Nested();
> }
>
> # pass B.java to javac first, B$Nested has a bridge method
>
> $ rm -f *.class
> $ javac I.java B.java A.java
> $ javap -private 'A$Nested'
> Compiled from "A.java"
> class A$Nested extends B {
>   A$Nested();
> }
> $ javap -private 'B$Nested'
> Compiled from "B.java"
> class B$Nested extends A {
>   B$Nested();
>   public void f(java.lang.Object);
> }



More information about the compiler-dev mailing list