Compiler bug: Instantiating non-static inner classes using constructor references inside lambdas
Vicente-Arturo Romero-Zaldivar
vicente.romero at oracle.com
Tue Nov 4 18:14:59 UTC 2014
Hi all,
I can't reproduce this error on jdk9 repo but it's still present in
8udev repo. Thanks for the report and for the small example. I will
locate the related changeset and create a backport to 8udev repo.
Vicente
On 11/03/2014 04:47 PM, Remi Forax wrote:
> Hi Victor, hi all,
> it seems that javac forget that an inner class has a hidden argument
> that should be passed at creation time :(
>
> First, in order to compile javac should rewrite foo like this,
> it's a little more complex in reality because the second lambda can be
> loaded as a real method reference
>
> public void foo() {
> Boom es = new Boom();
> go(() -> es.test(boom -> this.new Crash(boom)));
> }
>
> but the generated bytecode of foo and of the corresponding lambda
> seems very wrong,
> first the code of foo,
> public void foo();
> Code:
> 0: new #2 // class MakeVerifyError$Boom
> 3: dup
> 4: invokespecial #3 // Method
> MakeVerifyError$Boom."<init>":()V
> 7: astore_1
> 8: aload_1
> 9: invokedynamic #4, 0 // InvokeDynamic
> #0:run:(LMakeVerifyError$Boom;)Ljava/lang/Runnable;
> 14: invokestatic #5 // Method
> go:(Ljava/lang/Runnable;)V
> 17: return
>
> as you can see the problem is that the first lambda should capture 2
> arguments 'es' and 'this' but
> the code capture only 'es'. javac seems to forget that to create a
> Crash you need a MakeVerifyError
> because it's an inner class.
>
> so the code should be:
> ...
> 7: astore_1
> 8: aload_0 // load this !
> 9: aload_1
> 10: invokedynamic #4, 0 // InvokeDynamic
> #0:run:(LMakeVerifyError;LMakeVerifyError$Boom;)Ljava/lang/Runnable;
> 15: invokestatic #5 // Method
> go:(Ljava/lang/Runnable;)V
> 18: return
>
> and the code of the lambda is wrong too, instead of:
> private static void lambda$foo$0(MakeVerifyError$Boom);
> Code:
> 0: aload_0
> 1: aload_0
> 2: invokedynamic #6, 0 // InvokeDynamic
> #1:apply:(LMakeVerifyError;)Ljava/util/function/Function;
> 7: invokevirtual #7 // Method
> MakeVerifyError$Boom.test:(Ljava/util/function/Function;)V
> 10: return
>
> it should be:
> private static void
> lambda$foo$0(MakeVerifyError,MakeVerifyError$Boom);
> Code:
> 0: aload_1
> 1: aload_0
> 2: invokedynamic #6, 0 // InvokeDynamic
> #1:apply:(LMakeVerifyError;)Ljava/util/function/Function;
> 7: invokevirtual #7 // Method
> MakeVerifyError$Boom.test:(Ljava/util/function/Function;)V
> 10: return
>
> I hope this can help.
>
> cheers,
> Rémi
>
> On 11/03/2014 03:12 AM, Victor Williams Stafusa da Silva wrote:
>> Hi, I used javac 1.8.0_25 with this code:
>>
>> package com.example;
>> import java.util.function.Function;
>> public class MakeVerifyError {
>> public void foo() {
>> Boom es = new Boom();
>> go(() -> es.test(Crash::new));
>> }
>> private static void go(Runnable run) {}
>> public class Crash { public Crash(Boom e) {} }
>> public static class Boom { public void test(Function<Boom, ?>
>> ctor) {} }
>> public static void main(String[] args) {}
>> }
>>
>>
>> And this was the result:
>>
>> java.lang.VerifyError: Bad type on operand stack
>> Exception Details:
>> Location:
>> com/example/MakeVerifyError.lambda$foo$0(Lcom/example/MakeVerifyError$Boom;)V
>> @2: invokedynamic
>> Reason:
>> Type 'com/example/MakeVerifyError$Boom' (current frame,
>> stack[1]) is not assignable to 'com/example/MakeVerifyError'
>> Current Frame:
>> bci: @2
>> flags: { }
>> locals: { 'com/example/MakeVerifyError$Boom' }
>> stack: { 'com/example/MakeVerifyError$Boom',
>> 'com/example/MakeVerifyError$Boom' }
>> Bytecode:
>> 0x0000000: 2a2a ba00 0600 00b6 0007 b1
>> at java.lang.Class.getDeclaredMethods0(Native Method)
>> at java.lang.Class.privateGetDeclaredMethods(Class.java:2693)
>> at java.lang.Class.privateGetMethodRecursive(Class.java:3040)
>> at java.lang.Class.getMethod0(Class.java:3010)
>> at java.lang.Class.getMethod(Class.java:1776)
>> at
>> sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
>> at
>> sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
>> Exception in thread "main" Java Result: 1
>>
>>
>> If the 'static' modifier is added to the Crash class, it works fine.
>> If the 'test' method call is moved to outside the lambda, it works fine.
>> If the Boom object is instantiated inside the lambda, it fails to
>> load the class:
>>
>> Error: Could not find or load main class com.example.MakeVerifyError
>> Java Result: 1
>>
>>
>> So, obviously this looks like a compiler bug.
>> Do somebody already saw that before?
>>
>> Victor Williams Stafusa da Silva
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20141104/877e47ba/attachment.html>
More information about the compiler-dev
mailing list