Merge "Dex disassembly suppport for invoke-polymorphic."
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 20f3a9c..da828dc 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>