[jvm解析系列][十三]字節碼指令小節,從字節碼看JVM的棧解釋器執行過程。

衆所周知,JVM以前一直採用的是解釋執行,但是後來在歷代的版本更迭中也加入了編譯執行。所以總的來說JVM是包含了解釋執行和編譯執行。這一部分不屬於JVM的範疇了,已經屬於編譯了,大多數都是進行詞法分析之類的,以後有時間會補充。

同時大家都知道現在大體上分爲兩種指令集架構,第一種就是基於棧的第二種是基於寄存器的,簡單點說,基於寄存器的架構速度更快,但是可移植性不強,但是基於棧的指令集架構雖然慢,但是可移植性很強,大家都知道java本身就是依靠可移植性出名的,所以無可爭議的使用了棧的指令集架構。(也有例外,dalvik是基於寄存器的)

下面我們詳述一下JVM的棧解釋器執行過程,在此之前我們先來講一下字節碼的指令含義:



加載和存儲:加載和存儲指令一般可以把棧幀中的局部變量放到操作數棧中,然後把操作數棧中的變量存回棧幀中。

把局部變量加載到操作數棧中:主要有iload,liload_<n>,lload,(每一個指令前面代表的是它操作的數據類型iload就是int   lload就是long,接下來我們去除前面的前綴統一用x代替減少篇幅。)

從操作數棧中存回局部變量表 xstore_<n>,xstore(注意有的後面跟了_<n>這是省略了諸如xstore_1,xstore_2這樣的指令,xstore默認爲xstore_0,之後統一用xstore_<n>替代)

加載一個常量到操作數棧:xipush,xdc,xconst_<n>



運算指令:執行加減乘除取餘等運算

加:xadd

減:xsub

乘:xmul

除:xdiv

取餘:xrem

取反:xneg

位移:xshl。xshr

按位或指令:xor

按位與指令:xand

按位異或指令:xxor

比較指令:xcmpl



指令上我們大概就講這麼多,接下來就是我們查看字節碼的時刻了。首先寫一個方法如下:

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int a = 2;
		int b = 1;
		int c = a+b;
		System.out.println(c);
	}


然後我們用javap查看一下字節碼



可以看到我們的操作從第01兩行來看這事int a =2;的操作,先放置常量2到棧頂然後取出來放到常量表中1的位置。23同樣。

而45這兩個數字就是把局部變量表上12這兩個位置的數加載到操作棧中,然後用6行相加存入常量表3的位置。

爲了表明0123和7真的實在存儲數字到常量表我們對方法做如下修改:

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int c = 1+2;
		System.out.println(c);
	}
字節碼如下

很明顯的之前的0123行那種存儲的行爲沒有了,同樣我們能看到javac給我們的優化,在第0行把1+2直接變成了3。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章