字节码指令以及操作数栈的分析

事先创建一个java类,如下:

package com.yang.jvm;

public class Demo {

    public int getNum(){
        int a=1;
        int b=2;
        int c=3;
        int d=4;
        return (a+b-c)*d;
    }
}

在命令窗口输入:F:\jvmdemo>javap -c -verbose build/classes/java/main/com/yang/jvm/Demo.class

 


执行命令后获得字节码文件内容:

Classfile /F:/jvmdemo/build/classes/java/main/com/yang/jvm/Demo.class
  Last modified 2019-10-23; size 428 bytes
  MD5 checksum b4f01d8c01f685e501ee4f8dc209652d
  Compiled from "Demo.java"
public class com.yang.jvm.Demo
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#20         // java/lang/Object."<init>":()V
   #2 = Class              #21            // com/yang/jvm/Demo
   #3 = Class              #22            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               LocalVariableTable
   #9 = Utf8               this
  #10 = Utf8               Lcom/yang/jvm/Demo;
  #11 = Utf8               getNum
  #12 = Utf8               ()I
  #13 = Utf8               a
  #14 = Utf8               I
  #15 = Utf8               b
  #16 = Utf8               c
  #17 = Utf8               d
  #18 = Utf8               SourceFile
  #19 = Utf8               Demo.java
  #20 = NameAndType        #4:#5          // "<init>":()V
  #21 = Utf8               com/yang/jvm/Demo
  #22 = Utf8               java/lang/Object
{
  public com.yang.jvm.Demo();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/yang/jvm/Demo;

  public int getNum();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=5, args_size=1
         0: iconst_1
         1: istore_1
         2: iconst_2
         3: istore_2
         4: iconst_3
         5: istore_3
         6: iconst_4
         7: istore        4
         9: iload_1
        10: iload_2
        11: iadd
        12: iload_3
        13: isub
        14: iload         4
        16: imul
        17: ireturn
      LineNumberTable:
        line 6: 0
        line 7: 2
        line 8: 4
        line 9: 6
        line 10: 9
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      18     0  this   Lcom/yang/jvm/Demo;
            2      16     1     a   I
            4      14     2     b   I
            6      12     3     c   I
            9       9     4     d   I
}
SourceFile: "Demo.java"

F:\jvmdemo>javap -c -verbose build/classes/java/main/com/yang/jvm/Demo.class
Classfile /F:/jvmdemo/build/classes/java/main/com/yang/jvm/Demo.class
  Last modified 2019-10-23; size 428 bytes
  MD5 checksum b4f01d8c01f685e501ee4f8dc209652d
  Compiled from "Demo.java"
public class com.yang.jvm.Demo
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#20         // java/lang/Object."<init>":()V
   #2 = Class              #21            // com/yang/jvm/Demo
   #3 = Class              #22            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               LocalVariableTable
   #9 = Utf8               this
  #10 = Utf8               Lcom/yang/jvm/Demo;
  #11 = Utf8               getNum
  #12 = Utf8               ()I
  #13 = Utf8               a
  #14 = Utf8               I
  #15 = Utf8               b
  #16 = Utf8               c
  #17 = Utf8               d
  #18 = Utf8               SourceFile
  #19 = Utf8               Demo.java
  #20 = NameAndType        #4:#5          // "<init>":()V
  #21 = Utf8               com/yang/jvm/Demo
  #22 = Utf8               java/lang/Object
{
  public com.yang.jvm.Demo();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/yang/jvm/Demo;

  public int getNum();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=5, args_size=1
         0: iconst_1
         1: istore_1
         2: iconst_2
         3: istore_2
         4: iconst_3
         5: istore_3
         6: iconst_4
         7: istore        4
         9: iload_1
        10: iload_2
        11: iadd
        12: iload_3
        13: isub
        14: iload         4
        16: imul
        17: ireturn
      LineNumberTable:
        line 6: 0
        line 7: 2
        line 8: 4
        line 9: 6
        line 10: 9
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      18     0  this   Lcom/yang/jvm/Demo;
            2      16     1     a   I
            4      14     2     b   I
            6      12     3     c   I
            9       9     4     d   I
}
SourceFile: "Demo.java"

 本次需要分析的字节码内容如下:

 

 java虚拟机栈和栈帧关系图:

栈帧的组成:局部变量表,操作数栈,动态链接,方法出口 

由字节码文件可以看到,栈深度为2(stack=2)说明操作数栈的深度是2,本地变量表变量长度为5因此过程分析如下:

0.指令 iconst_1 意义:将常量1压入操作数栈的栈顶

 

 1.指令istore_1:意义将操作数栈顶的数字弹出,然后赋值给局部变量表索引为1的变量,索引为0的变量为this

 

 

将常量1入栈,并存到栈顶

 

 

 

 

 

 

 

 

 2. 同理 iconst_2istore_2 分别表示将常量2入栈,存到栈顶,然后出栈,赋值给局部变量表索引为2的变量

 

 


 

 3.之后的指令 iconst_3 和 istore_3 , iconst_4 和 istore 4 同理,他们执行完后此时操作数栈和局部变量表如下:

 

 

 

 4. 之后执行 iload_1,意义是将局部变量表索引为1的变量压入操作数栈的栈顶
  

 

 5.同理:iload_2,意义是将局部变量表索引为2的变量压入操作数栈的栈顶此时:

 

 

 

 6.指令iadd,表示将操作数栈的2个值弹出,然后计算他们的和,之后将结果压入栈顶

 

 此时:

 

 

 

 7.之后执行命令iload_3,表示将局部变量索引为3的变量入栈,到栈顶,此时:

 

 

 

 

 

 8.isub将操作数栈的2个数弹出,然后做减法,之后将结果压入栈顶

 

 

 

 

 

 9. iload 4 表示将局部变量索引为4的变量压入栈顶:此时

 

 

10. imul 表示将操作数栈的2个数弹出,并做乘法运算,之后将结果压入栈顶:

 

 11.ireturn指令:将操作数栈顶的数弹出,然后压入调用者的操作数栈的栈顶,如果操作操作数栈除了栈顶的内容外还有其他内容,其他内容都会被丢弃掉,所以这里将0返回

 

 



 

 

 

 

     


       

 

posted @ 2019-10-23 10:34  yangxiaohui227  阅读(562)  评论(0编辑  收藏  举报