VerifyError (original) (raw)

Remi Forax forax at univ-mlv.fr
Sat Apr 20 14:48:53 PDT 2013


On 04/20/2013 08:37 PM, Richard Warburton wrote:

Hi,

Just reporting a verify error (from b86 binary) java.lang.VerifyError: Bad type on operand stack Exception Details: Location: org/adoptajsr/java8/Java8Recommender.lambda$2(Ljava/util/List;)Ljava/util/stream/Stream; @13: invokedynamic Reason: Type 'java/util/List' (current frame, stack[2]) is not assignable to 'org/adoptajsr/java8/Java8Recommender' Current Frame: bci: @13 flags: { } locals: { 'java/util/List' } stack: { 'java/util/stream/Stream', 'java/util/stream/Stream', 'java/util/List' } Bytecode: 0000000: 2ab9 0004 0100 2ab9 0004 0100 2aba 002b 0000010: 0000 b800 2cb0 at org.adoptajsr.java8.Java8RecommenderTest.example(Java8RecommenderTest.java:18) Code is available at: https://github.com/RichardWarburton/java-8-benchmarks/blob/master/java-8-benchmarks/src/main/java/org/adoptajsr/java8/Java8Recommender.java regards, Richard Warburton http://insightfullogic.com @RichardWarburto <http://twitter.com/richardwarburto>

It's a compiler issue, in the following expression, the lambda used as parameter of flatMap is not able to create CoBuy::new correctly

// product id -> product id -> frequency purchased together Map<Integer, Map<Integer, Long>> productSimilarity = buysByUser.values() .stream() .flatMap(buys -> zip(buys.stream(), buys.stream(), CoBuy::new)) .collect(groupingBy(coBuy -> coBuy.x, groupingBy(coBuy -> coBuy.y, TreeMap::new, counting())));

so the bug is here: buys -> zip(buys.stream(), buys.stream(), CoBuy::new)

CoBuy is declared as a non static inner class (BTW, Richard, I think you forget to declare it static) so it capture 'this' which is an instance of Java8Recommender.

javac generates the following code:

private static java.util.stream.Stream lambda$2(java.util.List); Code: 0: aload_0 1: invokeinterface #4, 1 // InterfaceMethod java/util/List.stream:()Ljava/util/stream/Stream; 6: aload_0 7: invokeinterface #4, 1 // InterfaceMethod java/util/List.stream:()Ljava/util/stream/Stream; 12: aload_0 13: invokedynamic #43, 0 // InvokeDynamic #8:lambda$:(LJava8Recommender;)Ljava/util/function/BiFunction; 18: invokestatic #44 // Method java/util/stream/Streams.zip:(Ljava/util/stream/Stream;Ljava/util/stream/Stream;Ljava/util/function/BiFunction;)Ljava/util/stream/Stream; 21: areturn

if you take a look to bytecode 12, instead of pushing 'this' (which is not materialized as a parameter anyway), the compiler push the argument of the lambda ('buys' in the source code). I think it's because both lies in local variable 0 but not in the same stack frame.

here is a simple test case to reproduce the bug: import java.util.function.Supplier; import java.util.function.Consumer;

class Bug2 { class Inner { Inner() { } }

void m() { foo(s -> bar(Inner::new)); }

static void foo(Consumer consumer) { }

static void bar(Supplier supplier) {

}

public static void main(String[] args) { new Bug2().m(); } }

while investigating this issue, I found another related issue, if the lambda take no parameter, the compiler throw an exception.

import java.util.function.Supplier;

class Bug { class Inner { Inner() { } }

void m() { foo(() -> bar(Inner::new)); }

static void foo(Runnable runnable) { }

static void bar(Supplier supplier) {

}

public static void main(String[] args) { new Bug().m(); } }

stack trace: java.lang.NullPointerException at com.sun.tools.javac.jvm.Code.emitop0(Code.java:546) at com.sun.tools.javac.jvm.Items$SelfItem.load(Items.java:367) at com.sun.tools.javac.jvm.Gen.genArgs(Gen.java:913) at com.sun.tools.javac.jvm.Gen.visitApply(Gen.java:1752) at com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1440) at com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:894) at com.sun.tools.javac.jvm.Gen.genArgs(Gen.java:913) at com.sun.tools.javac.jvm.Gen.visitApply(Gen.java:1752) at com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1440) at com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:894) at com.sun.tools.javac.jvm.Gen.visitExec(Gen.java:1698) at com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1271) at com.sun.tools.javac.jvm.Gen.genDef(Gen.java:684) at com.sun.tools.javac.jvm.Gen.genStat(Gen.java:719) at com.sun.tools.javac.jvm.Gen.genStat(Gen.java:705) at com.sun.tools.javac.jvm.Gen.genStats(Gen.java:756) at com.sun.tools.javac.jvm.Gen.visitBlock(Gen.java:1094) at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:884) at com.sun.tools.javac.jvm.Gen.genDef(Gen.java:684) at com.sun.tools.javac.jvm.Gen.genStat(Gen.java:719) at com.sun.tools.javac.jvm.Gen.genMethod(Gen.java:969) at com.sun.tools.javac.jvm.Gen.visitMethodDef(Gen.java:942) at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:771) at com.sun.tools.javac.jvm.Gen.genDef(Gen.java:684) at com.sun.tools.javac.jvm.Gen.genClass(Gen.java:2359) at com.sun.tools.javac.main.JavaCompiler.genCode(JavaCompiler.java:753) at com.sun.tools.javac.main.JavaCompiler.generate(JavaCompiler.java:1547) at com.sun.tools.javac.main.JavaCompiler.generate(JavaCompiler.java:1511) at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:909) at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:868) at com.sun.tools.javac.main.Main.compile(Main.java:516) at com.sun.tools.javac.main.Main.compile(Main.java:376) at com.sun.tools.javac.main.Main.compile(Main.java:365) at com.sun.tools.javac.main.Main.compile(Main.java:356) at com.sun.tools.javac.Main.compile(Main.java:77) at com.sun.tools.javac.Main.main(Main.java:62)

cheers, Rémi



More information about the lambda-dev mailing list