Class verifier issues with unboxing method handles
Mark Derricutt
mark at talios.com
Tue May 28 18:04:59 PDT 2013
Hi all,
Mark Reinhold suggested I posted this question/bug report to hotspot-dev
rather than jdk8-dev so here goes.
I have a fairly simple test case using the new streams API:
public static void main(String[] args) {
List<String> strings = Arrays.asList("1", "2", "3", "4", "5");
strings.stream()
.mapToInt(s -> new Integer(s))
.forEach(i -> System.out.println(String.format("int %d", i)));
}
which compiles, runs, and prints out what I expect:
int 1
int 2
int 3
int 4
int 5
Given that mapToInt() is returning an IntegerStream wrapping primitive
ints, the result of my closure is successfully autoboxed down to an int
and all is happy with the world.
If I change this code to be:
strings.stream()
.mapToInt(Integer::parseInt)
.forEach(i -> System.out.println(String.format("int %d", i)));
Again, everything works as expected as Integer::parseInt returns an int,
so there's no boxing.
Changing this once again to:
strings.stream()
.mapToInt(Integer::valueOf)
.forEach(i -> System.out.println(String.format("int %d", i)));
I also see the expected result, Integer::valueOf returns an Integer
which is then being boxed down to an int.
However, if I change the code to:
strings.stream()
.mapToInt(Integer::new)
.forEach(i -> System.out.println(String.format("int %d", i)));
which, if I understand correctly - Integer::new should be returning a
method handle to the constructor. IntelliJ IDEA 13 autocompletes this
for me, and hyperlinks to the Integer(String s) constructor, javac
successfully compiles the code so my -assumption- is that the
constructor would be called, returning an Integer which is then boxed
down to an int, however, this is what I get:
Exception in thread "main" java.lang.BootstrapMethodError: call site
initialization exception
at java.lang.invoke.CallSite.makeSite(CallSite.java:298)
at
java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:294)
at com.talios.test.TestJdk.main(TestJdk.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.VerifyError: Bad type on operand stack
Exception Details:
Location:
com/talios/test/TestJdk$$Lambda$1.applyAsInt(Ljava/lang/Object;)I
@11: ireturn
Reason:
Type 'java/lang/Integer' (current frame, stack[0]) is not
assignable to integer
Current Frame:
bci: @11
flags: { }
locals: { 'com/talios/test/TestJdk$$Lambda$1', 'java/lang/Object' }
stack: { 'java/lang/Integer' }
Bytecode:
0000000: bb00 0e59 2bc0 0010 b700 13ac
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2536)
at java.lang.Class.getDeclaredConstructors(Class.java:1928)
at
java.lang.invoke.InnerClassLambdaMetafactory$1.run(InnerClassLambdaMetafactory.java:147)
at
java.lang.invoke.InnerClassLambdaMetafactory$1.run(InnerClassLambdaMetafactory.java:144)
at java.security.AccessController.doPrivileged(Native Method)
at
java.lang.invoke.InnerClassLambdaMetafactory.buildCallSite(InnerClassLambdaMetafactory.java:143)
at
java.lang.invoke.LambdaMetafactory.metaFactory(LambdaMetafactory.java:191)
at java.lang.invoke.CallSite.makeSite(CallSite.java:283)
... 7 more
This is on OSX Mountain Lion, with JDK 8 Build 91.
Have I walked in an obscure corner case of method handle breakage and
found something new, or is this a new problem?
Cheers,
Mark
More information about the hotspot-dev
mailing list