Jvm:编译器需要在方法字节码中的哪些位置指定堆栈映射帧?

sag*_*aga 5 java jvm bytecode java-bytecode-asm

这是asm用户指南的摘录:

为了节省空间,编译方法每个指令不包含一个帧:实际上它只包含与跳转目标或异常处理程序相对应的指令的帧,或者遵循无条件跳转指令.实际上,可以从这些框架中容易且快速地推断出其他框架.

我可以理解为什么jvm需要跳转目标和异常处理程序的堆栈映射帧,但是goto在不必要的需求之后不需要有堆栈映射帧,因为在方法字节码中的某处必须有一个跳转指令在指令之后的goto指令,该情况将由第一个要求处理.它必须是这样的,否则后面的指令goto将无法访问,因此是可丢弃的.

例:

下面给出了一个方法及其字节码:

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 */
}
Run Code Online (Sandbox Code Playgroud)

index 11处的指令是一个goto指令,索引处的指令414,指令就在11它的跳转目标之后.

在无条件跳转后需要堆栈映射框架的理性是什么?

Ant*_*ony 5

堆栈映射的目标是允许在单个线性传递代码中执行验证.

如果按照goto语句代码中有没有跳转指向它,那么代码是死的,理论上并不需要进行验证.但是,验证者不知道这一点.由于它在代码中执行单次传递,因此无法提前知道代码是否已死.因此,它必须验证所有内容,这意味着它需要一个堆栈框架来开始.

请注意,这与传统的非堆栈映射验证程序不同.在引入堆栈映射之前,验证器将简单地迭代它找到的所有代码(有效地)跟随跳转,并迭代直到收敛.这意味着在旧的验证器下,根本不会触及死代码.