Dex disassembly suppport for invoke-polymorphic.

Bug:  30550796
Test: art/test/dexdump/run-all-tests
Change-Id: I013ce2ebbcf9555e01170dc47fc38036c276b1b4
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 2042934..b241c8b 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -42,6 +42,7 @@
 #include <sstream>
 #include <vector>
 
+#include "base/stringprintf.h"
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
 #include "utils.h"
@@ -780,9 +781,11 @@
 static std::unique_ptr<char[]> indexString(const DexFile* pDexFile,
                                            const Instruction* pDecInsn,
                                            size_t bufSize) {
+  static const u4 kInvalidIndex = std::numeric_limits<u4>::max();
   std::unique_ptr<char[]> buf(new char[bufSize]);
   // Determine index and width of the string.
   u4 index = 0;
+  u4 secondary_index = kInvalidIndex;
   u4 width = 4;
   switch (Instruction::FormatOf(pDecInsn->Opcode())) {
     // SOME NOT SUPPORTED:
@@ -806,6 +809,12 @@
       index = pDecInsn->VRegC();
       width = 4;
       break;
+    case Instruction::k45cc:
+    case Instruction::k4rcc:
+      index = pDecInsn->VRegB();
+      secondary_index = pDecInsn->VRegH();
+      width = 4;
+      break;
     default:
       break;
   }  // switch
@@ -870,6 +879,26 @@
     case Instruction::kIndexFieldOffset:
       outSize = snprintf(buf.get(), bufSize, "[obj+%0*x]", width, index);
       break;
+    case Instruction::kIndexMethodAndProtoRef: {
+        std::string method("<method?>");
+        std::string proto("<proto?>");
+        if (index < pDexFile->GetHeader().method_ids_size_) {
+          const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(index);
+          const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
+          const Signature signature = pDexFile->GetMethodSignature(pMethodId);
+          const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
+          method = StringPrintf("%s.%s:%s",
+                                backDescriptor, name, signature.ToString().c_str());
+        }
+        if (secondary_index < pDexFile->GetHeader().proto_ids_size_) {
+          const DexFile::ProtoId& protoId = pDexFile->GetProtoId(secondary_index);
+          const Signature signature = pDexFile->GetProtoSignature(protoId);
+          proto = signature.ToString();
+        }
+        outSize = snprintf(buf.get(), bufSize, "%s, %s // method@%0*x, proto@%0*x",
+                           method.c_str(), proto.c_str(), width, index, width, secondary_index);
+      }
+      break;
     // SOME NOT SUPPORTED:
     // case Instruction::kIndexVaries:
     // case Instruction::kIndexInlineMethod:
@@ -1043,7 +1072,8 @@
     case Instruction::k32x:        // op vAAAA, vBBBB
       fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
       break;
-    case Instruction::k35c: {      // op {vC, vD, vE, vF, vG}, thing@BBBB
+    case Instruction::k35c:       // op {vC, vD, vE, vF, vG}, thing@BBBB
+    case Instruction::k45cc: {    // op {vC, vD, vE, vF, vG}, method@BBBB, proto@HHHH
     // NOT SUPPORTED:
     // case Instruction::k35ms:       // [opt] invoke-virtual+super
     // case Instruction::k35mi:       // [opt] inline invoke
@@ -1061,10 +1091,10 @@
       break;
     }
     case Instruction::k3rc:        // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
+    case Instruction::k4rcc: {     // op {vCCCC .. v(CCCC+AA-1)}, method@BBBB, proto@HHHH
     // NOT SUPPORTED:
     // case Instruction::k3rms:       // [opt] invoke-virtual+super/range
     // case Instruction::k3rmi:       // [opt] execute-inline/range
-      {
         // This doesn't match the "dx" output when some of the args are
         // 64-bit values -- dx only shows the first register.
         fputs(" {", gOutFile);
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 0f07f23..c3c763f 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -122,6 +122,8 @@
     // case Instruction::k3rms:
     // case Instruction::k35mi:
     // case Instruction::k3rmi:
+    case Instruction::k45cc:
+    case Instruction::k4rcc:
       index = dec_insn->VRegB();
       break;
     case Instruction::k31c:
@@ -150,6 +152,7 @@
       }
       break;
     case Instruction::kIndexMethodRef:
+    case Instruction::kIndexMethodAndProtoRef:
       if (index < collections.MethodIdsSize()) {
         method_ids->push_back(collections.GetMethodId(index));
         return true;
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index a9ae55f..1071880 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -30,6 +30,7 @@
 #include <sstream>
 #include <vector>
 
+#include "base/stringprintf.h"
 #include "dex_ir_builder.h"
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
@@ -722,9 +723,11 @@
 static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
                                            const Instruction* dec_insn,
                                            size_t buf_size) {
+  static const uint32_t kInvalidIndex = std::numeric_limits<uint32_t>::max();
   std::unique_ptr<char[]> buf(new char[buf_size]);
   // Determine index and width of the string.
   uint32_t index = 0;
+  uint32_t secondary_index = kInvalidIndex;
   uint32_t width = 4;
   switch (Instruction::FormatOf(dec_insn->Opcode())) {
     // SOME NOT SUPPORTED:
@@ -748,6 +751,12 @@
       index = dec_insn->VRegC();
       width = 4;
       break;
+    case Instruction::k45cc:
+    case Instruction::k4rcc:
+      index = dec_insn->VRegB();
+      secondary_index = dec_insn->VRegH();
+      width = 4;
+      break;
     default:
       break;
   }  // switch
@@ -815,6 +824,24 @@
     // SOME NOT SUPPORTED:
     // case Instruction::kIndexVaries:
     // case Instruction::kIndexInlineMethod:
+    case Instruction::kIndexMethodAndProtoRef: {
+      std::string method("<method?>");
+      std::string proto("<proto?>");
+      if (index < header->GetCollections().MethodIdsSize()) {
+        dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
+        const char* name = method_id->Name()->Data();
+        std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
+        const char* back_descriptor = method_id->Class()->GetStringId()->Data();
+        method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str());
+      }
+      if (secondary_index < header->GetCollections().ProtoIdsSize()) {
+        dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index);
+        proto = GetSignatureForProtoId(proto_id);
+      }
+      outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
+                         method.c_str(), proto.c_str(), width, index, width, secondary_index);
+      }
+      break;
     default:
       outSize = snprintf(buf.get(), buf_size, "<?>");
       break;
@@ -984,7 +1011,8 @@
     case Instruction::k32x:        // op vAAAA, vBBBB
       fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
       break;
-    case Instruction::k35c: {      // op {vC, vD, vE, vF, vG}, thing@BBBB
+    case Instruction::k35c:           // op {vC, vD, vE, vF, vG}, thing@BBBB
+    case Instruction::k45cc: {        // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH
     // NOT SUPPORTED:
     // case Instruction::k35ms:       // [opt] invoke-virtual+super
     // case Instruction::k35mi:       // [opt] inline invoke
@@ -1001,7 +1029,8 @@
       fprintf(out_file_, "}, %s", index_buf.get());
       break;
     }
-    case Instruction::k3rc:        // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
+    case Instruction::k3rc:           // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
+    case Instruction::k4rcc:          // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH
     // NOT SUPPORTED:
     // case Instruction::k3rms:       // [opt] invoke-virtual+super/range
     // case Instruction::k3rmi:       // [opt] execute-inline/range
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index 108a5af..621b2c5 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -90,6 +90,10 @@
   return Signature(this, GetProtoId(method_id.proto_idx_));
 }
 
+inline const Signature DexFile::GetProtoSignature(const ProtoId& proto_id) const {
+  return Signature(this, proto_id);
+}
+
 inline const char* DexFile::GetMethodName(const MethodId& method_id) const {
   return StringDataByIdx(method_id.name_idx_);
 }
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 29b8c3a..07daf81 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -639,6 +639,9 @@
   // Returns a representation of the signature of a method id.
   const Signature GetMethodSignature(const MethodId& method_id) const;
 
+  // Returns a representation of the signature of a proto id.
+  const Signature GetProtoSignature(const ProtoId& proto_id) const;
+
   // Returns the name of a method id.
   const char* GetMethodName(const MethodId& method_id) const;
 
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index f437fde..8eb1a79 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -126,13 +126,14 @@
 
   enum IndexType {
     kIndexUnknown = 0,
-    kIndexNone,          // has no index
-    kIndexTypeRef,       // type reference index
-    kIndexStringRef,     // string reference index
-    kIndexMethodRef,     // method reference index
-    kIndexFieldRef,      // field reference index
-    kIndexFieldOffset,   // field offset (for static linked fields)
-    kIndexVtableOffset   // vtable offset (for static linked methods)
+    kIndexNone,              // has no index
+    kIndexTypeRef,           // type reference index
+    kIndexStringRef,         // string reference index
+    kIndexMethodRef,         // method reference index
+    kIndexFieldRef,          // field reference index
+    kIndexFieldOffset,       // field offset (for static linked fields)
+    kIndexVtableOffset,      // vtable offset (for static linked methods)
+    kIndexMethodAndProtoRef  // method and a proto reference index (for invoke-polymorphic)
   };
 
   enum Flags {
diff --git a/runtime/dex_instruction_list.h b/runtime/dex_instruction_list.h
index 3194c1a..e537afe 100644
--- a/runtime/dex_instruction_list.h
+++ b/runtime/dex_instruction_list.h
@@ -269,8 +269,8 @@
   V(0xF7, UNUSED_F7, "unused-f7", k10x, kIndexUnknown, 0, kVerifyError) \
   V(0xF8, UNUSED_F8, "unused-f8", k10x, kIndexUnknown, 0, kVerifyError) \
   V(0xF9, UNUSED_F9, "unused-f9", k10x, kIndexUnknown, 0, kVerifyError) \
-  V(0xFA, INVOKE_POLYMORPHIC, "invoke-polymorphic", k45cc, kIndexMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero | kExperimental) \
-  V(0xFB, INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range", k4rcc, kIndexMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero | kExperimental) \
+  V(0xFA, INVOKE_POLYMORPHIC, "invoke-polymorphic", k45cc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero | kExperimental) \
+  V(0xFB, INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range", k4rcc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero | kExperimental) \
   V(0xFC, UNUSED_FC, "unused-fc", k10x, kIndexUnknown, 0, kVerifyError) \
   V(0xFD, UNUSED_FD, "unused-fd", k10x, kIndexUnknown, 0, kVerifyError) \
   V(0xFE, UNUSED_FE, "unused-fe", k10x, kIndexUnknown, 0, kVerifyError) \
diff --git a/test/dexdump/invoke-polymorphic.dex b/test/dexdump/invoke-polymorphic.dex
new file mode 100644
index 0000000..5cf3068
--- /dev/null
+++ b/test/dexdump/invoke-polymorphic.dex
Binary files differ
diff --git a/test/dexdump/invoke-polymorphic.lst b/test/dexdump/invoke-polymorphic.lst
new file mode 100644
index 0000000..3eb8e24
--- /dev/null
+++ b/test/dexdump/invoke-polymorphic.lst
@@ -0,0 +1,3 @@
+#invoke-polymorphic.dex
+0x000001bc 8 Main <init> ()V Main.java 9
+0x000001d4 60 Main main ([Ljava/lang/String;)V Main.java 31
diff --git a/test/dexdump/invoke-polymorphic.txt b/test/dexdump/invoke-polymorphic.txt
new file mode 100644
index 0000000..16e708c
--- /dev/null
+++ b/test/dexdump/invoke-polymorphic.txt
@@ -0,0 +1,109 @@
+Processing 'invoke-polymorphic.dex'...
+Opened 'invoke-polymorphic.dex', DEX version '037'
+DEX file header:
+magic               : 'dex\n037\0'
+checksum            : 0b5f9fd7
+signature           : fcf4...f0e5
+file_size           : 1160
+header_size         : 112
+link_size           : 0
+link_off            : 0 (0x000000)
+string_ids_size     : 30
+string_ids_off      : 112 (0x000070)
+type_ids_size       : 11
+type_ids_off        : 232 (0x0000e8)
+proto_ids_size      : 6
+proto_ids_off       : 276 (0x000114)
+field_ids_size      : 0
+field_ids_off       : 0 (0x000000)
+method_ids_size     : 5
+method_ids_off      : 348 (0x00015c)
+class_defs_size     : 1
+class_defs_off      : 388 (0x000184)
+data_size           : 740
+data_off            : 420 (0x0001a4)
+
+Class #0 header:
+class_idx           : 2
+access_flags        : 1 (0x0001)
+superclass_idx      : 4
+interfaces_off      : 0 (0x000000)
+source_file_idx     : 12
+annotations_off     : 528 (0x000210)
+class_data_off      : 959 (0x0003bf)
+static_fields_size  : 0
+instance_fields_size: 0
+direct_methods_size : 2
+virtual_methods_size: 0
+
+Class #0 annotations:
+Annotations on method #1 'main'
+  VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; }
+
+Class #0            -
+  Class descriptor  : 'LMain;'
+  Access flags      : 0x0001 (PUBLIC)
+  Superclass        : 'Ljava/lang/Object;'
+  Interfaces        -
+  Static fields     -
+  Instance fields   -
+  Direct methods    -
+    #0              : (in LMain;)
+      name          : '<init>'
+      type          : '()V'
+      access        : 0x10001 (PUBLIC CONSTRUCTOR)
+      code          -
+      registers     : 1
+      ins           : 1
+      outs          : 1
+      insns size    : 4 16-bit code units
+0001ac:                                        |[0001ac] Main.<init>:()V
+0001bc: 7010 0200 0000                         |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@0002
+0001c2: 0e00                                   |0003: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=9
+      locals        : 
+        0x0000 - 0x0004 reg=0 this LMain; 
+
+    #1              : (in LMain;)
+      name          : 'main'
+      type          : '([Ljava/lang/String;)V'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 10
+      ins           : 1
+      outs          : 0
+      insns size    : 30 16-bit code units
+0001c4:                                        |[0001c4] Main.main:([Ljava/lang/String;)V
+0001d4: 1802 9a99 9999 9999 0140               |0000: const-wide v2, #double 2.2 // #400199999999999a
+0001de: 1214                                   |0005: const/4 v4, #int 1 // #1
+0001e0: 1200                                   |0006: const/4 v0, #int 0 // #0
+0001e2: 1205                                   |0007: const/4 v5, #int 0 // #0
+0001e4: 1b01 1200 0000                         |0008: const-string/jumbo v1, "a" // string@00000012
+0001ea: 0146                                   |000b: move v6, v4
+0001ec: fb07 0300 0000 0200                    |000c: invoke-polymorphic/range {v0, v1, v2, v3, v4, v5, v6}, Ljava/lang/invoke/MethodHandle;.invoke:([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/String;DILjava/lang/Object;I)Ljava/lang/String; // method@0003, proto@0002
+0001f4: 0c07                                   |0010: move-result-object v7
+0001f6: fa40 0400 2043 0000                    |0011: invoke-polymorphic {v0, v2, v3, v4}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (DI)I // method@0004, proto@0000
+0001fe: 0a08                                   |0015: move-result v8
+000200: 1b01 1200 0000                         |0016: const-string/jumbo v1, "a" // string@00000012
+000206: fa54 0300 1032 0400                    |0019: invoke-polymorphic {v0, v1, v2, v3, v4}, Ljava/lang/invoke/MethodHandle;.invoke:([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/String;DI)V // method@0003, proto@0004
+00020e: 0e00                                   |001d: return-void
+      catches       : (none)
+      positions     : 
+        0x0006 line=31
+        0x0007 line=32
+        0x0008 line=33
+        0x0011 line=34
+        0x0016 line=35
+        0x001d line=56
+      locals        : 
+        0x0007 - 0x001e reg=0 handle Ljava/lang/invoke/MethodHandle; 
+        0x0008 - 0x001e reg=5 o Ljava/lang/Object; 
+        0x0011 - 0x001e reg=7 s Ljava/lang/String; 
+        0x0016 - 0x001e reg=8 x I 
+        0x0000 - 0x001e reg=9 args [Ljava/lang/String; 
+
+  Virtual methods   -
+  source_file_idx   : 12 (Main.java)
+
diff --git a/test/dexdump/invoke-polymorphic.xml b/test/dexdump/invoke-polymorphic.xml
new file mode 100644
index 0000000..ab99a76
--- /dev/null
+++ b/test/dexdump/invoke-polymorphic.xml
@@ -0,0 +1,33 @@
+<api>
+<package name=""
+>
+<class name="Main"
+ extends="java.lang.Object"
+ interface="false"
+ abstract="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<constructor name="Main"
+ type="Main"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</constructor>
+<method name="main"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="java.lang.String[]">
+</parameter>
+</method>
+</class>
+</package>
+</api>