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