《深入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是一個開源的分析類文件內容的工具,可以從網上下載,運行之後,類似下面的界面:

 

比如下面的代碼:

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);

    }

}

 

對應的方法的指令如下:

 

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);

    }

}

 

其對應的指令序列爲:

 

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';

    }

}

 

 

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

字符則把它當成是一個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;

       }

    }

}

 

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行,將重複上述的過程!

發佈了34 篇原創文章 · 獲贊 30 · 訪問量 38萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章