《深入Java虚拟机学习笔记》- 第10章 栈和局部变量操作

1.     10章 栈和局部变量操作

基本指令分析:

规律:

store表示弹出操作数栈(操作数栈是一个栈)顶的数据放入局部变量区

store_x表示弹出操作数栈顶的数据放入局部变量区索引为x的地方

load表示将局部变量区中某个位置(即某个索引,因为局部变量区是一个数组)的局部变量压入操作数栈

load_x表示将局部变量区中x位置的局部变量压入操作数栈

astore表示弹出操作数栈顶的对象引用,并放入局部变量区

astore_x也跟前面有相同的规则

aload表示将局部变量区中某个位置的对象引用压入操作数栈

aload_x也跟前面有相同的规则

const_x表示将某个值(x)压入操作数栈

bipush x表示将某个值(x,类型是byte)转换为int类型压入操作数栈

sipush x 表示将某个值(x,类型为short)转换为int类型压入操作数栈

ldc x表示将常量池中的某个入口地址(x表示常量池入口地址)压入操作数栈

 

pop表示将操作数栈顶部的数据弹出栈

dup表示复制操作数栈顶的数据

 

下面,让我们开始通过一些例子来分析这些指令:

jClassLib是一个开源的分析类文件内容的工具,可以从网上下载,运行之后,类似下面的界面:

《深入Java虚拟机学习笔记》- 第10章 栈和局部变量操作_第1张图片 

比如下面的代码:

public class HelloWorld01 {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       int i0 = 1;

       int i1 = 10;

       int i2 = i0 + i1;

       System.out.println(i2);

    }

}

 

对应的方法的指令如下:

《深入Java虚拟机学习笔记》- 第10章 栈和局部变量操作_第2张图片

 

int i0=1,目标是给变量i0赋值:

iconst_1意思是将1这个值压入操作数栈

istore_1意思是将操作数栈顶的数据(即刚压进去的值1)弹出并存储在变量区中索引为1的地方

bipush 10意思是将10压入操作数栈

istore_2意思是将操作数栈顶的数据(即刚压进去的10)弹出并存储在变量区中索引为2的地方

iload_1表示将变量区中索引为1的值压入操作数栈(这个值就是1

iload_2表示将变量区中索引为2的值压入操作数栈(这个值就是10

iadd表示将操作数栈中的两个数弹出相加,并将结果压入操作数栈中

istore_3表示将操作数栈顶的数据(即在iadd操作码中压进去的相加之后的结果)弹出并存储在变量区中索引为3的地方

从上面的分析可以看到,很多数据,比如110这些常量值,编译器是直接将它们放在指令序列中!

 

再看下面的代码:

public class HelloWorld02 {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       long i0 = 100;

       long i1 = 999999999L;

       long i2 = i0 + i1;

       System.out.println(i2);

    }

}

 

其对应的指令序列为:

 

《深入Java虚拟机学习笔记》- 第10章 栈和局部变量操作_第3张图片

ldc2_w #16表示将常量池16号的值压入操作数栈,两个字长(一个字长是32位)的宽度

lstore_1表示将操作数栈顶的数据弹出放到变量区索引号为1的地方

ldc2_w #18表示将常量池18号的值压入操作数栈

lstore_3表示将操作数栈顶的数据弹出放到变量区索引号为3的地方(之所以放到索引号为3而不是2的地方,是因为一个Long占据了两个字长,即两个索引号)

lload_1lload_3自然也就表示将变量区索引号为13的两个值压入操作数栈

ladd表示将操作数栈中的两个数据弹出并相加,结果再次入栈

lstore 5表示将操作数栈顶的数据(刚才相加的计算结果)弹出,并放到变量区索引号为5的地方

从上面的分析中,可以知道,对于比较大的数据,编译器会把这些数据放到常量池中,在指令序列中则仅指明位置而已。

 

再看下面的例子:

public class HelloWorld03 {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       String stringvalue1 = "H";

       String stringvlaue2 = "H";

       String stringvalue3 = "Hello";

       char c = 'H';

    }

}

 

《深入Java虚拟机学习笔记》- 第10章 栈和局部变量操作_第4张图片 

上面例子可以看出,字符串也是放到常量池中的,而且相同的字符串在常量池中只有一份。

字符则把它当成是一个int类型压入到操作数栈中。

 

再看下面的代码:

public class HelloWorld05 {

 

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       int result = 0;

       for(int i=0; i<10; i++){

           result = result + i;

       }

    }

}

 

《深入Java虚拟机学习笔记》- 第10章 栈和局部变量操作_第5张图片

iconst_0表示将0压入操作数栈

istore_1表示将栈顶数据弹出存放到变量区,索引号为1(即给result这个变量赋值)

iconst_0表示将0压入操作数栈

istore_2表示将栈顶数据弹出存放到变量区,索引号为2(即给i这个变量赋值,int i=0

goto 14,跑到14行去

14行中,iload_2表示把变量区索引号为2的值压入操作数栈(即取出i变量)

bipush 10,表示把10这个值压入操作数栈

if_icmplt 7,表示弹出操作数栈的两个数据,并判断操作数栈中的两个数的大小(即是否i<10?),如果是,则跑到第7行,否则,直接往下执行了

在第7行中:iload_1即把变量区索引号为1的值压入操作数栈(即result变量)

iload_2表示把变量区索引号为2的值压入操作数栈(即i变量)

iadd前面已经讲过了,就是把两个操作数栈中的数据弹出并相加,把结果重新压入操作数栈

istore_1表示把操作数栈中的数据弹出,并存放到变量区索引号为1的地方(即更新了result变量的值)

iinc 2 by 1,表示的是将变量区索引号为2的值自增1

然后又到了14行,将重复上述的过程!

你可能感兴趣的:(java,虚拟机,String,存储,Class,编译器)