This is an excerpt from the asm
user guide:
In order to save space, a compiled method does not contain one frame per instruction: in fact it contains only the frames for the instructions that correspond to jump targets or exception handlers, or that follow unconditional jump instructions. Indeed the other frames can be easily and quickly inferred from these ones.
I can understand why the jvm needs stack map frames at jump targets and for exception handlers, but isn't the need to have a stack map frame after a goto
a needless requirement, since there must be a jump instruction somewhere in the method bytecode which points to the instruction just after the goto
instruction, and that case will be handled by the first requirement. It has to be that way or otherwise the instruction after goto
will be unreachable, and hence discardable.
Example:
A method and it's bytecode are given below:
public class t {
public static void main(String[] s) {
int i = 10;
while ( i > 0 ) {
i = i + 1;
}
int j = 10;
}
}
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: bipush 10
2: istore_1
3: iload_1
4: ifle 14
7: iload_1
8: iconst_1
9: iadd
10: istore_1
11: goto 3
14: bipush 10
16: istore_2
17: return
LineNumberTable:
line 9: 0
line 10: 3
line 11: 7
line 13: 14
line 14: 17
StackMapTable: number_of_entries = 2
frame_type = 252 /* append */
offset_delta = 3
locals = [ int ]
frame_type = 10 /* same */
}
Instruction at index 11
is a goto instruction and the instruction at index 4
has 14
, the instruction just after 11
as it's jump target.
What's the rational behind requiring a stack map frame following an unconditional jump?
A Java Virtual Machine stack stores frames (§2.6). A Java Virtual Machine stack is analogous to the stack of a conventional language such as C: it holds local variables and partial results, and plays a part in method invocation and return.
The JVM is what takes the bytecode and translates it into machine code. The point of bytecode is that you get better performance than a strictly interpreted language (like PHP for example) because the bytecode is already partially compiled and optimized.
The bytecode format When a JVM loads a class file, it gets one stream of bytecodes for each method in the class. The bytecodes streams are stored in the method area of the JVM. The bytecodes for a method are executed when that method is invoked during the course of running the program.
Byte code is an intermediate code between the source code and machine code. It is a low-level code that is the result of the compilation of a source code which is written in a high-level language. It is processed by a virtual machine like Java Virtual Machine (JVM).
The goal of stack maps is to allow verification to be performed in a single linear pass through the code.
If the code following a goto has no jumps pointing to it, then the code is dead and theoretically does not need to be verified. However, the verifier does not know this. Since it is performing a single pass through the code, it is impossible to know ahead of time whether the code is dead or not. Therefore, it has to verify everything, and this means that it needs a stack frame to start with.
Note that this is different from the legacy non-stack map verifier. Prior to the introduction of stack maps, the verifier would simply iterate through all the code it found, (effectively) following jumps, and iterate until convergence. This means that under the old verifier, dead code is never touched at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With