2013-04-14 60 views
10

根據這篇文章http://slurp.doc.ic.ac.uk/pubs/observing/linking.html#assignmentJava字節碼:局部變量的類型?

由於Java代碼和字節 (字節碼不包含類型的局部變量)之間的信息差異,驗證 並不需要檢查亞型的分配來局部變量,或 參數。

我的問題:爲什麼字節碼不包含局部變量的類型信息,而它確實包含參數和返回值的類型信息?

+2

我懷疑在編譯時檢查了類型值,導致代碼不再需要類型值信息,只有二進制數據。然而,方法參數&返回值在'run-time'處被調用,並且需要類型檢查信息 –

+0

謝謝,這很有道理! – JB2

+1

因爲就是這樣。 JDK驗證程序使用數據流分析來確定每個數據使用的「達到」類型。參數和實例/靜態變量需要聲明類型以饋入數據流。計算結果的類型OTOH可以由規則確定。除此之外,編譯時局部變量通常會消失爲堆棧值。 –

回答

5

首先,有幾種不同的類型概念。有編譯時類型,其中包括泛型。但是,編譯時間後,泛型不存在。

有一個變量的驗證推斷靜態類型,可以是int,float,long,double,returnaddress或對象引用。對象引用還有一個上限,因此所有引用都是例如java/lang/String的子類型。字段還可以具有其中一種短字符類型:字節,短字符,字符或布爾值。爲了執行目的,這些處理方式與整體處理方式相同,但存儲空間不同。

最後,存在運行時類型,它與驗證的靜態類型相同,但在對象引用的情況下,表示正在引用的實例的實際類型。請注意,由於驗證者的懶惰,在某些情況下,運行時類型實際上可能不是已驗證類型的子類型。例如,聲明類型爲Comparable的變量實際上可以在Hotspot中保存任何對象,因爲虛擬機在驗證時不會檢查接口。

編譯時間信息不會保留,除非通過反射和調試的可選屬性。這是因爲沒有理由保留它。

局部變量沒有顯式的類型信息(除了新的StackMapTable屬性,但這是一個技術性)。相反,當類加載時,字節碼驗證器通過運行靜態數據流分析來推斷每個值的類型。這樣做的目的不是爲了趕上像編譯時類型檢查這樣的錯誤,因爲它假定字節碼已經在編譯時經過了這種檢查。

相反,驗證的目的是確保指令對VM本身沒有危險。例如,它需要確保您沒有取整數並將其作爲對象引用進行匹配,因爲這可能會導致任意內存訪問和黑客入侵VM。

所以雖然字節碼值沒有明確的類型信息,但它們有一個隱式類型,它是靜態類型推斷的結果。這些細節取決於每個虛擬機的內部實現細節,儘管它們是假定遵循JVM標準。但是你只需要擔心手寫字節碼。

由於VM需要知道存儲哪種類型的數據,因此字段具有明確的類型。方法參數和返回類型在所謂的方法描述符中編碼,也用於類型檢查。他們不可能自動推斷,因爲這些值可以來自或去任何地方,而類型檢查是在每個班的基礎上完成的。

P.S.談到驗證類型時,我忽略了一些細節。對象類型還追蹤它們是否已被初始化,以及在未初始化的情況下由哪個指令創建它們。地址類型跟蹤創建它們的jsr的目標。

+0

值得注意的是,'returnAddress'類型只用於在Java 6中被禁止的'jsr'和'jsr_w'操作碼。由現代字節碼操縱的值不會包含'returnAddress'。 –

+0

@Tom它們不能用於大於49的主要版本的類文件中,但仍可以在現代VM上運行版本號較低的類文件。如果您願意,可以將版本設置爲低於45.0,並且這樣做會在Hotspot中啓用一些有趣的未記錄行爲。如果您只考慮Java編譯的字節碼,那麼javac生成的字節碼將永遠不會執行相當多的事情。但它仍然對字節碼黑客感興趣。 – Antimony

+0

真的!我們必須避免這種錯誤,這有點令人遺憾,因爲它解釋了字節碼如何工作更復雜。 –

2

的Java bytecode保留鍵入有關fields信息, methodreturnsparameters但事實並非如此, 你問, 包含local variables類型信息。

在Java類文件中的 類型的信息呈現的bytecode編譯比 machine code編譯容易的任務 。因此,反編譯Java字節碼需要對大多數局部變量類型進行分析,基於堆棧的平臺化指令和結構化的loopsconditionals。 然而,字節碼反編譯的任務比編譯難得多。你會看到經常反編譯器 不能完全執行其預定功能

3

這是一個非常古老的論文。當前類文件包括本地和堆棧變量的類型。類型不存儲在方法字節碼中,但存儲在方法附帶的StackMapTable attribute中。

通過數據流分析重構所有局部變量和堆棧元素的類型(並且始終如此)是可能的,而不需要StackMapTable,但是這在計算上是昂貴的。使用StackMapTable代碼可以更快地驗證。雖然我不得不承認,我沒有看到如何驗證StackMapTable可以比分析更快,但我對此幾乎一無所知。

+0

我很佩服你的專業知識。對我來說,字節碼就像魔術一樣......同樣也是神祕的。 – scottb

+0

我並沒有真正的專業知識 - 我已經閱讀過規格說明書,但就是這樣。 –

+0

StackMapTables僅爲每個基本塊的開始處的值提供一種類型,因此需要數據流分析來重新構建所有值的類型。特別是,線性代碼甚至可能沒有'StackMapTable'屬性。它只會更快,因爲數據流不再需要在循環或分支的情況下進行多次傳遞。 – Antimony