2011-03-15 60 views

回答

3

如果你在談論invokeinterfaceinvokespecialinvokestaticinvokevirtual,有它們之間的差異。開始時對堆棧的影響。

+0

大家都知道,在運行時會出現不同的結構。我的觀察是,運行時可以使用目標方法的簽名和元數據,並從中做正確的事情。如果有的話,對目標類型進行編碼是多餘的,因爲這些信息可以從實際來源中收集。在檢查目標之後,invokeinterface代碼路徑將用於接口,爲方法接口調用virtual等等。 – 2011-03-16 02:10:32

+0

@mP:「搞清楚」該怎麼做,在我看來,主要是編譯時的活動。除非有很好的理由(例如,平臺獨立性),否則我們不希望讓編譯器可以做的工作減慢解釋器的速度。 – 2011-03-16 05:40:12

+0

但驗證者還檢查方法調用是否匹配目標的方法類型 - 就像它驗證可見性一樣,它也檢查方法<->調用指令匹配......如果需要,請嘗試。 javac用來解析,驗證和發送字節碼的所有元數據在運行時也存在。運行時知道所有在類文件中編碼的方法類型,可見性,類型等。 – 2011-03-16 13:42:25

0

這將是可能的。但是,每解釋一條指令都會增加額外成本。所以性能會受到很小的損失。

有人爭辯說,單獨的指令通過減少混淆虛擬機的可能性來提高安全性。我不確定我是否確信這一點。

+0

虛擬機永遠不會感到困惑,因爲如果代碼在目標現在是接口(需要調用接口)時調用虛擬代碼,它總是會驗證並投訴。當然,如果您更新第三方jar並且目標從接口<->類別等發生更改等,則這當然會發生。 – 2011-03-16 02:04:03

+0

@mP參數說明:組合指令會增加漏洞的風險。 – 2011-03-16 08:59:34

+0

什麼漏洞?加載類時的運行時知道它確實檢查指令是否與目標匹配。如果方法調用ins對於目標是錯誤的,你會得到一個驗證加載錯誤 – 2011-03-16 13:43:26

0

你需要這個操作碼,因爲當時方法的字節碼引用被佈置,它們只包含對常量池中條目的符號引用。要解決這些引用,您需要知道需要解決哪種類型:例如,invokespecial和invokevirtual之間的區別是靜態與動態綁定。對於invokespecial,你決定引用的類型,而不是對象的類。如果沒有編譯器放入特殊的操作碼來區分這些方法,則無法收集這些信息。在java中,代碼通常是動態鏈接的,這是強制這些操作碼的原因。

0

至少invokespecial是需要的是一個單獨的指令,因爲Java允許顯式調用超級實現的覆蓋方法:

class Super { 
    public void m() { } 
} 
class Sub { 
    public void m() { 
     super.m(); 
    } 
} 

Sub呼叫已經是一個invokespecial,因爲它本來只需要調用本身並用完堆棧。

2

我們假設您只爲虛擬和靜態調用操作碼。讓我們在編譯時假設你有

Test { 
     public static void test(Test t) { 
     // static method 
    } 
} 

和地方這種靜態調用使用僞字節碼

push t 
jmp Test.test(T)V 

現在讓我們假設一個人在用另一種測試類運行

Test { 
    public void test(Test t) { 
     // obj call 
    } 
} 

在這案例jmp Test.test(T)V仍然有效。問題是它會弄亂堆棧。兩個不同的操作碼可以解決這個問題的鏈接時間。

+0

有更好的格式化代碼的方法,請在問題或答案文本框中單擊[橙色問號](http://i.imgur.com/GjKAG.png)以獲取解釋。謝謝! – Trufa 2011-06-14 16:38:20

+0

類驗證程序檢查您是否有錯誤的調用代碼。運行時每次調用方法時都不會檢查目標是否與原始調用類型兼容。想象一下,如果它做的事情會不可逾越的慢,也是不必要的。在班級加載時進行檢查,並且由於沒有切實可行的方法來重新定義方法,因爲您知道目標與呼叫站點兼容,所以您的代碼無法執行黑客內存。 – 2011-06-15 05:23:14

0

我覺得這個辯論是不必要的,因爲java有這個設計決定。不確定,但您可能想再看一看他們稱之爲用戶定義的數據端點:invokedynamic

相關問題