本文翻譯自:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html
第二章 虛擬機結構
本文檔描述了一個抽象的虛擬機規范,並不描述某個特定的虛擬機實現。
要正確實現一個Java虛擬機,你只需要能夠讀取class文件的格式並正確執行其中指定的操作。具體的實現並不是java虛擬機規范的一部分,因為它們會限制實現者的創造力。比如,運行時數據區域的內存布局,垃圾回收使用的算法,以及任何的java虛擬機指令的內部優化(如:轉換為機器碼)都留給實現者去決定。
本規范中引用的所有Unicode都遵守Unicode 標准,6.0.0版本,可以從http://www.unicode.org/
.獲取。
2.1 class文件格式
編譯后能夠被java虛擬機執行的代碼使用了一個獨立於硬件和操作系統的二進制格式,通常(不是必須的)存在一個文件中,就是通常所說的class文件格式。class文件格式精確的定義了類和接口的表示,包括一些如字節序(byte ordering)的細節,可能在平台相關的目標文件格式中這被認為是理所當然的。
第四章,class文件格式給出了class文件格式的細節。
2.2 數據類型
類似於java編程語言,java虛擬機操作兩種數據類型:基本類型和引用類型(primitive types and reference types)。相應的,有兩種類型的數據可以用於變量賦值、參數傳遞和方法返回:基本值和引用值(primitive values and reference values)。
java虛擬機期望幾乎所有的類型檢查在運行前完成,通常由編譯器完成,不應該在java虛擬機中完成。基本類型的值不需要特殊標記,或者特殊的方法在運行時確定他們的類型,也不需要將它們和引用類型區分開來。相反,Java虛擬機的指令集對不同的操作數使用不用的操作數指令,從而來區分其操作數類型。例如,iadd,ladd,fadd和dadd這些java虛擬機指令用來求兩個數之和,它們分別指明了操作數的類型是int,long,float和double。更多的java虛擬機指令可參考2.11.1。
Java虛擬機包含對對象的顯式支持。對象是動態分配的類實例或數組。一個對象的引用可以認為是Java虛擬機的引用(reference)類型。引用(reference)的值可以被認為是指向對象的指針。可能存在多個對象的引用。對象始終通過引用(reference)類型的值來進行的值的操作,傳遞和檢查。
2.3 基本數據類型和值
java虛擬機支持的基本類型由數字類型,布爾類型以及returnAddress類型。
數字類型包括整數類型和浮點數類型。
具體的整數類型如下:
- byte,其值為8位有符號二進制補碼整數,其默認值為零
- short,其值為16位有符號二進制補碼整數,其默認值為零
- int,其值為32位有符號二進制補碼整數,其默認值為零
- long,其值為64位有符號二進制補碼整數,其默認值為零
- char,其值為16位無符號整數,表示基本多文本平面(Basic Multilingual Plane)中的Unicode代碼點,使用UTF-16編碼,其默認值為空代碼點('\ u0000')
浮點型數字類型如下:
- fload,值為單精度浮點數集中的元素,或者(如果虛擬機支持的話)是單精度擴展指數(Float-Extended-Exponent)集合中的元素。默認值為正數零。
- double,取值范圍是雙精度浮點數集合中的元素,或者(如果虛擬機支持的話)是雙精度擴展指數(Double-Extended-Exponent)集合中的元素。默認值為正數零。
布爾類型的值取值范圍是true和false,默認值是false(Java®虛擬機規范的第一版沒有將布爾值視為Java虛擬機類型。但是,布爾值在Java虛擬機中的支持有限。Java®虛擬機規范的第二版通過將布爾值視為一種類型來澄清該問題。)
returnAddress類型的值是指向Java虛擬機指令的操作碼(opcodes)的指針。在基本類型中,除了returnAddress類型,其它類型都與Java編程語言類型直接相關聯。
2.3.1 整數類型和值
java虛擬機中的整型的取值范圍如下:
byte, (-27 to 27 - 1),
short, (-215 to 215 - 1),
int, (-231 to 231 - 1)
long,(-263 to 263 - 1)
char,(0 ~ 2^16-1)
2.3.2 浮點類型和值
浮點類型就是指 float 類型和 double 類型,它們在概念上與《IEEE Standard for Binary Floating-Point Arithmetic》(ANSI/IEEE Std. 754-1985, New York)
標准中定義的 32 位單精度和 64 位雙精度 IEEE 754 格式取值和操作都是一致的。
IEEE 754標准不僅包含了正負帶符號數,還包括了正負零,正負無窮大,以及特殊的非數字值(下面簡稱NaN)。NaN表示某些無效操作的結果,比如0/0。
每一個java虛擬機實現都必須支持兩種標准的浮點數集:單精度浮點數集合和雙精度浮點數集合。另外,java虛擬機實現也可以選擇性的支持一種或者兩種擴展指數集合:單精度擴展指數集合和雙精度擴展指數集合(float-extended-exponent value set and the double-extended-exponent value set. )。在某些情況下,可以使用這些擴展指數值集代替標准值集來表示float或double類型的值。
任何有限非零浮點數可以表示為 s ⋅ m ⋅ 2(e − N + 1),其中s為+1或者-1,m為小於2N的正整數,e為一個介於Emin, −(2K−1−2)和 Emax, 2K−1−1之間的一個整數,N和K的取值范圍取決於當前的浮點數值集合。部分浮點數使用這種規則得到的表示形式可能不是唯一的,例如在指定的數值集合內,可以存在一個數字 v,它能找到特定的 s、m 和 e 值來表示,使得其中 m 是偶數,並且 e 小於 2K-1,這樣我們就能夠通過把 m 的值減半再將 e 的值增加 1 來的方式得到 v 的另外一種不同的表示形式。在這些表示形式中,如果其中某種表示形式中 m 的值滿足條件 m ≥ 2N-1的話,那就稱這種表示為標准表示(Normalized Representation),不滿足這個條件的其他表示形式就稱為非標准表示(Denormalized Representation)。如果某個數值不存在任何滿足 m ≥ 2N-1的表示形式,即不存在任何標准表示,那就稱這個數字為非標准值(Denormalized Value)
在兩種必須支持的浮點數集和兩種可選的浮點數集中,N和K(也包括Emin 和 Emax)的取值范圍如下:
參數 | float | 單精度擴展指數集合 | double | 雙精度擴展指數集合 |
---|---|---|---|---|
N | 24 | 24 | 53 | 53 |
K | 8 | ≥ 11 | 11 | ≥ 15 |
Emax | +127 | ≥ +1023 | +1023 | ≥ +16383 |
Emin | -126 | ≤ -1022 | -1022 | ≤ -16382 |
當虛擬機實現一個或者都實現的擴展指數集,這里有一個和實現無關的限制參數K,見上表中的具體限制。參數K同時決定了Emin和Emax的范圍。
注意上表中的限制是經過設計的,從而保證每一個單精度浮點數必然是一個單精度擴展指數、雙精度浮點數和雙精度擴展指數。同樣的,每一個雙精度浮點數必然是雙精度擴展指數。所以每一個擴展的指數集比對應的標准集具有更大的范圍,但是會損失精度。
單精度浮點數集中的元素可以精確的表示為IEEE 754標准中的單精度浮點格式,除了NaN(IEEE 754中描述了224-2中不同的NaN值)。雙精度浮點數集中的元素可以精確的表示為IEEE 754標准中的雙精度浮點格式,除了NaN(IEEE 754中描述了253-2中不同的NaN值)。注意,這里定義的單精度擴展指數和雙精度擴展指數和IEEE 754中對應的單精度擴展和雙精度擴展並不對應。不過除了 Class 文件格式中必要的浮點數表示描述以外,本規范並不特別要求表示浮點數值表示形式。
上面提到的單精度浮點數集合、單精度擴展指數集合、雙精度浮點數集合和雙精度擴展指數集合都並不是具體的數據類型。虛擬機實現使用一個單精度浮點數集合的元素來表示一個 float 類型的數值在所有場景中都是可行的,但是在某些特定的上下文環境中,也允許虛擬機實現使用單精度擴展指數集合的元素來代替。類似的,虛擬機實現使用一個雙精度浮點數集合的元素來表示一個double 類型的數值在所有場景中都是可行的,但是在某些特定的上下文環境中,也允許虛擬機實
現使用雙精度擴展指數集合的元素來代替。
除了 NaN 以外,浮點數集合中的所有元素都是有序的。如果把它們從小到大按順序排列好,那順序將會是:負無窮,可數負數、正負零、可數正數、正無窮。
浮點數中,正數零和負數零是相等的,但是它們有一些操作會有區別。例如 1.0 除以 0.0 會產生正無窮大的結果,而 1.0 除以-0.0 則會產生負無窮大的結果。
NaN 是無序的,對它進行任何的數值比較和等值測試都會返回 false 的比較結果。值得一提的是,有且只有 NaN 一個數與自身比較是否數值上相等時會得到 false 的比較結果,任何數字與NaN 進行非等值比較都會返回 true。
2.3.3 returnAddress 類型和值
returnAddress類型被java虛擬機使用在jsr,ret和jsr_w指令中。returnAddress的值是java虛擬機指令操作碼的指針。和基本的數字類型不同,returnAddress在java編程語言中沒有對應的類型,同時在運行的程序中無法被修改。
2.3.4 布爾類型
盡管java虛擬機定義了boolean類型,但是僅僅提供了非常有限的支持。java虛擬機沒有單獨專門的指令來操作布爾值。相反,java編程語言中的表達式涉及到boolean類型的值會被編譯為java虛擬機中的int類型。
java虛擬機直接支持布爾數組。java虛擬機中的newarray指令允許創建boolean類型的數組。boolean類型數組的元素通過byte數組指令baload和bastore來訪問和修改。
java虛擬機將boolean數組元素編碼成1和0分別表示true和false。java編程語言中boolean值會被編譯器映射為java虛擬機中類型int,編譯器必須使用相同的編碼方式。
2.4 引用類型和值
總共又三種類型的引用類型(reference):類類型(class types),數組類型(array types)以及接口類型(interface types),它們的值分別表示動態創建的類實例,數組和類實例或者數組實現的接口。
數組類型由具有單個維度的組件類型(component type)組成(其長度不是由類型給出的)。數組的組件類型本身也可以是數組類型。但從任意一個數組開始,如果發現其組件類型也是數組類型的話,繼續重復取這個數組的組件類型,這樣操作不斷執行,最終一定可以遇到組件類型不是數組的情況,這時就把這種類型成為數組類型的元素類型(Element Type)。數組的元素類型必須是原始類型、類類型或者接口類型之中的一種。
引用值也可以是特殊的空引用,對無對象的引用,這里將用null表示。null引用本質上沒有任何的運行時類型,但是可以轉變為任意類型。引用類型的默認值時null。
本規范沒有強制將null編程成一個具體的值。