Java虛擬機指令由一個字節長度的、表明某種特定含義的操做碼(Opcode)以及其後的零個至多個表明此操做參數的操做數構成。虛擬機中許多指令並不包含操做數,只有一個操做碼。若忽略異常,JVM解釋器使用一下爲代碼便可有效工做。數組
複製代碼代碼以下:數據結構
do{
自動計算PC寄存器以及從PC寄存器的位置取出操做碼
if(存在操做數) 取出操做數;
執行操做碼所定義的操做;
}while(處理下一次循環)ide
操做數的數量以及長度,取決於操做碼,若一個操做數長度超過了一個字節,將會以Big-Endian順序存儲(高位在前字節碼),其值應爲(byte1<<8)|byte2。
字節碼指令流是單字節對齊,只有"tableswitch"和"lookupswitch"兩指令例外,它們的操做數比較特殊,以4字節爲界限劃分的,須要預留出相應的空位來實現對齊。
限制Java虛擬機操做碼的長度爲一個字節,且放棄編譯後代碼的參數長度對齊,是爲了得到短小精幹的編譯代碼,即便可能會讓JVM實現付出必定性能成本爲代價。因爲操做碼只能有一個字節長度,故限制了指令集的數量,又沒有假設數據是對齊好的,意味着數據超過一個字節時,不得不從字節中重建出具體的數據結構,會損失一些性能。性能
在JVM中的指令集中,大多數指令包含了其操做對應的數據類型信息。如iload指令從局部變量表中加載int型的數據到操做數棧中,而fload加載的是float類型的數據。
對於大部分與數據類型相關的字節碼指令,他們的操做碼助記符都有特殊的字符來代表:i表明int類型,l表明long,s表明short,b表明 byte,c表明char,f表明float,d表明double,a表明reference。有一些單獨指令能夠在必要的時候用來將一些不不支持的類型轉換爲可被支持的類型。spa
加載和存儲指令用於將數據從棧幀的局部變量表和操做數棧之間來回傳輸。
1)將一個局部變量加載到操做數棧的指令包括:iload,iload_<n>,lload、lload_<n>、float、 fload_<n>、dload、dload_<n>,aload、aload_<n>。
2)將一個數值從操做數棧存儲到局部變量標的指令:istore,istore_<n>,lstore,lstore_<n>,fstore,fstore_<n>,dstore,dstore_<n>,astore,astore_<n>
3)將常量加載到操做數棧的指令:bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_ml,iconst_<i>,lconst_<l>,fconst_<f>,dconst_<d>
4)局部變量表的訪問索引指令:wide
一部分以尖括號結尾的指令表明了一組指令,如iload_<i>,表明了iload_0,iload_1等,這幾組指令都是帶有一個操做數的通用指令。線程
算術指令用於對兩個操做數棧上的值進行某種特定運算,並把結果從新存入到操做棧頂。
1)加法指令:iadd,ladd,fadd,dadd
2)減法指令:isub,lsub,fsub,dsub
3)乘法指令:imul,lmul,fmul,dmul
4)除法指令:idiv,ldiv,fdiv,ddiv
5)求餘指令:irem,lrem,frem,drem
6)取反指令:ineg,leng,fneg,dneg
7)位移指令:ishl,ishr,iushr,lshl,lshr,lushr
8)按位或指令:ior,lor
9)按位與指令:iand,land
10)按位異或指令:ixor,lxor
11)局部變量自增指令:iinc
12)比較指令:dcmpg,dcmpl,fcmpg,fcmpl,lcmpcode
Java虛擬機沒有明確規定整型數據溢出的狀況,但規定了處理整型數據時,只有除法和求餘指令出現除數爲0時會致使虛擬機拋出異常。對象
加載和存儲指令用於將數據從哦你哦過棧幀的局部變量表和操做數棧之間來回傳輸。
1)將一個局部變量加載到操做數棧的指令包括:iload,iload_<n>,lload、lload_<n>、float、 fload_<n>、dload、dload_<n>,aload、aload_<n>。
2)將一個數值從操做數棧存儲到局部變量標的指令:istore,istore_<n>,lstore,lstore_<n>,fstore,fstore_<n>,dstore,dstore_<n>,astore,astore_<n>
3)將常量加載到操做數棧的指令:bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_ml,iconst_<i>,lconst_<l>,fconst_<f>,dconst_<d>
4)局部變量表的訪問索引指令:wide
一部分以尖括號結尾的指令表明了一組指令,如iload_<i>,表明了iload_0,iload_1等,這幾組指令都是帶有一個操做數的通用指令。索引
算術指令用於對兩個操做數棧上的值進行某種特定運算,並把結果從新存入到操做棧頂。
1)加法指令:iadd,ladd,fadd,dadd
2)減法指令:isub,lsub,fsub,dsub
3)乘法指令:imul,lmul,fmul,dmul
4)除法指令:idiv,ldiv,fdiv,ddiv
5)求餘指令:irem,lrem,frem,drem
6)取反指令:ineg,leng,fneg,dneg
7)位移指令:ishl,ishr,iushr,lshl,lshr,lushr
8)按位或指令:ior,lor
9)按位與指令:iand,land
10)按位異或指令:ixor,lxor
11)局部變量自增指令:iinc
12)比較指令:dcmpg,dcmpl,fcmpg,fcmpl,lcmp
Java虛擬機沒有明確規定整型數據溢出的狀況,但規定了處理整型數據時,只有除法和求餘指令出現除數爲0時會致使虛擬機拋出異常。接口
類型轉換指令將兩種Java虛擬機數值類型相互轉換,這些操做通常用於實現用戶代碼的顯式類型轉換操做。
JVM支持寬化類型轉換(小範圍類型向大範圍類型轉換):
1)int類型到long,float,double類型
2)long類型到float,double類型
3)float到double類型
窄花類型轉換指令:i2b,i2c,i2s,l2i,f2i,f2l,d2l和d2f,窄化類型轉換可能會致使轉換結果產生不一樣的正負號,不一樣數量級,轉換過程可能會致使數值丟失精度。如int或long類型轉化整數類型T時,轉換過程是僅僅丟棄最低位N個字節意外的內容(N是類型T的數據類型長度)
雖然類實例和數組都是對象,Java虛擬機對類實例和數組的建立與操做使用了不一樣的字節碼指令。
1)建立實例的指令:new
2)建立數組的指令:newarray,anewarray,multianewarray
3)訪問字段指令:getfield,putfield,getstatic,putstatic
4)把數組元素加載到操做數棧指令:baload,caload,saload,iaload,laload,faload,daload,aaload
5)將操做數棧的數值存儲到數組元素中執行:bastore,castore,castore,sastore,iastore,fastore,dastore,aastore
6)取數組長度指令:arraylength
7)檢查實例類型指令:instanceof,checkcast
直接操做操做數棧的指令:pop,pop2,dup,dup2,dup_x1,dup2_x1,dup_x2,dup2_x2和swap
控制轉移指令
讓JVM有條件或無條件從指定指令而不是控制轉移指令的下一條指令繼續執行程序。控制轉移指令包括:
1)條件分支:ifeq,iflt,ifle,ifne,ifgt,ifge,ifnull,ifnotnull,if_cmpeq,if_icmpne,if_icmlt,if_icmpgt等
2)複合條件分支:tableswitch,lookupswitch
3)無條件分支:goto,goto_w,jsr,jsr_w,ret
JVM中有專門的指令集處理int和reference類型的條件分支比較操做,爲了能夠無明顯標示一個實體值是不是null,有專門的指令檢測null 值。boolean類型和byte類型,char類型和short類型的條件分支比較操做,都使用int類型的比較指令完成,而 long,float,double條件分支比較操做,由相應類型的比較運算指令,運算指令會返回一個整型值到操做數棧中,隨後再執行int類型的條件比較操做完成整個分支跳轉。各類類型的比較都最終會轉化爲int類型的比較操做。
invokevirtual指令:調用對象的實例方法,根據對象的實際類型進行分派(虛擬機分派)。
invokeinterface指令:調用接口方法,在運行時搜索一個實現這個接口方法的對象,找出合適的方法進行調用。
invokespecial:調用須要特殊處理的實例方法,包括實例初始化方法,私有方法和父類方法
invokestatic:調用類方法(static)
方法返回指令是根據返回值的類型區分的,包括ireturn(返回值是boolean,byte,char,short和 int),lreturn,freturn,drturn和areturn,另一個return供void方法,實例初始化方法,類和接口的類初始化i 方法使用。
JVM支持方法級同步和方法內部一段指令序列同步,這兩種都是經過moniter實現的。 方法級的同步是隱式的,無需經過字節碼指令來控制,它實如今方法調用和返回操做中。虛擬機從方法常量池中的方法標結構中的 ACC_SYNCHRONIZED標誌區分是不是同步方法。方法調用時,調用指令會檢查該標誌是否被設置,若設置,執行線程持有moniter,而後執行方法,最後完成方法時釋放moniter。 同步一段指令集序列,一般由synchronized塊標示,JVM指令集中有monitorenter和monitorexit來支持synchronized語義。 結構化鎖定是指方法調用期間每個monitor退出都與前面monitor進入相匹配的情形。JVM經過如下兩條規則來保證結結構化鎖成立(T表明一線程,M表明一個monitor): 1)T在方法執行時持有M的次數必須與T在方法完成時釋放的M次數相等 2)任什麼時候刻都不會出現T釋放M的次數比T持有M的次數多的狀況