2013-07-11 22 views
5

我遇到了dalvik dex轉換器和它用於調用方法的操作碼的問題。基本上我有一個在我的類中定義的private final方法,在調用它時,不是生成invoke-direct操作碼,而是生成invoke-super。由於它是一種私有方法,因此該方法在超類中不存在,所以我在設備上遇到VFY違例。我能追查觸發這個確切的情況下,它出現時發生:使用錯誤調用代碼的Dalvik轉換

  1. 插裝班,JaCoCo,並與--target 1.6

編譯

  • 類如果這兩個條件得到的dex類具有invoke-super而不是invoke-direct。如果我禁用JaCoCo或者如果我使用--target 1.5進行編譯,它將使用正確的invoke-direct操作碼。

    在看javap拆卸類代碼,我可以看到是什麼原因導致dx超,而不是直接的假設:

    好工具,編譯爲1.6:

    $ javap -d com.example.ClassName | grep waitForConnectivity 
    159: invokespecial #115; //Method waitForConnectivity:()V 
    $ dexdump -d classes.dex | grep waitForConnectivity 
    147ad8: 7010 6042 0200   |001e: invoke-direct {v2}, Lcom/example/ClassName;.waitForConnectivity:()V // [email protected] 
    

    儀表,編譯1.5(--target 1.5):

    $ javap -d com.example.ClassName | grep waitForConnectivity 
    235: invokespecial #115; //Method waitForConnectivity:()V 
    $ dexdump -d classes.dex | grep waitForConnectivity 
    149d4c: 7010 9242 0400   |0018: invoke-direct {v4}, Lcom/example/ClassName;.waitForConnectivity:()V // [email protected] 
    

    儀表,編爲1.6:

    $ javap -d com.example.ClassName | grep waitForConnectivity 
    235: invokespecial #115; //Method com/example/ClassName.waitForConnectivity:()V 
    $ dexdump -d classes.dex | grep waitForConnectivity 
    149d4c: 6f10 9242 0400   |0018: invoke-super {v4}, Lcom/example/ClassName;.waitForConnectivity:()V // [email protected] 
    

    所以不同的是,編譯後的.class文件已編譯Java字節碼引用完全限定類名的this類(通知//Method waitForConnectivity:()V」與「//Method com/example/ClassName.waitForConnectivity:()V」)。看起來dx自動假定如果方法名稱是完全限定的,它必須使用invoke-super,但如果它不合格,它將使用invoke-direct

    我的問題是:

    1. 這是Android的dx,或JaCoCo錯誤的錯誤嗎?
    2. 我該如何避免這種情況,以便JaCoCo儀器化的類可以在我的自動化測試版本中正常工作?

    我目前的解決方法是擁有一個Maven「jacoco」配置文件,並在那裏覆蓋${java.version}屬性將其從默認的「1.6」更改爲「1.5」。有沒有更好的解決方案?

  • 回答

    2

    一個是dx使用,以確定是否發出invoke-superinvoke-direct是,是否認爲該方法調用被同一類作爲一個做主叫制定的規則。請查看源代碼RopperMachine.java,圍繞線912,包括在這裏以供參考:

     case ByteOps.INVOKESPECIAL: { 
          /* 
          * Determine whether the opcode should be 
          * INVOKE_DIRECT or INVOKE_SUPER. See vmspec-2 section 6 
          * on "invokespecial" as well as section 4.8.2 (7th 
          * bullet point) for the gory details. 
          */ 
          CstMethodRef ref = (CstMethodRef) cst; 
          if (ref.isInstanceInit() || 
           (ref.getDefiningClass() == method.getDefiningClass()) || 
           !method.getAccSuper()) { 
           return RegOps.INVOKE_DIRECT; 
          } 
          return RegOps.INVOKE_SUPER; 
    

    看到天色misconverted類的更完整的轉儲這將是有趣。我想可能是這種情況,你從javap看到的不完全是現實的全貌。請注意,dx本身內置了一個.class文件翻轉器,它提供了比javap更多的細節。將其調用爲dx --dump --bytes path/to/Name.class

    +0

    所以這意味着'ref.getDefiningClass()!= method.getDefiningClass()'。今天我會盡量爲你提供一個更完整的轉儲。但是,使用JaCoCo離線設備和Java 1.6編譯器,問題似乎很容易重現。有趣的是,它並不總是這樣,所以你可能是正確的,還有其他事情正在發生。我只是不知道什麼時候開始。 – Joe

    +0

    我正在授予賞金,因爲您已經滿足賞金要求的可信部分。雖然尚未解決或追蹤到某個原因/原因,但現在看來,罪魁禍首最有可能是JaCoCo的指導員,儘管我覺得'dx'仍然應該能夠識別被調用方法的定義類等於調用者的定義類,從而導致「INVOKE_DIRECT」如預期的那樣。將需要進一步調查建議。也許我們可以在稍後的聊天中繼續這一點,因爲我有時間回到這裏。 – Joe

    +1

    謝謝!正如我所說的,'dx --dump'可能有助於查明差異的確切性質。我不會聲稱'dx'是完美無缺的(儘管驕傲使我想要),但是,JaCoCo幾乎肯定會做一些至少有些懷疑的事情。 – danfuzz

    相關問題