JVM-字節碼指令

Java虛擬機字節碼指令

  瞭解了class文件,我以爲就頗有必要去了解一下JVM中的字節碼指令,那樣堆class文件以及JVM運行機制也後很大的幫助. 數組

  Java虛擬機的指令由一個字節長度的,表明着某種特定操做含義的數字(稱爲操做碼,Opcode)以及跟隨其後的零至多個表明所需參數(稱爲操做數,Oprands)而構成.因爲Java虛擬機採用面向操做數棧而不是寄存器的架構,因此大多參數的指令都不包含操做數,只有一個操做碼.安全

字節碼指令的一些特性

  因爲限制了Java虛擬機操做碼的長度爲一個字節(0~255),這意味着指令集的操做碼總數不可能超過256條.架構

  因爲class文件格式放棄了編譯後的操做數長度對齊,這意味着虛擬機處理那些超過一個字節數據的時候,不得不在運行時從字節中重建出具體數據的結構.若是要將一個16位長度的無符號整數,使用兩個無符號字節存儲起來(將它們命名爲byte1和byte2),那它們的值應該是這樣的:(byte<<8)| byte2 .這種操做在某種程度上會致使解釋執行字節碼的時候會損失一些性能.但這樣作的優點也是很是明顯的,放棄了操做數長度對齊,就意味着能夠省略不少填充和間隔符號:用一個字節來表示操做碼,也是爲了儘量得到短小精幹的編譯代碼.ide

 字節碼指令與數據類型

  對於大部分與數據類型相關的字節碼指令它們的操做碼助記符中都有特殊特的字符來代表專門爲哪一種數據類型服務:i:表明int,l表明long,s表明short,b表明byte,c表明char,f表明float,d表明double,a表明reference.性能

  Java虛擬機的指令集對於特定的操做只提供了有限的類型相關指令去支持它,換句話說,指令集將會故意被設計成非徹底獨立的Java虛擬機規範中把這種特性稱爲"Not Orthpogoal".即並不是每種操做都有對應的指令.有一些單獨的指令能夠在必要的時候來將一些不支持的類型轉換成爲可被支持的類型.spa

 加載和存儲指令

  加載和存儲指令用於將數據在棧幀中的局部變量和操做數之間來回傳輸.設計

  將一個局部變量加載到操做棧:ilaod , ioload<n>,llaod , llaod<n>,float,float<n>,double,double<n>,aload,aload<n>.code

  將一個數據從操做數棧存儲到局部變量表:istore,istore<n>,lstore,lstore<n>,fstore.fstore<n>,dstore,dstore<n>,astore,asotre<n>.對象

  將一個常量加載到數據棧:bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_ml,iconst_<i>,lconst_<l>,fconst_<f>,dconst_<d>索引

  擴充局部變量表訪問索引的指令:wide

 運算指令

  運算或算術指令用於對兩個操做數棧上的值進行某種特定運算,並把結果從新存入到操做棧頂.

  大致上算術指令能夠分爲兩種:對整型數據進行運算的指令對浮點數據進行運算的指令.不管是哪一種算術指令,都使用Java虛擬機的數據類型,因爲沒有直接支持byte,short,char和boolean類型的算術指令,對於這類數據的運算應使用操做int類型的指令代替.

  加法指令:iadd,ladd,fadd,dadd

  減法指令:isub,lsub,fsub,dsub

  乘法指令:imul,lmul,fmul,dmul

  求餘指令:irem,lrem,frem,drem

  求反指令:ineg,lneg,fneg,dneg

  移位指令:ishl.ishr,lshl,lshr,lushr

  按位或指令:ior,lor

  按位與指令:iand,land]

  按位異或指令:ixor,lxor

  局部變量自增指令:iinc

  比較指令:dcmpy,dcmpl,fcmpg,fsmpyl,lcomp

  Java虛擬機要求在進行浮點數運算時,全部的運算結果都必須舍入到適當的精度,非精確的結果必須舍入爲可被表示的最接近的精確值.若是有兩種可表示的形式與該值同樣接近,將優先選擇最低有效位爲零的,稱爲向最近數舍入模式.

  在把浮點數轉換爲整數時,Java虛擬機使用IEEE754規範中的向零舍入模式,這中模式的舍入結果會致使數字被截斷,全部小數部分的有效字節都會被丟棄掉.向零舍入模式將在目標數值類型與該數值類型中選擇一個最接近可是不大於原數值的數字來做爲最精確的舍入結果.

  Java虛擬機在處理浮點數運算時,不會拋出任何運行時異常,當一個操做產生溢出時,將會使用有符號的無窮大來表示,若是某個操做結果沒有明確的數學定義的話,將會使用NaN值來表示,全部使用NaN值做爲操做數的算術運算,結果都會返回NaN.

  在對long類型數值進行比較時,虛擬機採用帶符號的比較方式,而對浮點數值,進行比較時(dcmpy,dcmpl,fcmpg,fcmpl),虛擬機會採用IEEE754規範所定義的無信號比較(Nonsignaling Conparions)方式.  

 

類型轉換指令

  類型轉換指令能夠將兩種不一樣的數值類型進行相互轉換

  Java直接支持(即轉換時無需顯示進行轉換指令)如下數值類型的寬化類型轉化(即範圍類型向大範圍類型的安全轉化):

  1. int  -->long , float , double
  2. long -->float , double
  3. float -->double

  處理窄化類型轉換時,必須顯示的使用轉換指令來完成,這些轉換指令包括:i2b , i2c , i2s , l2i , f2c , d2i , d2l , d2f.窄化類型轉換可能會致使轉換結果產生不一樣的正負號,不一樣的數量級的狀況,轉換可能會致使數值精度丟失.

  將一個浮點型數值窄化爲整型類型(int 或long)的時候,將遵循一下轉換規則

  • 若是浮點值是NaN,那轉換結果就是int或long類型的0.
  • 若是浮點值不是無窮大的話,浮點值使用向零舍入模式取整,得到整數v.若是v在目標類型的表示範圍以內,轉換結果就是v.
  • 不然,將根據v的符號,轉換爲一個T所能表示的最大會最小正數.

對象建立與訪問指令

  指令:

  • 建立類實例的指令:new
  • 建立數組獲得指令:newarray , anewarray , multianewarray
  • 訪問類字段(static 字段,或者稱爲類變量)和實例字段(非static 字段,或者稱爲實例變量)的指令:getfield , putfield , getstatic , putstatic\
  • 把一個數組元素加載到操做數棧的指令:baload , caload , saload , iaload , laload , faload , daload , aaload
  • 將一個操做數棧的值存儲到數組元素中的指令:bastore , castore , sastore , iastore , fastore , dastore , aastore
  • 取數組長度的指令:arraylength
  • 檢查類實例類型的指令:instanceof , checkcast

 操做數棧管理指令

  Java虛擬機提供了一些直接操做操做數的指令:

  • 操做數棧的棧頂一個或兩個元素出棧:pop , po2
  • 複製棧頂一個或兩個元素並將複製值或雙份值從新壓入棧頂:dup ,dup2,duo_x1,dup_x2,dup2_x2
  • 將棧最頂端的兩個數值交換:swap

 控制轉移指令

  控制轉移指令可讓Java虛擬機有條件的從指定的位置而不是控制轉移指令的下一條指令繼續執行程序。能夠認爲控制轉移指令就是在有條件或無條件的修改PC寄存器的值。

  控制轉移指令:

  • 條件分支:ifeq,iflt,ifne,ifge,ifgt,ifnull,ifnonnull,if_icmpeq,if_icmpne,if_icmplt,if_cmpgt,if_icmpge,if_cmpge,if_icmpeq,if_acmpne
  • 複合條件分支:tableswitch,lookupswitch
  • 無條件分支:goto,goto_w,jsr,jsr_w,ret

 方法調用和返回指令

  invokevirtual指令用於調用對象德邦實例方法,根據對象的實體的類型進行分派(虛方法分派),也就是Java語言中最多見的方法分派方式。

  invokeinterface指令用於調用接口方法,它會在運行時搜索一個實現了這個接口方法的對象找出適合的方法進行調用。

  invokespecial指令用於調用一些須要特殊處理的實例方法,包括實例初始化方法,私有方法和父類方法

  involvestatic指令用於調用類的方法(static方法)

  invokedynamic指令用於在運行時動態解析出調用點限定符所引用的方法,並執行該方法

  前面4條調用指令的分派邏輯都固化在Java虛擬機的內部,而invokedynamic指令的分派邏輯是由用戶設定的引導方法決定的 

 

異常處理指令 

  在Java虛擬機中處理異常catch語句不是由字節碼指令來實現的,而是用異常表來完成的。

  在Java程序中顯式拋出異常的操做(throw語句)都是由athrow來實現的,除了用throw語句顯式拋出異常的狀況以外,Java虛擬機規範還規定了許多運行時異常會在其餘Java虛擬機指令檢測到異常情況時自動拋出。

 同步指令

  Java虛擬機能夠支持方法級的同步和方法內部一段指令序列的同步。這兩種同步結構都是使用管理(Monitor)來支持的。

  方法級的同步是隱含的,既無需經過字節碼指令來控制,也實如今方法調用和返回操做之中。

  同步一段指令序列一般是由Java語言中的synchronize語句塊來表示的,Java虛擬機的指令集中有monitorenter和monitorexit兩條指令來支持synchronize關鍵字的語義,正確實現synchronized關鍵字須要Java編譯器與Java虛擬機二者共同協做支持

相關文章
相關標籤/搜索