summaryrefslogtreecommitdiff
path: root/runtime/dex_instruction.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/dex_instruction.cc')
-rw-r--r--runtime/dex_instruction.cc210
1 files changed, 140 insertions, 70 deletions
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index 3f621249c5..9f34c12d9a 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -21,14 +21,17 @@
#include <iomanip>
#include <sstream>
-#include "base/stringprintf.h"
+#include "android-base/stringprintf.h"
+
#include "dex_file-inl.h"
#include "utils.h"
namespace art {
+using android::base::StringPrintf;
+
const char* const Instruction::kInstructionNames[] = {
-#define INSTRUCTION_NAME(o, c, pname, f, r, i, a, v) pname,
+#define INSTRUCTION_NAME(o, c, pname, f, i, a, v) pname,
#include "dex_instruction_list.h"
DEX_INSTRUCTION_LIST(INSTRUCTION_NAME)
#undef DEX_INSTRUCTION_LIST
@@ -36,7 +39,7 @@ const char* const Instruction::kInstructionNames[] = {
};
Instruction::Format const Instruction::kInstructionFormats[] = {
-#define INSTRUCTION_FORMAT(o, c, p, format, r, i, a, v) format,
+#define INSTRUCTION_FORMAT(o, c, p, format, i, a, v) format,
#include "dex_instruction_list.h"
DEX_INSTRUCTION_LIST(INSTRUCTION_FORMAT)
#undef DEX_INSTRUCTION_LIST
@@ -44,7 +47,7 @@ Instruction::Format const Instruction::kInstructionFormats[] = {
};
Instruction::IndexType const Instruction::kInstructionIndexTypes[] = {
-#define INSTRUCTION_INDEX_TYPE(o, c, p, f, r, index, a, v) index,
+#define INSTRUCTION_INDEX_TYPE(o, c, p, f, index, a, v) index,
#include "dex_instruction_list.h"
DEX_INSTRUCTION_LIST(INSTRUCTION_INDEX_TYPE)
#undef DEX_INSTRUCTION_LIST
@@ -52,7 +55,7 @@ Instruction::IndexType const Instruction::kInstructionIndexTypes[] = {
};
int const Instruction::kInstructionFlags[] = {
-#define INSTRUCTION_FLAGS(o, c, p, f, r, i, flags, v) flags,
+#define INSTRUCTION_FLAGS(o, c, p, f, i, flags, v) flags,
#include "dex_instruction_list.h"
DEX_INSTRUCTION_LIST(INSTRUCTION_FLAGS)
#undef DEX_INSTRUCTION_LIST
@@ -60,7 +63,7 @@ int const Instruction::kInstructionFlags[] = {
};
int const Instruction::kInstructionVerifyFlags[] = {
-#define INSTRUCTION_VERIFY_FLAGS(o, c, p, f, r, i, a, vflags) vflags,
+#define INSTRUCTION_VERIFY_FLAGS(o, c, p, f, i, a, vflags) vflags,
#include "dex_instruction_list.h"
DEX_INSTRUCTION_LIST(INSTRUCTION_VERIFY_FLAGS)
#undef DEX_INSTRUCTION_LIST
@@ -68,12 +71,13 @@ int const Instruction::kInstructionVerifyFlags[] = {
};
int const Instruction::kInstructionSizeInCodeUnits[] = {
-#define INSTRUCTION_SIZE(opcode, c, p, format, r, i, a, v) \
- ((opcode == NOP) ? -1 : \
- ((format >= k10x) && (format <= k10t)) ? 1 : \
- ((format >= k20t) && (format <= k25x)) ? 2 : \
- ((format >= k32x) && (format <= k3rc)) ? 3 : \
- (format == k51l) ? 5 : -1),
+#define INSTRUCTION_SIZE(opcode, c, p, format, i, a, v) \
+ (((opcode) == NOP) ? -1 : \
+ (((format) >= k10x) && ((format) <= k10t)) ? 1 : \
+ (((format) >= k20t) && ((format) <= k22c)) ? 2 : \
+ (((format) >= k32x) && ((format) <= k3rc)) ? 3 : \
+ (((format) >= k45cc) && ((format) <= k4rcc)) ? 4 : \
+ ((format) == k51l) ? 5 : -1),
#include "dex_instruction_list.h"
DEX_INSTRUCTION_LIST(INSTRUCTION_SIZE)
#undef DEX_INSTRUCTION_LIST
@@ -190,10 +194,11 @@ std::string Instruction::DumpString(const DexFile* file) const {
if (file != nullptr) {
uint32_t string_idx = VRegB_21c();
if (string_idx < file->NumStringIds()) {
- os << StringPrintf("const-string v%d, %s // string@%d",
- VRegA_21c(),
- PrintableString(file->StringDataByIdx(string_idx)).c_str(),
- string_idx);
+ os << StringPrintf(
+ "const-string v%d, %s // string@%d",
+ VRegA_21c(),
+ PrintableString(file->StringDataByIdx(dex::StringIndex(string_idx))).c_str(),
+ string_idx);
} else {
os << StringPrintf("const-string v%d, <<invalid-string-idx-%d>> // string@%d",
VRegA_21c(),
@@ -207,9 +212,9 @@ std::string Instruction::DumpString(const DexFile* file) const {
case CONST_CLASS:
case NEW_INSTANCE:
if (file != nullptr) {
- uint32_t type_idx = VRegB_21c();
- os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyType(type_idx, *file)
- << " // type@" << type_idx;
+ dex::TypeIndex type_idx(VRegB_21c());
+ os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", "
+ << file->PrettyType(type_idx) << " // type@" << type_idx;
break;
}
FALLTHROUGH_INTENDED;
@@ -222,7 +227,7 @@ std::string Instruction::DumpString(const DexFile* file) const {
case SGET_SHORT:
if (file != nullptr) {
uint32_t field_idx = VRegB_21c();
- os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
+ os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyField(field_idx, true)
<< " // field@" << field_idx;
break;
}
@@ -236,19 +241,11 @@ std::string Instruction::DumpString(const DexFile* file) const {
case SPUT_SHORT:
if (file != nullptr) {
uint32_t field_idx = VRegB_21c();
- os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
+ os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyField(field_idx, true)
<< " // field@" << field_idx;
break;
}
FALLTHROUGH_INTENDED;
- case CREATE_LAMBDA:
- if (file != nullptr) {
- uint32_t method_idx = VRegB_21c();
- os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyMethod(method_idx, *file, true)
- << " // method@" << method_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
default:
os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c());
break;
@@ -271,7 +268,7 @@ std::string Instruction::DumpString(const DexFile* file) const {
if (file != nullptr) {
uint32_t field_idx = VRegC_22c();
os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
- << PrettyField(field_idx, *file, true) << " // field@" << field_idx;
+ << file->PrettyField(field_idx, true) << " // field@" << field_idx;
break;
}
FALLTHROUGH_INTENDED;
@@ -294,7 +291,7 @@ std::string Instruction::DumpString(const DexFile* file) const {
if (file != nullptr) {
uint32_t field_idx = VRegC_22c();
os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
- << PrettyField(field_idx, *file, true) << " // field@" << field_idx;
+ << file->PrettyField(field_idx, true) << " // field@" << field_idx;
break;
}
FALLTHROUGH_INTENDED;
@@ -309,17 +306,19 @@ std::string Instruction::DumpString(const DexFile* file) const {
FALLTHROUGH_INTENDED;
case INSTANCE_OF:
if (file != nullptr) {
- uint32_t type_idx = VRegC_22c();
- os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
- << PrettyType(type_idx, *file) << " // type@" << type_idx;
+ dex::TypeIndex type_idx(VRegC_22c());
+ os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
+ << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
+ << " // type@" << type_idx.index_;
break;
}
FALLTHROUGH_INTENDED;
case NEW_ARRAY:
if (file != nullptr) {
- uint32_t type_idx = VRegC_22c();
- os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
- << PrettyType(type_idx, *file) << " // type@" << type_idx;
+ dex::TypeIndex type_idx(VRegC_22c());
+ os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
+ << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
+ << " // type@" << type_idx.index_;
break;
}
FALLTHROUGH_INTENDED;
@@ -329,26 +328,6 @@ std::string Instruction::DumpString(const DexFile* file) const {
}
break;
}
- case k25x: {
- if (Opcode() == INVOKE_LAMBDA) {
- uint32_t arg[kMaxVarArgRegs25x];
- GetAllArgs25x(arg);
- const size_t num_extra_var_args = VRegB_25x();
- DCHECK_LE(num_extra_var_args + 2, arraysize(arg));
-
- // invoke-lambda vC, {vD, vE, vF, vG}
- os << opcode << " v" << arg[0] << ", {";
- for (size_t i = 0; i < num_extra_var_args; ++i) {
- if (i != 0) {
- os << ", ";
- }
- os << "v" << arg[i + 2]; // Don't print the pair of vC registers. Pair is implicit.
- }
- os << "}";
- break;
- }
- FALLTHROUGH_INTENDED;
- }
case k32x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_32x(), VRegB_32x()); break;
case k30t: os << StringPrintf("%s %+d", opcode, VRegA_30t()); break;
case k31t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break;
@@ -358,11 +337,12 @@ std::string Instruction::DumpString(const DexFile* file) const {
uint32_t string_idx = VRegB_31c();
if (file != nullptr) {
if (string_idx < file->NumStringIds()) {
- os << StringPrintf("%s v%d, %s // string@%d",
- opcode,
- VRegA_31c(),
- PrintableString(file->StringDataByIdx(string_idx)).c_str(),
- string_idx);
+ os << StringPrintf(
+ "%s v%d, %s // string@%d",
+ opcode,
+ VRegA_31c(),
+ PrintableString(file->StringDataByIdx(dex::StringIndex(string_idx))).c_str(),
+ string_idx);
} else {
os << StringPrintf("%s v%d, <<invalid-string-idx-%d>> // string@%d",
opcode,
@@ -378,7 +358,7 @@ std::string Instruction::DumpString(const DexFile* file) const {
}
break;
case k35c: {
- uint32_t arg[5];
+ uint32_t arg[kMaxVarArgRegs];
GetVarArgs(arg);
switch (Opcode()) {
case FILLED_NEW_ARRAY:
@@ -409,7 +389,7 @@ std::string Instruction::DumpString(const DexFile* file) const {
}
os << "v" << arg[i];
}
- os << "}, " << PrettyMethod(method_idx, *file) << " // method@" << method_idx;
+ os << "}, " << file->PrettyMethod(method_idx) << " // method@" << method_idx;
break;
}
FALLTHROUGH_INTENDED;
@@ -427,6 +407,20 @@ std::string Instruction::DumpString(const DexFile* file) const {
break;
}
FALLTHROUGH_INTENDED;
+ case INVOKE_CUSTOM:
+ if (file != nullptr) {
+ os << opcode << " {";
+ uint32_t call_site_idx = VRegB_35c();
+ for (size_t i = 0; i < VRegA_35c(); ++i) {
+ if (i != 0) {
+ os << ", ";
+ }
+ os << "v" << arg[i];
+ }
+ os << "}, // call_site@" << call_site_idx;
+ break;
+ }
+ FALLTHROUGH_INTENDED;
default:
os << opcode << " {v" << arg[0] << ", v" << arg[1] << ", v" << arg[2]
<< ", v" << arg[3] << ", v" << arg[4] << "}, thing@" << VRegB_35c();
@@ -435,6 +429,8 @@ std::string Instruction::DumpString(const DexFile* file) const {
break;
}
case k3rc: {
+ uint16_t first_reg = VRegC_3rc();
+ uint16_t last_reg = VRegC_3rc() + VRegA_3rc() - 1;
switch (Opcode()) {
case INVOKE_VIRTUAL_RANGE:
case INVOKE_SUPER_RANGE:
@@ -443,32 +439,106 @@ std::string Instruction::DumpString(const DexFile* file) const {
case INVOKE_INTERFACE_RANGE:
if (file != nullptr) {
uint32_t method_idx = VRegB_3rc();
- os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1))
- << PrettyMethod(method_idx, *file) << " // method@" << method_idx;
+ os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
+ << file->PrettyMethod(method_idx) << " // method@" << method_idx;
break;
}
FALLTHROUGH_INTENDED;
case INVOKE_VIRTUAL_RANGE_QUICK:
if (file != nullptr) {
uint32_t method_idx = VRegB_3rc();
- os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1))
+ os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
<< "// vtable@" << method_idx;
break;
}
FALLTHROUGH_INTENDED;
+ case INVOKE_CUSTOM_RANGE:
+ if (file != nullptr) {
+ uint32_t call_site_idx = VRegB_3rc();
+ os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
+ << "// call_site@" << call_site_idx;
+ break;
+ }
+ FALLTHROUGH_INTENDED;
default:
- os << StringPrintf("%s, {v%d .. v%d}, thing@%d", opcode, VRegC_3rc(),
- (VRegC_3rc() + VRegA_3rc() - 1), VRegB_3rc());
+ os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
+ << "thing@" << VRegB_3rc();
break;
}
break;
}
+ case k45cc: {
+ uint32_t arg[kMaxVarArgRegs];
+ GetVarArgs(arg);
+ uint32_t method_idx = VRegB_45cc();
+ uint32_t proto_idx = VRegH_45cc();
+ os << opcode << " {";
+ for (int i = 0; i < VRegA_45cc(); ++i) {
+ if (i != 0) {
+ os << ", ";
+ }
+ os << "v" << arg[i];
+ }
+ os << "}";
+ if (file != nullptr) {
+ os << ", " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx)
+ << " // ";
+ } else {
+ os << ", ";
+ }
+ os << "method@" << method_idx << ", proto@" << proto_idx;
+ break;
+ }
+ case k4rcc:
+ switch (Opcode()) {
+ case INVOKE_POLYMORPHIC_RANGE: {
+ if (file != nullptr) {
+ uint32_t method_idx = VRegB_4rcc();
+ uint32_t proto_idx = VRegH_4rcc();
+ os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc())
+ << "}, " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx)
+ << " // method@" << method_idx << ", proto@" << proto_idx;
+ break;
+ }
+ }
+ FALLTHROUGH_INTENDED;
+ default: {
+ uint32_t method_idx = VRegB_4rcc();
+ uint32_t proto_idx = VRegH_4rcc();
+ os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc())
+ << "}, method@" << method_idx << ", proto@" << proto_idx;
+ }
+ }
+ break;
case k51l: os << StringPrintf("%s v%d, #%+" PRId64, opcode, VRegA_51l(), VRegB_51l()); break;
- default: os << " unknown format (" << DumpHex(5) << ")"; break;
}
return os.str();
}
+// Add some checks that ensure the flags make sense. We need a subclass to be in the context of
+// Instruction. Otherwise the flags from the instruction list don't work.
+struct InstructionStaticAsserts : private Instruction {
+ #define IMPLIES(a, b) (!(a) || (b))
+
+ #define VAR_ARGS_CHECK(o, c, pname, f, i, a, v) \
+ static_assert(IMPLIES((f) == k35c || (f) == k45cc, \
+ ((v) & (kVerifyVarArg | kVerifyVarArgNonZero)) != 0), \
+ "Missing var-arg verification");
+ #include "dex_instruction_list.h"
+ DEX_INSTRUCTION_LIST(VAR_ARGS_CHECK)
+ #undef DEX_INSTRUCTION_LIST
+ #undef VAR_ARGS_CHECK
+
+ #define VAR_ARGS_RANGE_CHECK(o, c, pname, f, i, a, v) \
+ static_assert(IMPLIES((f) == k3rc || (f) == k4rcc, \
+ ((v) & (kVerifyVarArgRange | kVerifyVarArgRangeNonZero)) != 0), \
+ "Missing var-arg verification");
+ #include "dex_instruction_list.h"
+ DEX_INSTRUCTION_LIST(VAR_ARGS_RANGE_CHECK)
+ #undef DEX_INSTRUCTION_LIST
+ #undef VAR_ARGS_RANGE_CHECK
+};
+
std::ostream& operator<<(std::ostream& os, const Instruction::Code& code) {
return os << Instruction::Name(code);
}