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

Jan Lahoda jan.lahoda at oracle.com
Fri Nov 8 02:59:33 PST 2013


On 11/08/2013 01:25 AM, Alex Buckley wrote:
> 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.

Thanks.

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

Ok. In that case, I'll see if the existing code for super methods 
invocations can be reused - that would fix the problem for targets 1.2+.

Jan

>
> 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