Generated JVM byte code gives "stack shape inconsistent" error

I've been teaching myself how to generate JVM byte code directly for a side project recently, and got stuck on the following exception a few times:

Exception in thread "main" java.lang.VerifyError: stack shape inconsistent (class: CompiledTest method: evaluate(Lcom/ibm/test/Param;)S) at pc: 2
    at java.lang.J9VMInternals.verifyImpl(Native Method)
    at java.lang.J9VMInternals.verify(J9VMInternals.java:66)
    at java.lang.J9VMInternals.initialize(J9VMInternals.java:127)
    at java.lang.Class.newInstanceImpl(Native Method)
    at java.lang.Class.newInstance(Class.java:1300)
    at TestHarness.execute(TestHarness.java:158)
    at TestHarness.main(TestHarness.java:100)

After a long time Googling unsuccessfully, I hacked around until stumbled across the answer. Turns out this exception is caused when your byte code is attempting to perform an instruction but the stack contains an invalid type for that instruction.

One example is if the top of the stack contains a string but you're using a operand that expects an integer. Using BCEL:

//Push a string onto the stack
il.append( new PUSH( cg.getConstantPool(), "123" ));

//Attempt to save the top of the stack using "ISTORE"
LocalVariableGen var = mg.addLocalVariable( "var", Type.STRING, il.getEnd(), null );
il.append( new ISTORE( var.getIndex() ));

Note that I'm using the integer-specific ISTORE instruction to save the variable even though I've pushed the string "123" onto the stack!  Try to execute the class generated from this code, and you'll get the VerifyError from above.

The simple, and obvious in hindsight, fix is to change the ISTORE instruction to ASTORE.

blog comments powered by Disqus