In the article Inline constant pool, we showed a delta to make programming Java bytecode easier. In this article, we’ll take another step towards that end. In bytecode, there are no structured programming statements, instead there are jump instructions. These instructions take an integer as a argument, that specifies an offset in number of bytes, from the jump instruction to another instruction further along the list of instructions. Here is an example of a Code attribute that contains a list of instructions and a StackMapTable:
Code: Instructions: iload 0 iconst 2 if_icmpge 7 iconst 1 goto 16 iload 0 iconst 1 isub invokestatic Fibonacci.fibonacci (I)I iload 0 iconst 2 isub invokestatic Fibonacci.fibonacci (I)I iadd ireturn StackMapTable: same frame, offset:9 same locals, 1 stack item, offset:12 int
if_icmpge 7, takes two values from the top of the stack, compares them, and if the first is greater than the second, it will jump 7 bytes ahead in the instruction list. The jump instruction itself is 3 bytes, the
iconst 1 instruction after it is 1 byte, and the
goto 16 instruction is again 3 bytes. That makes a total of 7 bytes, so the jump will be to the next instruction,
Note also that below the instruction the StackMapTable is specified. It must contain an entry for each instruction that is jumped to, in order to tell the JVM what the stack and local variables look like at that point. Each entry has an offset property that specifies to which instruction the entry applies. The first entry has offset 9, counted from the start of the program, which points to the
iload 0 instruction that
if_icmge 7 jumps to. The second entry has offset 12, counted from the previous offset 9, which points to the
ireturn instruction at the end, which is jumped to be the
goto 16 instruction.
Understanding the above code by calculating to what instruction each jump goes, and for what instruction each stack map table entry is, is cumbersome. Let’s remove all the byte offsets with the delta LabelledLocations. Our example from earlier now becomes:
Code: Instructions: iload 0 iconst 2 if_icmpge <false> iconst 1 goto <end> label <false> same frame iload 0 iconst 1 isub invokestatic Fibonacci.fibonacci (I)I iload 0 iconst 2 isub invokestatic Fibonacci.fibonacci (I)I iadd label <end> same locals, 1 stack item int ireturn
As you can see we’ve added a new type of instruction, the label, which has a name and contains an entry from the stack map table. The stack map table itself is gone. Also, the jump instructions now point to labels instead of using byte offsets.