2011-10-05 57 views
1

我試圖檢索實現Java接口的類的名稱,然後使用此名稱作爲數據結構中的鍵來檢索有關該類的一些代碼度量標準。這是我所做的:重新加載ASM中的局部變量

public void visitMethodInsn(int opcode, String owner, String name, String desc) { 

    int methodOwner = _lvs.newLocal(Type.getType("Ljava/lang/String;")); 

    if (opcode == Opcodes.INVOKEINTERFACE) { 

     // some code to pop the operand stack and 
     // get to the object whose method is being called 

     // retrieving the name of the class 
     int callingObj = _lvs.newLocal(Type.getType(Object.class)); 
     this.visitVarInsn(Opcodes.ASTORE, callingObj); 
     this.visitVarInsn(Opcodes.ALOAD, callingObj); 
     this.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;"); 
     this.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;"); 
     this.visitVarInsn(Opcodes.ASTORE, methodOwner);   
     this.visitVarInsn(Opcodes.ALOAD, callingObj); 

     /// (1) 
     /// some code using the methodOwner .... 
     /// something like the following 
     /// this.visitVarInsn(Opcodes.ALOAD, methodOwner); 

     /// code to reconstruct the operand stack 
     /// for the method to be invoked 
    } 

    super.visitMethodInsn(opcode, owner, name, desc); 

    if (opcode == Opcodes.INVOKEINTERFACE) { 
     /// (2) 
     /// some more code using the methodOwner ..... 
     /// 
     /// this.visitVarInsn(Opcodes.ALOAD, methodOwner); 
    } 
} 

如果我從上面的代碼註釋塊(2)中的代碼片段,它的工作原理。但是,當我嘗試訪問塊(2)中的「methodOwner」時,我收到以下驗證錯誤,指出字符串對象不見了。我不明白爲什麼。

org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 813: Expected an object reference, but found . 

由於主叫「super.visitMethodInsn(操作碼,所有者,名稱,內容描述);」彈出調用接口方法的對象,我無法再次獲取對它的引用。我試着在另一個變量中保留對象的第二個副本,但同樣的問題發生。

我想知道你是否對這裏有什麼問題有任何線索,如果你能給我一些建議。

非常感謝您的幫助

+0

我應該在這裏添加的一件事是,在方法(1)中的代碼執行時沒有任何問題,將變量添加到方法中首先工作。它只是在調用** super.visitMethodInsn **之後才能訪問新添加的變量。 – nemo

回答

0

訪問者實現應該延長LocalVariableSorter類,你應該叫super.visitXXX的本身,而不是混淆實例LVS,這之間的訪問調用。

問題是,你在一個訪問者上調用newLocalVar,然後在另一個訪問者中使用這個變量位置,這個位置對這個變量不知道。如果此類已經擴展LocalVariableSorter,那麼您應該用this.xxx()或其他方式替換lvs.xxx()cals,但不應該有兩個訪問者交錯。

+0

感謝尤金的回覆。我的訪問者已經在擴展MethodAdapter,所以我通過委託使用LocalVariableSorter,並且我已經將LVS鏈接到正在分析其方法的類的適配器。它更像是如何在ASM手冊的第64頁和第65頁中解釋的。你有什麼建議? – nemo

+0

請參閱上面的說明。 –

2

一個非常非常簡單的建議。儀器代碼爲 時,我通常使用靜態方法在純java中編寫邏輯並調用該方法。

例如

class ZZZ{ 
    public static Object handleIntefaceCall(Object callee){ 
    //process 
    return callee; 
    } 
    } 

如果接口沒有參數,你需要的是調用靜態方法,這是代碼

visitMethodInsn(INVOKESTATIC, "pack/ZZZ", "handleIntefaceCall", "(Ljava/lang/Object;)Ljava/lang/Object;"); 
super.visitMethodInsn(opcode, owner, name, desc); 

單行如果有一個參數(但不長/雙),您必須在通話前後添加交換指令。

+0

感謝您的建議@bestsss。你是對的。我應該做obj.getClass()。getName()並使其更清潔。 – nemo