Compiler bug: Instantiating non-static inner classes using constructor references inside lambdas
Remi Forax
forax at univ-mlv.fr
Tue Nov 4 00:47:50 UTC 2014
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/1caa982c/attachment-0001.html>
More information about the compiler-dev
mailing list