javajvmjava-bytecode-asm

JVM Verify Error 'Illegal type at constant pool'


I am currently writing my own compiler and I am trying to compile the following code:

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

The compiler has no problem parsing, linking or compiling the code, but when it comes to executing it, the JVM throws the following error:

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:
    ...

I tried to use javap to find the problem, and this is the instruction @29:

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

And the entry in the Constant Pool (also using 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;

When opening the class with the Eclipse Class File Viewer, the line where @29 should be reads:

Class Format Exception

and all following instructions are not shown anymore (except for Locals, ...). However, the ASM Bytecode Plugin writes

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

at that line, which appears to be valid. What am I doing wrong / missing here?


Solution

  • I figured out my mistake. The error lies here:

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

    I am using invokevirtual on an interface method, which is generally not a good idea. However I think that the error thrown by the verifier should be a bit more clear about what is actually wrong.