JVM验证错误'常量池中的非法类型'

时间:2015-02-23 19:48:12

标签: java jvm java-bytecode-asm

我正在编写自己的编译器,我正在尝试编译以下代码:

List[String] list = List("a", "b", "c", "d")
list stream map((String s) => s.toUpperCase())
System out println list

编译器解析,链接或编译代码没有问题,但是当执行它时,JVM会抛出以下错误:

java.lang.VerifyError: Illegal type at constant pool entry 40 in class dyvil.test.Main
Exception Details:
  Location:
    dyvil/test/Main.main([Ljava/lang/String;)V @29: invokevirtual
  Reason:
    Constant pool index 40 is invalid
  Bytecode:
    ...

我尝试使用javap来查找问题,这是指令@29

29: invokevirtual #40 // InterfaceMethod java/util/Collection.stream:()Ljava/util/stream/Stream;

Constant Pool中的条目(也使用javap):

#37 = Utf8               stream
#38 = Utf8               ()Ljava/util/stream/Stream;
#39 = NameAndType        #37:#38 // stream:()Ljava/util/stream/Stream;
#40 = InterfaceMethodref #36.#39 // java/util/Collection.stream:()Ljava/util/stream/Stream;

使用Eclipse类文件查看器打开类时,应该读取@29的行:

Class Format Exception

以及所有以下说明不再显示(本地人除外,......)。但是,ASM字节码插件写

INVOKEVIRTUAL java/util/Collection.stream ()Ljava/util/stream/Stream;

在该行,似乎是有效的。我在做错了什么/在这里失踪了?

2 个答案:

答案 0 :(得分:8)

我发现了自己的错误。错误在于:

invokevirtual #40 // InterfaceMethod
      ^^^^^^^        ^^^^^^^^^

我在接口方法上使用调用虚拟,这通常不是一个好主意。但是我认为验证者抛出的错误应该更明确一些错误。

答案 1 :(得分:1)

使用ASM,您会看到此错误,因为isInterface标志不正确。 isInterface的参数visitMethodInsn指的是目标/所有者/目的地,而不是当前的上下文。

i.o.w使用INVOKEVIRTUAL时,isInterface为假。

有关详细信息,请参阅issue here