2013-07-11 4 views
5

私はdalvik dexコンバータとメソッドを呼び出すために使用しているオペコードに問題があります。基本的には私のクラスでprivate finalメソッドが定義されていて、それを呼び出すときにinvoke-directオペコードを生成する代わりに、dxはinvoke-superを生成しています。プライベートメソッドなので、メソッドはスーパークラスには存在しないため、デバイス上でVFY違反が発生します。私はこれをトリガし、正確なシナリオを追跡することができました、そして、場合に発生することが表示されます。間違ったinvoke-opcodeを使用したDalvik変換

  1. がJaCoCoを持つクラスをインストルメント、および
  2. クラスは--target 1.6

でコンパイルしたものを二つの条件の場合結果のdexクラスがinvoke-directの代わりにinvoke-superになっています。 JaCoCoを無効にした場合、または--target 1.5でコンパイルすると、正しいinvoke-directオペコードが使用されます。

、インストルメントされていないが、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] 

は、コンパイルされ、インストルメントjavap解体クラスのコードを見て

、私はスーパーの代わりに、直接の前提とするdxの原因となるものを見ることができます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ファイルがthisクラスの完全修飾クラス名を参照するJavaバイトコード(通知「//Method waitForConnectivity:()V」対をコンパイルしたことがあります"//Method com/example/ClassName.waitForConnectivity:()V")。 dxは、メソッド名が完全修飾されている場合はinvoke-superを使用する必要があると自動的に判断しているようですが、修飾されていない場合はinvoke-directが使用されます。

私の質問は以下のとおりです。

  1. が、これはAndroidのdx、またはJaCoCoのバグのバグですか?
  2. これを避けると、JaCoCoインストルメントクラスが自動テストビルドで正しく動作するようになりますか?

私の現在の回避策は、Mavenの「jacoco」プロファイルを持っていることであり、そこに私が「1.5」にデフォルトの「1.6」からそれを変更する${java.version}プロパティをオーバーライドします。もっと良い解決策はありますか?

答えて

2

invoke-superまたはinvoke-directを発行するかどうかを判断するために使用する規則の1つは、呼び出しを行っているクラスと同じクラスでメソッド呼び出しが行われていると考えられるかどうかです。ソースの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

賞金を授与しているのは、あなたが賞金要件の信頼できる部分を満たしているからです。それはまだ解決されていないか、または理由/原因に戻って追跡されていませんが、 'dx'が依然として呼び出されたメソッドの定義クラスを認識できる必要があるとは思いますが、JaCoCo instrumenter invokerの定義クラスと等しく、結果として 'INVOKE_DIRECT'が期待通りに発生します。提案されているようにさらに調査する必要があります。おそらく私はこれに戻る時間があるので、後でチャットでこれを続けることができます。 – Joe

+1

ありがとう!私が言ったように、 'dx --dump'は違いの正確な性質を正確に示すのに役立ちます。私は「dx」が完璧ではないと主張するつもりはないが(誇りは私に欲しいと思うが)、JaCoCoは少なくとも確かに少なくともある程度は疑わしいことをしている。 – danfuzz

関連する問題