jvm-字节码指令

文章目录

      • 背景
      • 指令分析
        • 1 加载和存储指令
        • 2 运算指令
        • 3 类型转换指令
        • 4 对象创建与访问指令
        • 5 操作数栈管理指令
        • 6 控制转移指令
        • 7 方法调用和返回指令
        • 8 异常处理指令
        • 9 同步指令

Java虚拟机的指令由一个字节长度的、代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成。
以下笔记可以当做是阅读 字节码文件编译成的虚拟机指令文件 的帮助文档。

背景

字节码文件主要是操作虚拟机栈的栈帧中的数据。
jvm-字节码指令_第1张图片

我们可以用javap来查看一个class文件的字节码指令文件:

javap  -verbose  Main.class

eg.

public com.example.demo.Main();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: return
      LineNumberTable:
        line 7: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/example/demo/Main;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=3, args_size=1
         0: iconst_1
         1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         4: astore_1
         5: sipush        129
         8: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        11: astore_2
        12: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        15: new           #4                  // class java/lang/StringBuilder
        18: dup
        19: invokespecial #5                  // Method java/lang/StringBuilder."":()V
        22: aload_1
        23: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
        26: ldc           #7                  // String ,
        28: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        31: aload_2
        32: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
        35: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        38: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        41: return
      LineNumberTable:
        line 9: 0
        line 10: 5
        line 11: 12
        line 12: 41
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      42     0  args   [Ljava/lang/String;
            5      37     1     a   Ljava/lang/Integer;
           12      30     2     b   Ljava/lang/Integer;

指令分析

1 加载和存储指令

用于将数据在栈帧中的局部变量表操作数栈之间来回传输

指令 含义 示例
load 将一个局部变量加载到操作数栈 iload 1:将int型本地变量1加载到操作数栈顶中
store 将一个数值从操作数栈存储到局部变量表 astore_0( 0-3 ):将操作数栈顶引用型(reference)数值存入到第一个局部变量中
push 将一个整形数字(长度比较小)送到到栈顶 bipush:将单字节的常量值(-128至127)推送至栈顶;sipush:将一个短整型常量值(-32768至32767)推送至栈顶
ldc 将数值常量或String常量值从常量池中推送至栈顶 ldc: 将int, float或String型常量值从常量池中推送至栈顶;ldc_w: 将int, float或String型常量值从常量池中推送至栈顶(宽索引);ldc2_w: 将long或double型常量值从常量池中推送至栈顶(宽索引)
const 把简单的数值类型( iconst_(0 - 5) )送到栈顶,不带参数 aconst_null、iconst_m1、iconst_<i>、lconst_<l>、fconst_<f>、dconst_<d>;iconst_m1:将int型的-1推送至操作数栈顶;fconst_1:将float型的1推送至操作数栈顶
wide 扩充局部变量表的访问索引

2 运算指令

用于对两个操作数栈上的值进行某种特定运算,并把结果重新存入到操作数栈顶

指令 含义 示例
add 加法 支持 i, l, f, d;iadd:将栈顶两int型数值相加并将结果压入栈顶
sub 减法 支持 i, l, f, d
mul 乘法 支持 i, l, f, d
div 除法 支持 i, l, f, d
rem 求余 支持 i, l, f, d
neg 取反 支持 i, l, f, d
sh 位移 支持 i, l;ishl:将int型数值(有符号)左移位指定位数并将结果压入栈顶;iushr:将int型数值(无符号)右移位指定位数并将结果压入栈顶
or 按位或 支持 i, l;ior:将栈顶两int型数值作“按位或”并将结果压入栈顶
and 按位与 支持 i, l;
xor 按位异或 支持 i, l;
iinc 局部变量自增
cmp 比较 支持 d, f, l;dcmpg、dcmpl、fcmpg、fcmpl、lcmp

3 类型转换指令

将两种不同的数值类型进行相互转换。
java虚拟机支持从小范围到大范围(如int到long/float/double)的直接转换,无需显式的转换指令,当然你也可以显式写出来;而从大范围到小范围的转换必须要显式的使用转换指令来完成。

指令 含义 示例
i2l、f2b、l2f、l2d、f2d 宽化类型转换
i2b、i2c、i2s、l2i、f2i、f2l、d2i、d2l和d2f 窄化类型转换

4 对象创建与访问指令

创建对象和创建数组,以及访问对象和访问数组的指令

指令 含义 示例
new 新建类
newarray 新建数组
getfield、putfield、getstatic、putstatic 访问类变量,静态变量
aload 将一个数组元素加载到操作数栈 支持 b, c, i, l, f, d;iaload:将int型数组的指定索引的元素加载到操作数栈顶中
astore 将一个操作数栈顶的值存储到数组元素指定索引中 支持 b, c, i, l, f, d;dastore:将操作数栈顶中double型数值存入到指定数组的指定索引位置
arraylength 取数组长度
instanceof、checkcast 检查实例类型

5 操作数栈管理指令

直接操作操作数栈的指令

指令 含义 示例
pop、pop2 将操作数栈顶1或2个元素出栈
dup、dup2、dup_x1、dup_x2、dup2_x1、dup2_x2 复制1或2份操作数栈顶1或2个元素,重新压入栈顶
swap 将操作数栈最顶端两个元素互换

6 控制转移指令

可以让java虚拟机从 指定位置 的指令的下一条指令继续执行程序,可以认为控制转移指令就是在有条件或无条件地修改PC寄存器的值。

指令 含义 示例
ifeq、iflt、ifle、ifne、ifgt、ifge、ifnull、ifnonnull、if_icmpeq、if_icmpne、if_icmplt、if_icmpgt、if_icmple、if_icmpge、if_acmpeq和if_acmpne 条件分支
tableswitch、lookupswitch 复合条件分支
goto、goto_w、jsr、jsr_w、ret 无条件分支

7 方法调用和返回指令

指令 含义 示例
invokevirtual 调用对象实例,根据对象的实际类型进行分派(虚方法分派)
invokeinterface 调用接口方法,它对在运行时搜索一个实现了这个接口方法的对象,找出合适的方法进行调用
invokespecial 调用一些需要特殊处理的实例方法,如实例初始化方法、私有方法、父类方法
invokestatic 调用类方法(static方法)
invokedynamic 执行在运行时动态解析出调用点限定符所引用的方法,invokedynamic指令的分派逻辑是由用户所设定的引导方法决定的

8 异常处理指令

指令 含义 示例
athrow 程序中显式抛出异常(throw语句)

9 同步指令

java虚拟机支持方法级的同步和方法内部代码块的同步,这两种同步结构都是使用管程(Mentor)来支持的。

方法级的同步是隐式的,即无须通过字节码指令来控制。它实现在方法调用和返回操作之中。虚拟机可以从方法常量池的方法表结构中的ACC_SYNCHRONIZED访问标志得知一个方法是否声明为同步方法。当方法调用时,调用指令将会检查方法的ACC_SYNCHRONIZED访问标志是否被设置,如果设置了,执行线程就要求先成功持有管程,然后才能执行方法,最后当方法完成(无论是正常完成还是非正常完成)时释放管程。在方法执行期间,执行线程持有了管程,其他任何线程都无法再获取到同一个管程。如果一个同步方法执行期间抛出了异常,并且在方法内部无法处理此异常,那么这个同步方法所持有的管程将在异常抛到同步方法之外时自动释放。

方法内部代码块的同步需要显式声明指令,来支持synchronized关键字语义

指令 含义 示例
monitorenter、monitorexit 方法内部代码块的同步,调用过的每个monitorenter指令必须要执行其对应的monitorexit指令

相关:https://blog.csdn.net/YABAJ/article/details/89240707

你可能感兴趣的:(java)