1. 程式人生 > >JVM學習05-位元組碼執行過程和JVM指令集

JVM學習05-位元組碼執行過程和JVM指令集

1. 位元組碼的Code部分

在執行位元組碼的時候,無非也就是對呼叫類中的函式。那麼下面將介紹下位元組碼函式的Code部分,Code部分的程式碼一個可以用java自帶的命令javap命令進行檢視。還可以在eclipse中安裝ByteCode visualizer外掛檢視,具體使用自行研究。
在我介紹java記憶體模型的時候,函式的執行過程是分配在棧記憶體中的,所以在執行Code部分的時候肯定會涉及到區域性變量表和運算元棧,同時還會涉及到程式計數器。之前也介紹了一個小例子,下面繼續先以一個小例子講述。

2. 例子

原始碼:

package com.minosa.test;
public
class HelloClass { public int foo(){ int a = 1; int b = 2; int c = a + b; return c; } }

ByteCode visualizer檢視

public int foo() {
        /* L6 */
        0 iconst_1;
        1 istore_1;               /* a */
        /* L7 */
        2 iconst_2;
        3 istore_2;               /* b */
/* L8 */ 4 iload_1; /* a */ 5 iload_2; /* b */ 6 iadd; 7 istore_3; /* c */ /* L9 */ 8 iload_3; /* c */ 9 ireturn; /* LineNumberTable */ /* ----------+------------- */ /* start_pc | line_number */
/* ----------+------------- */ /* 0 | 6 */ /* 2 | 7 */ /* 4 | 8 */ /* 8 | 9 */ /* ----------+------------- */ /* LocalVariableTable */ /* -------+----------+--------+------------+------------------ */ /* index | start_pc | length | name_index | descriptor_index */ /* -------+----------+--------+------------+------------------ */ /* 0 | 0 | 10 | 12 | 13 */ /* 1 | 2 | 8 | 16 | 17 */ /* 2 | 4 | 6 | 18 | 17 */ /* 3 | 8 | 2 | 19 | 17 */ /* -------+----------+--------+------------+------------------ */ /* ExceptionTable (empty) */ /* max_stack: 2 max_locals: 4 */ }

上面在位元組碼的檔案結構中講過,每個方法中存在很多屬性,例如LineNumberTable,LocalVariableTable 等等。裡面的一些”_index”就是指向常量池中的索引。對於成員方法來說(非類方法),區域性變量表中的第一個是this(之前有講過)。
這裡抽出最關鍵的Code進行講述:
由上面的LocalVariableTable可以知道,a變數的index是1,b是2,c是3。

public int foo() {
        /* L6 */
        0 iconst_1;
        1 istore_1;               /* a */
        /* L7 */
        2 iconst_2;
        3 istore_2;               /* b */
        /* L8 */
        4 iload_1;                /* a */
        5 iload_2;                /* b */
        6 iadd;
        7 istore_3;               /* c */
        /* L9 */
        8 iload_3;                /* c */
        9 ireturn;
}

1. int a = 1;
首先程式計數器值為0,iconst_1指令將整數1壓入運算元棧中;執行istore_1,程式計數器為1,將運算元棧中的數彈出,然後賦值給索引為1的變數(即a)。
這裡寫圖片描述

2. int b = 2;
跟 int a = 1; 基本一致。
這裡寫圖片描述

3. int c = a + b;
這裡iload指令(i表示int型,後面會列出常用的指令表)將下標為1和2,即a和b壓入棧中。然後執行 idd 指令,彈出兩個運算元進行相加,並將結果值壓入運算元棧中。最後istore_3指令將棧中的運算元彈出並賦值給變數c。
這裡寫圖片描述

這裡寫圖片描述

4. return c;
這裡先將c的值載入壓入到棧中,然後執行ireturn指令。
這裡寫圖片描述
這裡有一個很經典的面試題,就是try中的return和finally中的return,兩個return的執行流程。其實看一下反彙編的指令就一目瞭然了。

3. JVM指令集

1. aconst_null
null物件入棧,前面的a表示物件ref。
2. iconst_m1
將 -1 壓入棧中。其他的byte型和short型參照 bipush 和 sipush 指令
3. iconst_0 ~ iconst_5
將整數 0 ~ 5 壓入棧中。其他的byte型和short型參照 bipush 和 sipush 指令
4. lconst_1 ~ lconst_2
將long型別常量 1或2 壓入棧中,其他參照 ldc2_w 指令;
5. fconst_1 ~ fconst_2
將float型別常量 1或2 壓入棧中,其他參照 ldc 指令。
6. dconst_1 ~ dconst_1
將double型別常量 1或2 壓入棧中,其他參照 ldc2_w 指令。
7. bipush 和 sipush
bipush將一個byte的帶符號常量壓入棧中,sipush將一個short型帶符號常量壓入棧中
8. ldc,ldc_w和ldc2_w
ldc 將int、float或String型常量值從常量池中壓入棧中。
ldc_w將int、float或String型常量值從常量池中壓入棧中(寬索引)。
ldc2_w將long或double型常量值從常量池中壓入到棧中(寬索引)。

3.2 區域性變數操作

1. load(為i,l,f,d和a中一個)
分別將int型,long型,float型,double型以及Object ref型的區域性變數壓入棧中。指令後面繼續跟著”0,_1,_2,_3”表示將索引為0 ~ 3的區域性變數壓入到棧中,大於3的索引則去掉下劃線”“,如”iload_1”,”iload 4”。

2. aload(為c,b,s,i,l,f,d和a中一個)
將指定型別陣列中的值壓入到棧中。取值的時候先將陣列的ref壓入棧,然後是需要獲取資料的index,然後執行*aload指令,並將獲取到的值壓入到棧中。這裡可能會丟擲陣列下標越界的異常。

3. *store 和 *astore 指令
這裡基本和 *load 和 *aload指令類似。

3.3 通用棧操作

1. nop
什麼都不做。

2. pop
從棧頂彈出一個字長。

3. dup
賦值棧頂一個字長,複製內容壓入棧中。

3.4 型別轉化

i2c、i2b、i2s、i2l,i2f,l2i,l2f,l2d,f2i,f2d,d2i,d2l,d2f。

3.5 整數運算和浮點運算

iadd,ladd,fadd,dadd  加 +
isub,lsub,fsub,dsub   減 -
imul,lmul,fmul,dmul  乘 *
idiv, ldiv,fdiv,ddiv   除 /
irem,lrem,frem,drem  取模 %
ineg,lneg,fneg,dneg   取負 -
ishl,lshl          左移 <<
ishr,lshr,iushr,lushr   有符號和無符號右移 >>和>>>
iand,land         按位與 &
ior,lor           按位或 |
ixor,lxor          按位異或 ^
iinc          指定int型變數增加指定的值
 

3.6 物件操作指令和方法呼叫指令

1. new
建立一個物件,並將引用壓入棧中。
2. invokespecial 和 invokevirtual
呼叫構造方法,私有方法
3. invokestatic 和 invokeinterface
呼叫靜態方法和介面方法
4. getstatic 和 putstatic
getstatic 獲取指定類的靜態域並將值壓入棧中;putstatic為指定靜態域賦值。
5. getfield 和 putfield
同上,只是針對例項域
6. return (為 i l f d a 或(為空return即void))

3.7 條件控制

ifeq,ifne,if_icmpeq 等等一些指令。詳細見指令表。

相關推薦

JVM學習05-位元組執行過程JVM指令

1. 位元組碼的Code部分 在執行位元組碼的時候,無非也就是對呼叫類中的函式。那麼下面將介紹下位元組碼函式的Code部分,Code部分的程式碼一個可以用java自帶的命令javap命令進行檢視。還可以在eclipse中安裝ByteCode visualize

虛擬機器位元組執行過程

虛擬機器位元組碼執行引擎:概述,執行引擎:是jvm最核心的部分之一。和物理機相對應。物理機是指直接建立在處理器,硬體,指令集,作業系統層面。虛擬機器是自己實現的,自己制定結構體系。 執行過程: 1. 輸入位元組碼檔案 2. 處理位元組碼 3. 輸出

JVM字節執行引擎動態綁定原理

找不到 順序 入棧 兩種 運行時 mage 過程 狀態 對象 1.執行引擎 所有Java虛擬機的執行引擎都是一致的: 輸入的是字節碼文件,處理過程就是解析過程,最後輸出執行結果。 在整個過程不同的數據在不同的結構中進行處理。 2.棧幀 jvm進行方法調用和方法執行的數

JVM總括三-位元組位元組指令、JIT編譯執行

JVM總括三-位元組碼、位元組碼指令、JIT編譯執行     java檔案編譯後的class檔案,java跨平臺的中間層,JVM通過對位元組碼的解釋執行(執行模式,還有JIT編譯執行,下面講解),遮蔽對作業系統的依賴。一個位元組(8位)可以儲存256中不同的指令,這樣的指令就是位元組碼,ja

jvm位元組解析i++++

i++和++i是編碼中比較常用的程式碼,並且也是初學者容易混淆的。我們知道i++是先賦值再+自己,而++i是先+自己再賦值。為什麼是這樣呢?他們之間效率對比又是怎麼樣呢?本文我們從位元組碼層面來分析。 前面的文章介紹過了jvm位元組碼的基本知識還有如何分析位元組碼,我們現在還是寫個小demo

深入理解JVM虛擬機器讀書筆記【第八章】虛擬機器位元組執行引擎

8.1 概述 8.2 執行時棧幀結構 8.2.1 區域性變量表 8.2.2 運算元棧 8.2.3 動態連線 8.2.4 方法返回地址

JVM位元組執行引擎

一、概述   在不同的虛擬機器實現裡面,執行引擎在執行Java程式碼的時候可能會有解釋執行(通過直譯器執行)和編譯器執行(通過即時編譯器產生原生代碼執行)兩種選擇,所有的Java虛擬機器的執行引擎都是一致的:輸入的是位元組碼檔案,處理過程是位元組碼解析的等效過程,輸出的是執行結果。   每個位元組碼指令都

位元組執行方式--解釋執行JIT

此文已由作者趙計剛薪授權網易雲社群釋出。 歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。 1、兩種執行方式: 解釋執行(執行期解釋位元組碼並執行) 強制使用該模式:-Xint 編譯為機器碼執行(將位元組碼編譯為機器碼並執行,這個編譯過程發生在執行期,稱

深入理解JVM(八)——位元組執行引擎

不用虛擬機器,執行引擎在執行Java程式碼時,會有解釋執行(通過直譯器執行)和編譯執行(通過及時編譯器產生原生代碼執行)兩種選擇。 執行時棧幀結構 棧幀用於支援虛擬機器進行方法呼叫和方法執行的資料結構。棧幀儲存了方法的區域性變量表,運算元棧,動態連線和方法返回地址等資訊。每一個方法從

深入理解JVM虛擬機器(七):虛擬機器位元組執行引擎

程式碼編譯的結果就是從本地機器碼轉變為位元組碼。我們都知道,編譯器將Java原始碼轉換成位元組碼?那麼位元組碼是如何被執行的呢?這就涉及到了JVM位元組碼執行引擎,執行引擎負責具體的程式碼呼叫及執行過程。就目前而言,所有的執行引擎的基本一致: 輸入:位元組碼檔案

JVM十一:虛擬機器位元組執行引擎(2)

解析      繼續前面關於方法呼叫的話題,所有方法呼叫中的目標方法在 Class 檔案裡面都是一個常量池中的符號引用,在類載入的解析階段,會將其中的一部分符號引用轉化為直接引用,這種解析能成立的前提是:方法在程式真正執行之前就有一個可確定的呼叫版本,並且

JVM十一:虛擬機器位元組執行引擎(1)

         執行引擎是Java最核心的組成部分之一。虛擬機器與物理機的區別:虛擬機器是一個相對“物理機”的概念,這兩種機器都有程式碼執行能力,其區別就是物理機的執行引擎是直接建立在處理器,硬體,指令集和作業系統層面

虛擬機器位元組執行引擎 JVM筆記4

目錄   概述 執行時棧幀結構 區域性變量表 運算元棧 方法返回地址 附加資訊 方法呼叫 解析 分派 靜態分派 動態分派 單分派與多分派 虛擬機器動態分派的實現 基於棧的位元組碼解釋執行引擎 概述 輸入的是位元組

[深入理解JVM 六]---虛擬機器位元組執行系統

前邊介紹了jvm的執行時記憶體分配,類檔案的結構,以及類載入機制,這樣,一個編譯好的class二進位制位元組碼檔案就已經被載入完畢,等待下一步的執行。接下來分幾個部分來介紹這部分內容。首先方法的呼叫和執行依賴於虛擬機器棧,第一部分詳細介紹一下虛擬機器棧的棧幀結構

【深入Java虛擬機器】之七:深入JVM位元組執行引擎

我們都知道,在當前的Java中(1.0)之後,編譯器講原始碼轉成位元組碼,那麼位元組碼如何被執行的呢?這就涉及到了JVM的位元組碼執行引擎,執行引擎負責具體的程式碼呼叫及執行過程。就目前而言,所有的執行引擎的基本一致: 輸入:位元組碼檔案 處理:位元組碼解析 輸出:執

JVM系列之七:位元組執行

Javap– class檔案反彙編工具– javap –verbose Calcjava 檔案public class Calc {public int calc() {int a = 500;int b = 200;int c = 50;return (a + b) / c

深入理解JVM總結——虛擬機器位元組執行引擎

執行引擎是Java虛擬機器最核心的組成部分之一。物理機和虛擬機器都有執行程式碼的能力。區別在於物理機的執行引擎是直接建立在處理器、硬體、指令集和作業系統層面上的,而虛擬機器的執行引擎則是由自己實現的,因此可以自行指定指令集與執行引擎的結構體系,並且能夠執行那些不

Java虛擬機器學習筆記(位元組執行引擎)

執行時棧幀結構 1.區域性變量表 null JIT編譯器優化 2.運算元棧 LIFO 3.動態連結 | 4.方法返回地址 | 棧幀資訊 5.附加資訊 | —————————————————————————————————— 方法呼叫 1.解析呼叫 符號引用 靜態、私有

JAVA虛擬機器(JVM)——虛擬機器位元組執行引擎(二)

方法呼叫 方法呼叫並不等同於方法執行,方法呼叫階段唯一的任務就是確定呼叫哪一個方法,暫時還不涉及方法內部的具體執行過程。Class檔案的編譯過程中不包含傳統編譯中的連線步驟,一切方法呼叫在C

JVM 位元組執行例項分析

最近在看《Java 虛擬機器規範》和《深入理解JVM虛擬機器》,對於位元組碼的執行有了進一步的瞭解。位元組碼就像是組合語言,是 JVM 的指令集。下面我們先對 JVM 執行引擎做一下簡單介紹,然後根據例項分析 JVM 位元組碼的執行過程。 執行時棧幀結構 棧幀是用於支