使用jvm指令解析局部变量的加减乘除

使用jvm指令解析局部变量的加减乘除

基础指令说明

  • iconst类指令说明 (部分志指令):
该系列命令主要负责把简单的数值类型送到栈顶。该系列命令不带参数。注意只把简单的数值类型送到栈顶时,才使用如下的命令。比如对应int型才该方式只能把-1,0,1,2,3,4,5(分别采用iconst_m1,iconst_0, iconst_1, iconst_2, iconst_3,iconst_4, iconst_5)送到栈顶。对于int型,其他的数值请使用push系列命令(比如bipush)

 | 指令码  | 助记符 |      说明         |
 | ------------- | ------------- |------------- |
 | 0x02  | iconst_m1  | 将int型(-1)推送至栈顶  |
 | 0x03  | iconst_0  | 将int型(0)推送至栈顶  |
 | 0x04  | iconst_1  | 将int型(1)推送至栈顶  |
 | 0x05  | iconst_2  | 将int型(2)推送至栈顶  |
 | 0x06  | iconst_3  | 将int型(3)推送至栈顶  |
 | 0x07  | iconst_4  | 将int型(4)推送至栈顶  |
  • store系列
该系列命令负责把栈顶的值存入本地变量。这里的本地变量不仅可以是数值类型,还可以是引用类型。如果是把栈顶的值存入到前四个本地变量的话,采用的是istore_0,istore_1,istore_2,istore_3(它们分别表示第0,1,2,3个本地整形变量)这种不到参数的简化命令形式。如果是把栈顶的值存入到第四个以上本地变量的话,将使用istore命令这种形式,在它后面给一参数,以表示是把栈顶的值存入到第几个(从0开始)本地变量中。对本地变量所进行的编号,是对所有类型的本地变量进行的(并不按照类型分类)。对于非静态函数,第一变量是this,它是只读的.还有函数传入参数也算本地变量,在进行编号时,它是先于函数体的本地变量的。
  • push系列
该系列命令负责把一个整形数字(长度比较小)送到到栈顶。该系列命令有一个参数,用于指定要送到栈顶的数字。注意该系列命令只能操作一定范围内的整形数值,超出该范围的使用将使用ldc命令系列。
  • load系列(部分志指令)
 | 指令码  | 助记符 |      说明         |
 | ------------- | ------------- |------------- |
|0x15 |iload |将指定的int型本地变量推送至栈顶|
|0x16 |lload |将指定的long型本地变量推送至栈顶|
|0x17 |fload |将指定的float型本地变量推送至栈顶|
|0x18 |dload |将指定的double型本地变量推送至栈顶|
|0x19 |aload |将指定的引用类型本地变量推送至栈顶|
|0x1a |iload_0 |将第一个int型本地变量推送至栈顶|
|0x1b |iload_1 |将第二个int型本地变量推送至栈顶|
|0x1c |iload_2 |将第三个int型本地变量推送至栈顶|
|0x1d |iload_3 |将第四个int型本地变量推送至栈顶|
| ------------- | ------------- |------------- |
|0x2e |iaload |将int型数组指定索引的值推送至栈顶|
|0x2f |laload |将long型数组指定索引的值推送至栈顶|
|0x30 |faload |将float型数组指定索引的值推送至栈顶|
|0x31 |daload |将double型数组指定索引的值推送至栈顶|
  • 栈顶元素数学操作及移位操作系列(部分志指令)
| 指令码  | 助记符 |      说明         |
 | ------------- | ------------- |------------- |
 |0x5f  |swap  |将栈最顶端的两个数值互换(数值不能是long或
 double类型的)
 |0x60  |iadd  |将栈顶两int型数值相加并将结果压入栈顶
 |0x61  |ladd  |将栈顶两long型数值相加并将结果压入栈顶
 |0x62  |fadd  |将栈顶两float型数值相加并将结果压入栈顶
 |0x63  |dadd  |将栈顶两double型数值相加并将结果压入栈顶
 |0x64  |isub  |将栈顶两int型数值相减并将结果压入栈顶
 |0x65  |lsub  |将栈顶两long型数值相减并将结果压入栈顶
 |0x66  |fsub  |将栈顶两float型数值相减并将结果压入栈顶
 |0x67  |dsub  |将栈顶两double型数值相减并将结果压入栈顶

基础类

class Test{
  public static void main(String args[]){
   int a=1;
   int b=2;
   int c=(a+b)*101;
   int d = c-20;
   System.out.print(d);
  }
}
  • 反编译
javac Test.java
javap -c Test.class > Test.txt # 得到反编译后的代码
  • 得到编译后的结果:
Compiled from "Test.java"
class Test {
  Test();
    Code:
       0: aload_0  第一变量是this,
       1: invokespecial #1   调用超类构造方法,实例初始化方法,私
有方法                // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1    第一个变量压入栈顶
       1: istore_1    将栈顶值存入第一个本地变量
       2: iconst_2    第二个变量压入栈顶
       3: istore_2    将栈顶值存入第二个本地变量
       4: iload_1     第一个本地变量送到栈顶
       5: iload_2     第二个本地变量送到栈顶
       6: iadd        add顾名思义 加法运算 (a+b)
       7: bipush        101  将101送到栈顶
       9: imul       将栈顶两int型数值相乘并将结果压入栈顶 即(a+b)* 101
      10: istore_3    将第三个变量存入本地变量 ---c的值
      11: iload_3     第三个本地变量入栈顶
      12: bipush        20  将20压入栈顶
      14: isub            将栈顶两int型数值相减并将结果压入栈顶  减法运算
      15: istore        4   将栈顶int型数值存入指定本地变量 即d的值
      17: getstatic     #2      获取指定类的静态域,并将其值压入栈顶             // Field java/lang/System.out:Ljava/io/PrintStream;
      20: iload         4   将指定的int型本地变量推送至栈顶 即d的值
      22: invokevirtual #3         调用实例方法         // Method java/io/PrintStream.print:(I)V
      25: return  从当前方法返回void
} 

来源:微信小程序(苏克分享)
gh_0b089e4e80ed_258

1 个赞

在IDEA中查看反编译字节码

image

oracle jvm 指令集参照表

1 个赞