有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java JVM验证错误“常量池中的非法类型”

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

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;

以及常量池中的条目(也使用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) 个答案

  1. # 1 楼答案

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

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

    我在接口上使用invokevirtual方法,这通常不是一个好主意。然而,我认为验证器抛出的错误应该更清楚地说明什么是真正的错误

  2. # 2 楼答案

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

    当使用INVOKEVIRTUAL时,isInterface为false

    有关更多详细信息,请参见issue here