Invoking a method from an indirect superclass via Enclosing.super.method (JDK-8027789)

Alex Buckley alex.buckley at oracle.com
Thu Nov 7 16:25:59 PST 2013


Hi Jan,

Your understanding of JLS 13.1 is correct: the expression C.super.m() 
has a qualifying type of p1.B, so that's what goes in the symbolic 
reference for invokespecial.

We have to fix the emission of p1.A in the access method because it's 
causing a run time failure of a legal source program. In a consistently 
compiled program, starting to resolve m() in p1.B never gives a worse 
result than starting to resolve m() in p1.A, because the direct 
superclass of the lexically enclosing class is necessarily accessible. 
So when the programs you saw "in the wild" with a bad invokespecial are 
recompiled, they will see no behavioral difference assuming they ran in 
the first place.

I recommend fixing this in JDK8 and having it take effect for all 
targets, not just 8.

Alex

On 11/7/2013 3:28 PM, Jan Lahoda wrote:
> Hello,
>
> Dan found out that in cases like this (JDK-8027789):
> ---
> package p1;
> /* package-access */ class A {
>     protected void m() {}
> }
> ---
> package p1;
> public class B extends A {}
> ---
> package p2;
> public class C extends p1.B {
>     { new Object() { { C.super.m(); } }; }
>     public static void main(String... args) { new C(); }
> }
> ---
>
> javac will generate an access method into the class p2.C like this:
> ---
>     static void access$001(p2.C);
>       flags: ACC_STATIC, ACC_SYNTHETIC
>       Code:
>         stack=1, locals=1, args_size=1
>            0: aload_0
>            1: invokespecial #1                  // Method p1/A.m:()V
>            4: return
>         LineNumberTable:
>           line 2: 0
> ---
>
> Which, as I understood, is wrong: the invokespecial should refer to p1.B
> (p1/B.m:()V), which is the direct superclass of the given class, not to
> the indirect superclass p1.A. An exception are references to methods
> from j.l.Object, where the reference should refer to j.l.Object. (This
> is per JLS 13.1 - is my understanding correct?)
>
> Based on my recent experiments, this problem only occurs when the access
> method is generated, javac generates the correct reference in cases
> where the access method is not required/generated (for target 1.2+).
>
> The question is whether we (I) should attempt to fix this for JDK8. As
> this is a change in the output binary form, this may pose some
> compatibility risk, although I don't know a particular case where this
> could actually introduce problems (but the fix for this would allow some
> programs to run which do not run now, as e.g. in the above example).
>
> I tried to estimate the impact of this, using my (somewhat old) copy of
> the qualitas corpus. Out of 54 usable systems, only about 7 contain at
> least one invokespecial instruction that would be changed, and there are
> about 103 total invokespecial instructions that would be changed.
>
> I also tried to analyze a fragment of the maven repo (about 34GB of
> artifacts, a copy of Mandy's repo), and there were about 530 instances
> of invokespecial instructions inside access methods (presumably
> generated by javac), that might be affected by the fix. (For the record,
> there are many more suspicious invokespecials, with somewhat unclear
> origins - possibly other compilers?)
>
> Would you suggest to try to fix this for JDK8? And if so, should the
> new/correct code be generated only for target 8+, keeping the original
> behavior for older targets?
>
> I am attaching my current fix for this for reference.
>
> Thanks,
>       Jan
>


More information about the compiler-dev mailing list