2012-11-05 99 views
0

我開發與ASM的檢測引擎,我需要攔截的方法,其中接收陣列類型的參數調用。爲此,我實施了MethodVisitor,並在其visitMethodInsn中檢查desc參數是否指定了數組類型的任何參數。如果目標方法沒有數組類型的參數,那麼我無關並且插入原始方法調用:super.visitMethodInsn(opcode, owner, name, desc);如何避免的VerifyError:「希望找到堆棧未初始化對象」的對象已經初始化

另一方面,如果目標方法具有數組類型的參數,那麼我必須執行一個針對其論點的具體行動。我獲得訪問每個參數的最簡單的解決方案是調用一箇中介方法,具有與目標方法相同的描述符,並且在此介體中,我可以輕鬆訪問其參數(與傳遞給目標方法的參數相對應)。

然而,當目標方法是一個實例的構造(<init>)出現一個問題。

NEW XXX 
    DUP 
    INVOKESPECIAL XXXX.<init>() 

根據我上面的解釋,我移動INVOKESPECIAL呼叫到調解方法和新創建的對象是該中介的第一個參數的方法:在Java的new XXX()如下被翻譯成字節碼。然而,驗證者爲這個介體產生一個錯誤,報告介體的第一個參數(它將成爲目標方法的第一個參數 - <init>)不是一個「單元化對象」。更確切地說,我得到了錯誤:Exception in thread "main" java.lang.VerifyError: Expecting to find unitialized object on stack」

一旦我用兩種不同的方法分割字節碼NEWINVOKESPECIAL,驗證者聲稱傳遞給INVOKESPECIAL的參數已經被初始化。

任何建議來解決這個問題呢? (請不要回答我避免介體並直接訪問堆棧中的參數,因爲複製並替換佔用堆棧中任意位置的參數並非易事)。

+0

「mediator」方法是什麼意思? – vijay

+0

想象一下,在某些時候,我的工具引擎正在攔截目標方法的調用:'obj.foo(x)'。因此,在這一點上,我將這個調用替換爲:'obj.foo(x)',by:'mediator $ foo(obj,x)' - 在這種情況下,調解器$ foo是調用方類中的一個新的靜態方法。因此,'mediator $ foo(obj,x)'完成它需要的東西,然後調用目標:'obj.foo(x)'。 –

+0

是靜態還是實例方法的中介方法? – vijay

回答

1

驗證器拒絕您的代碼(請參閱JVM規範)。沒有辦法繞過字節碼驗證器。

一種方式是圍繞在構造函數調用點內聯中介代碼。在調用構造函數之前或之後,您仍然可以調用調解器的某些部分作爲方法調用,但構造函數的調用必須與新指令的方法相同。

另一種方式是讓每一個類的實例存在特殊介質,所以調解員調用new指令自己,用構造函數調用一起。

你也可以看看現有的AOP庫,如果他們能正確地做必要的工作。