【问题标题】:JVM Verify Error 'Illegal type at constant pool'JVM验证错误'常量池中的非法类型'
【发布时间】:2015-02-23 19:48:11
【问题描述】:

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

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;

在那一行,这似乎是有效的。我在这里做错了什么/错过了什么?

【问题讨论】:

    标签: java jvm java-bytecode-asm


    【解决方案1】:

    我发现了我的错误。错误就在这里:

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

    我在 interface 方法上使用了 invokevirtual,这通常不是一个好主意。不过我认为验证者抛出的错误应该更清楚到底是什么错误。

    【讨论】:

    • 这可能值得作为编译器错误提交。
    • 哦,我知道这是你的编译器,而不是 javac。在这种情况下,请将错误报告发送给您自己。
    【解决方案2】:

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

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

    更多详情请参阅issue here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多