xref: /aosp_15_r20/art/libdexfile/dex/dex_instruction.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "dex_instruction-inl.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <inttypes.h>
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include <iomanip>
22*795d594fSAndroid Build Coastguard Worker #include <sstream>
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker #include "dex_file-inl.h"
27*795d594fSAndroid Build Coastguard Worker #include "dex_instruction_list.h"
28*795d594fSAndroid Build Coastguard Worker #include "utf.h"
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker namespace art {
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker using android::base::StringPrintf;
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker const char* const Instruction::kInstructionNames[] = {
35*795d594fSAndroid Build Coastguard Worker #define INSTRUCTION_NAME(o, c, pname, f, i, a, e, v) pname,
36*795d594fSAndroid Build Coastguard Worker   DEX_INSTRUCTION_LIST(INSTRUCTION_NAME)
37*795d594fSAndroid Build Coastguard Worker #undef INSTRUCTION_NAME
38*795d594fSAndroid Build Coastguard Worker };
39*795d594fSAndroid Build Coastguard Worker 
40*795d594fSAndroid Build Coastguard Worker static_assert(sizeof(Instruction::InstructionDescriptor) == 8u, "Unexpected descriptor size");
41*795d594fSAndroid Build Coastguard Worker 
GetTargetOffset() const42*795d594fSAndroid Build Coastguard Worker int32_t Instruction::GetTargetOffset() const {
43*795d594fSAndroid Build Coastguard Worker   switch (FormatOf(Opcode())) {
44*795d594fSAndroid Build Coastguard Worker     // Cases for conditional branches follow.
45*795d594fSAndroid Build Coastguard Worker     case k22t: return VRegC_22t();
46*795d594fSAndroid Build Coastguard Worker     case k21t: return VRegB_21t();
47*795d594fSAndroid Build Coastguard Worker     // Cases for unconditional branches follow.
48*795d594fSAndroid Build Coastguard Worker     case k10t: return VRegA_10t();
49*795d594fSAndroid Build Coastguard Worker     case k20t: return VRegA_20t();
50*795d594fSAndroid Build Coastguard Worker     case k30t: return VRegA_30t();
51*795d594fSAndroid Build Coastguard Worker     default:
52*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Tried to access the branch offset of an instruction " << Name()
53*795d594fSAndroid Build Coastguard Worker                  << " which does not have a target operand.";
54*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
55*795d594fSAndroid Build Coastguard Worker   }
56*795d594fSAndroid Build Coastguard Worker }
57*795d594fSAndroid Build Coastguard Worker 
CanFlowThrough() const58*795d594fSAndroid Build Coastguard Worker bool Instruction::CanFlowThrough() const {
59*795d594fSAndroid Build Coastguard Worker   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
60*795d594fSAndroid Build Coastguard Worker   uint16_t insn = *insns;
61*795d594fSAndroid Build Coastguard Worker   Code opcode = static_cast<Code>(insn & 0xFF);
62*795d594fSAndroid Build Coastguard Worker   return  FlagsOf(opcode) & Instruction::kContinue;
63*795d594fSAndroid Build Coastguard Worker }
64*795d594fSAndroid Build Coastguard Worker 
SizeInCodeUnitsComplexOpcode() const65*795d594fSAndroid Build Coastguard Worker size_t Instruction::SizeInCodeUnitsComplexOpcode() const {
66*795d594fSAndroid Build Coastguard Worker   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
67*795d594fSAndroid Build Coastguard Worker   // Handle special NOP encoded variable length sequences.
68*795d594fSAndroid Build Coastguard Worker   switch (*insns) {
69*795d594fSAndroid Build Coastguard Worker     case kPackedSwitchSignature:
70*795d594fSAndroid Build Coastguard Worker       return (4 + insns[1] * 2);
71*795d594fSAndroid Build Coastguard Worker     case kSparseSwitchSignature:
72*795d594fSAndroid Build Coastguard Worker       return (2 + insns[1] * 4);
73*795d594fSAndroid Build Coastguard Worker     case kArrayDataSignature: {
74*795d594fSAndroid Build Coastguard Worker       uint16_t element_size = insns[1];
75*795d594fSAndroid Build Coastguard Worker       uint32_t length = insns[2] | (((uint32_t)insns[3]) << 16);
76*795d594fSAndroid Build Coastguard Worker       // The plus 1 is to round up for odd size and width.
77*795d594fSAndroid Build Coastguard Worker       return (4 + (element_size * length + 1) / 2);
78*795d594fSAndroid Build Coastguard Worker     }
79*795d594fSAndroid Build Coastguard Worker     default:
80*795d594fSAndroid Build Coastguard Worker       if ((*insns & 0xFF) == 0) {
81*795d594fSAndroid Build Coastguard Worker         return 1;  // NOP.
82*795d594fSAndroid Build Coastguard Worker       } else {
83*795d594fSAndroid Build Coastguard Worker         LOG(FATAL) << "Unreachable: " << DumpString(nullptr);
84*795d594fSAndroid Build Coastguard Worker         UNREACHABLE();
85*795d594fSAndroid Build Coastguard Worker       }
86*795d594fSAndroid Build Coastguard Worker   }
87*795d594fSAndroid Build Coastguard Worker }
88*795d594fSAndroid Build Coastguard Worker 
CodeUnitsRequiredForSizeOfComplexOpcode() const89*795d594fSAndroid Build Coastguard Worker size_t Instruction::CodeUnitsRequiredForSizeOfComplexOpcode() const {
90*795d594fSAndroid Build Coastguard Worker   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
91*795d594fSAndroid Build Coastguard Worker   // Handle special NOP encoded variable length sequences.
92*795d594fSAndroid Build Coastguard Worker   switch (*insns) {
93*795d594fSAndroid Build Coastguard Worker     case kPackedSwitchSignature:
94*795d594fSAndroid Build Coastguard Worker       FALLTHROUGH_INTENDED;
95*795d594fSAndroid Build Coastguard Worker     case kSparseSwitchSignature:
96*795d594fSAndroid Build Coastguard Worker       return 2;
97*795d594fSAndroid Build Coastguard Worker     case kArrayDataSignature:
98*795d594fSAndroid Build Coastguard Worker       return 4;
99*795d594fSAndroid Build Coastguard Worker     default:
100*795d594fSAndroid Build Coastguard Worker       if ((*insns & 0xFF) == 0) {
101*795d594fSAndroid Build Coastguard Worker         return 1;  // NOP.
102*795d594fSAndroid Build Coastguard Worker       } else {
103*795d594fSAndroid Build Coastguard Worker         LOG(FATAL) << "Unreachable: " << DumpString(nullptr);
104*795d594fSAndroid Build Coastguard Worker         UNREACHABLE();
105*795d594fSAndroid Build Coastguard Worker       }
106*795d594fSAndroid Build Coastguard Worker   }
107*795d594fSAndroid Build Coastguard Worker }
108*795d594fSAndroid Build Coastguard Worker 
DumpHex(size_t code_units) const109*795d594fSAndroid Build Coastguard Worker std::string Instruction::DumpHex(size_t code_units) const {
110*795d594fSAndroid Build Coastguard Worker   size_t inst_length = SizeInCodeUnits();
111*795d594fSAndroid Build Coastguard Worker   if (inst_length > code_units) {
112*795d594fSAndroid Build Coastguard Worker     inst_length = code_units;
113*795d594fSAndroid Build Coastguard Worker   }
114*795d594fSAndroid Build Coastguard Worker   std::ostringstream os;
115*795d594fSAndroid Build Coastguard Worker   const uint16_t* insn = reinterpret_cast<const uint16_t*>(this);
116*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < inst_length; i++) {
117*795d594fSAndroid Build Coastguard Worker     os << StringPrintf("0x%04x", insn[i]) << " ";
118*795d594fSAndroid Build Coastguard Worker   }
119*795d594fSAndroid Build Coastguard Worker   for (size_t i = inst_length; i < code_units; i++) {
120*795d594fSAndroid Build Coastguard Worker     os << "       ";
121*795d594fSAndroid Build Coastguard Worker   }
122*795d594fSAndroid Build Coastguard Worker   return os.str();
123*795d594fSAndroid Build Coastguard Worker }
124*795d594fSAndroid Build Coastguard Worker 
DumpHexLE(size_t instr_code_units) const125*795d594fSAndroid Build Coastguard Worker std::string Instruction::DumpHexLE(size_t instr_code_units) const {
126*795d594fSAndroid Build Coastguard Worker   size_t inst_length = SizeInCodeUnits();
127*795d594fSAndroid Build Coastguard Worker   if (inst_length > instr_code_units) {
128*795d594fSAndroid Build Coastguard Worker     inst_length = instr_code_units;
129*795d594fSAndroid Build Coastguard Worker   }
130*795d594fSAndroid Build Coastguard Worker   std::ostringstream os;
131*795d594fSAndroid Build Coastguard Worker   const uint16_t* insn = reinterpret_cast<const uint16_t*>(this);
132*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < inst_length; i++) {
133*795d594fSAndroid Build Coastguard Worker     os << StringPrintf("%02x%02x", static_cast<uint8_t>(insn[i] & 0x00FF),
134*795d594fSAndroid Build Coastguard Worker                        static_cast<uint8_t>((insn[i] & 0xFF00) >> 8)) << " ";
135*795d594fSAndroid Build Coastguard Worker   }
136*795d594fSAndroid Build Coastguard Worker   for (size_t i = inst_length; i < instr_code_units; i++) {
137*795d594fSAndroid Build Coastguard Worker     os << "     ";
138*795d594fSAndroid Build Coastguard Worker   }
139*795d594fSAndroid Build Coastguard Worker   return os.str();
140*795d594fSAndroid Build Coastguard Worker }
141*795d594fSAndroid Build Coastguard Worker 
DumpString(const DexFile * file) const142*795d594fSAndroid Build Coastguard Worker std::string Instruction::DumpString(const DexFile* file) const {
143*795d594fSAndroid Build Coastguard Worker   std::ostringstream os;
144*795d594fSAndroid Build Coastguard Worker   const char* opcode = kInstructionNames[Opcode()];
145*795d594fSAndroid Build Coastguard Worker   switch (FormatOf(Opcode())) {
146*795d594fSAndroid Build Coastguard Worker     case k10x:  os << opcode; break;
147*795d594fSAndroid Build Coastguard Worker     case k12x:  os << StringPrintf("%s v%d, v%d", opcode, VRegA_12x(), VRegB_12x()); break;
148*795d594fSAndroid Build Coastguard Worker     case k11n:  os << StringPrintf("%s v%d, #%+d", opcode, VRegA_11n(), VRegB_11n()); break;
149*795d594fSAndroid Build Coastguard Worker     case k11x:  os << StringPrintf("%s v%d", opcode, VRegA_11x()); break;
150*795d594fSAndroid Build Coastguard Worker     case k10t:  os << StringPrintf("%s %+d", opcode, VRegA_10t()); break;
151*795d594fSAndroid Build Coastguard Worker     case k20t:  os << StringPrintf("%s %+d", opcode, VRegA_20t()); break;
152*795d594fSAndroid Build Coastguard Worker     case k22x:  os << StringPrintf("%s v%d, v%d", opcode, VRegA_22x(), VRegB_22x()); break;
153*795d594fSAndroid Build Coastguard Worker     case k21t:  os << StringPrintf("%s v%d, %+d", opcode, VRegA_21t(), VRegB_21t()); break;
154*795d594fSAndroid Build Coastguard Worker     case k21s:  os << StringPrintf("%s v%d, #%+d", opcode, VRegA_21s(), VRegB_21s()); break;
155*795d594fSAndroid Build Coastguard Worker     case k21h: {
156*795d594fSAndroid Build Coastguard Worker         // op vAA, #+BBBB0000[00000000]
157*795d594fSAndroid Build Coastguard Worker         if (Opcode() == CONST_HIGH16) {
158*795d594fSAndroid Build Coastguard Worker           uint32_t value = VRegB_21h() << 16;
159*795d594fSAndroid Build Coastguard Worker           os << StringPrintf("%s v%d, #int %+d // 0x%x", opcode, VRegA_21h(), value, value);
160*795d594fSAndroid Build Coastguard Worker         } else {
161*795d594fSAndroid Build Coastguard Worker           uint64_t value = static_cast<uint64_t>(VRegB_21h()) << 48;
162*795d594fSAndroid Build Coastguard Worker           os << StringPrintf("%s v%d, #long %+" PRId64 " // 0x%" PRIx64, opcode, VRegA_21h(),
163*795d594fSAndroid Build Coastguard Worker                              value, value);
164*795d594fSAndroid Build Coastguard Worker         }
165*795d594fSAndroid Build Coastguard Worker       }
166*795d594fSAndroid Build Coastguard Worker       break;
167*795d594fSAndroid Build Coastguard Worker     case k21c: {
168*795d594fSAndroid Build Coastguard Worker       switch (Opcode()) {
169*795d594fSAndroid Build Coastguard Worker         case CONST_STRING:
170*795d594fSAndroid Build Coastguard Worker           if (file != nullptr) {
171*795d594fSAndroid Build Coastguard Worker             uint32_t string_idx = VRegB_21c();
172*795d594fSAndroid Build Coastguard Worker             if (string_idx < file->NumStringIds()) {
173*795d594fSAndroid Build Coastguard Worker               os << StringPrintf(
174*795d594fSAndroid Build Coastguard Worker                   "const-string v%d, %s // string@%d",
175*795d594fSAndroid Build Coastguard Worker                   VRegA_21c(),
176*795d594fSAndroid Build Coastguard Worker                   PrintableString(file->GetStringData(dex::StringIndex(string_idx))).c_str(),
177*795d594fSAndroid Build Coastguard Worker                   string_idx);
178*795d594fSAndroid Build Coastguard Worker             } else {
179*795d594fSAndroid Build Coastguard Worker               os << StringPrintf("const-string v%d, <<invalid-string-idx-%d>> // string@%d",
180*795d594fSAndroid Build Coastguard Worker                                  VRegA_21c(),
181*795d594fSAndroid Build Coastguard Worker                                  string_idx,
182*795d594fSAndroid Build Coastguard Worker                                  string_idx);
183*795d594fSAndroid Build Coastguard Worker             }
184*795d594fSAndroid Build Coastguard Worker             break;
185*795d594fSAndroid Build Coastguard Worker           }
186*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
187*795d594fSAndroid Build Coastguard Worker         case CHECK_CAST:
188*795d594fSAndroid Build Coastguard Worker         case CONST_CLASS:
189*795d594fSAndroid Build Coastguard Worker         case NEW_INSTANCE:
190*795d594fSAndroid Build Coastguard Worker           if (file != nullptr) {
191*795d594fSAndroid Build Coastguard Worker             dex::TypeIndex type_idx(VRegB_21c());
192*795d594fSAndroid Build Coastguard Worker             os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", "
193*795d594fSAndroid Build Coastguard Worker                << file->PrettyType(type_idx) << " // type@" << type_idx;
194*795d594fSAndroid Build Coastguard Worker             break;
195*795d594fSAndroid Build Coastguard Worker           }
196*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
197*795d594fSAndroid Build Coastguard Worker         case SGET:
198*795d594fSAndroid Build Coastguard Worker         case SGET_WIDE:
199*795d594fSAndroid Build Coastguard Worker         case SGET_OBJECT:
200*795d594fSAndroid Build Coastguard Worker         case SGET_BOOLEAN:
201*795d594fSAndroid Build Coastguard Worker         case SGET_BYTE:
202*795d594fSAndroid Build Coastguard Worker         case SGET_CHAR:
203*795d594fSAndroid Build Coastguard Worker         case SGET_SHORT:
204*795d594fSAndroid Build Coastguard Worker           if (file != nullptr) {
205*795d594fSAndroid Build Coastguard Worker             uint32_t field_idx = VRegB_21c();
206*795d594fSAndroid Build Coastguard Worker             os << opcode << "  v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyField(field_idx, true)
207*795d594fSAndroid Build Coastguard Worker                << " // field@" << field_idx;
208*795d594fSAndroid Build Coastguard Worker             break;
209*795d594fSAndroid Build Coastguard Worker           }
210*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
211*795d594fSAndroid Build Coastguard Worker         case SPUT:
212*795d594fSAndroid Build Coastguard Worker         case SPUT_WIDE:
213*795d594fSAndroid Build Coastguard Worker         case SPUT_OBJECT:
214*795d594fSAndroid Build Coastguard Worker         case SPUT_BOOLEAN:
215*795d594fSAndroid Build Coastguard Worker         case SPUT_BYTE:
216*795d594fSAndroid Build Coastguard Worker         case SPUT_CHAR:
217*795d594fSAndroid Build Coastguard Worker         case SPUT_SHORT:
218*795d594fSAndroid Build Coastguard Worker           if (file != nullptr) {
219*795d594fSAndroid Build Coastguard Worker             uint32_t field_idx = VRegB_21c();
220*795d594fSAndroid Build Coastguard Worker             os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyField(field_idx, true)
221*795d594fSAndroid Build Coastguard Worker                << " // field@" << field_idx;
222*795d594fSAndroid Build Coastguard Worker             break;
223*795d594fSAndroid Build Coastguard Worker           }
224*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
225*795d594fSAndroid Build Coastguard Worker         default:
226*795d594fSAndroid Build Coastguard Worker           os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c());
227*795d594fSAndroid Build Coastguard Worker           break;
228*795d594fSAndroid Build Coastguard Worker       }
229*795d594fSAndroid Build Coastguard Worker       break;
230*795d594fSAndroid Build Coastguard Worker     }
231*795d594fSAndroid Build Coastguard Worker     case k23x:  os << StringPrintf("%s v%d, v%d, v%d", opcode, VRegA_23x(), VRegB_23x(), VRegC_23x()); break;
232*795d594fSAndroid Build Coastguard Worker     case k22b:  os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22b(), VRegB_22b(), VRegC_22b()); break;
233*795d594fSAndroid Build Coastguard Worker     case k22t:  os << StringPrintf("%s v%d, v%d, %+d", opcode, VRegA_22t(), VRegB_22t(), VRegC_22t()); break;
234*795d594fSAndroid Build Coastguard Worker     case k22s:  os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22s(), VRegB_22s(), VRegC_22s()); break;
235*795d594fSAndroid Build Coastguard Worker     case k22c: {
236*795d594fSAndroid Build Coastguard Worker       switch (Opcode()) {
237*795d594fSAndroid Build Coastguard Worker         case IGET:
238*795d594fSAndroid Build Coastguard Worker         case IGET_WIDE:
239*795d594fSAndroid Build Coastguard Worker         case IGET_OBJECT:
240*795d594fSAndroid Build Coastguard Worker         case IGET_BOOLEAN:
241*795d594fSAndroid Build Coastguard Worker         case IGET_BYTE:
242*795d594fSAndroid Build Coastguard Worker         case IGET_CHAR:
243*795d594fSAndroid Build Coastguard Worker         case IGET_SHORT:
244*795d594fSAndroid Build Coastguard Worker           if (file != nullptr) {
245*795d594fSAndroid Build Coastguard Worker             uint32_t field_idx = VRegC_22c();
246*795d594fSAndroid Build Coastguard Worker             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
247*795d594fSAndroid Build Coastguard Worker                << file->PrettyField(field_idx, true) << " // field@" << field_idx;
248*795d594fSAndroid Build Coastguard Worker             break;
249*795d594fSAndroid Build Coastguard Worker           }
250*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
251*795d594fSAndroid Build Coastguard Worker         case IPUT:
252*795d594fSAndroid Build Coastguard Worker         case IPUT_WIDE:
253*795d594fSAndroid Build Coastguard Worker         case IPUT_OBJECT:
254*795d594fSAndroid Build Coastguard Worker         case IPUT_BOOLEAN:
255*795d594fSAndroid Build Coastguard Worker         case IPUT_BYTE:
256*795d594fSAndroid Build Coastguard Worker         case IPUT_CHAR:
257*795d594fSAndroid Build Coastguard Worker         case IPUT_SHORT:
258*795d594fSAndroid Build Coastguard Worker           if (file != nullptr) {
259*795d594fSAndroid Build Coastguard Worker             uint32_t field_idx = VRegC_22c();
260*795d594fSAndroid Build Coastguard Worker             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
261*795d594fSAndroid Build Coastguard Worker                << file->PrettyField(field_idx, true) << " // field@" << field_idx;
262*795d594fSAndroid Build Coastguard Worker             break;
263*795d594fSAndroid Build Coastguard Worker           }
264*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
265*795d594fSAndroid Build Coastguard Worker         case INSTANCE_OF:
266*795d594fSAndroid Build Coastguard Worker           if (file != nullptr) {
267*795d594fSAndroid Build Coastguard Worker             dex::TypeIndex type_idx(VRegC_22c());
268*795d594fSAndroid Build Coastguard Worker             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
269*795d594fSAndroid Build Coastguard Worker                << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
270*795d594fSAndroid Build Coastguard Worker                << " // type@" << type_idx.index_;
271*795d594fSAndroid Build Coastguard Worker             break;
272*795d594fSAndroid Build Coastguard Worker           }
273*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
274*795d594fSAndroid Build Coastguard Worker         case NEW_ARRAY:
275*795d594fSAndroid Build Coastguard Worker           if (file != nullptr) {
276*795d594fSAndroid Build Coastguard Worker             dex::TypeIndex type_idx(VRegC_22c());
277*795d594fSAndroid Build Coastguard Worker             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
278*795d594fSAndroid Build Coastguard Worker                << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
279*795d594fSAndroid Build Coastguard Worker                << " // type@" << type_idx.index_;
280*795d594fSAndroid Build Coastguard Worker             break;
281*795d594fSAndroid Build Coastguard Worker           }
282*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
283*795d594fSAndroid Build Coastguard Worker         default:
284*795d594fSAndroid Build Coastguard Worker           os << StringPrintf("%s v%d, v%d, thing@%d", opcode, VRegA_22c(), VRegB_22c(), VRegC_22c());
285*795d594fSAndroid Build Coastguard Worker           break;
286*795d594fSAndroid Build Coastguard Worker       }
287*795d594fSAndroid Build Coastguard Worker       break;
288*795d594fSAndroid Build Coastguard Worker     }
289*795d594fSAndroid Build Coastguard Worker     case k32x:  os << StringPrintf("%s v%d, v%d", opcode, VRegA_32x(), VRegB_32x()); break;
290*795d594fSAndroid Build Coastguard Worker     case k30t:  os << StringPrintf("%s %+d", opcode, VRegA_30t()); break;
291*795d594fSAndroid Build Coastguard Worker     case k31t:  os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break;
292*795d594fSAndroid Build Coastguard Worker     case k31i:  os << StringPrintf("%s v%d, #%+d", opcode, VRegA_31i(), VRegB_31i()); break;
293*795d594fSAndroid Build Coastguard Worker     case k31c:
294*795d594fSAndroid Build Coastguard Worker       if (Opcode() == CONST_STRING_JUMBO) {
295*795d594fSAndroid Build Coastguard Worker         uint32_t string_idx = VRegB_31c();
296*795d594fSAndroid Build Coastguard Worker         if (file != nullptr) {
297*795d594fSAndroid Build Coastguard Worker           if (string_idx < file->NumStringIds()) {
298*795d594fSAndroid Build Coastguard Worker             os << StringPrintf(
299*795d594fSAndroid Build Coastguard Worker                 "%s v%d, %s // string@%d",
300*795d594fSAndroid Build Coastguard Worker                 opcode,
301*795d594fSAndroid Build Coastguard Worker                 VRegA_31c(),
302*795d594fSAndroid Build Coastguard Worker                 PrintableString(file->GetStringData(dex::StringIndex(string_idx))).c_str(),
303*795d594fSAndroid Build Coastguard Worker                 string_idx);
304*795d594fSAndroid Build Coastguard Worker           } else {
305*795d594fSAndroid Build Coastguard Worker             os << StringPrintf("%s v%d, <<invalid-string-idx-%d>> // string@%d",
306*795d594fSAndroid Build Coastguard Worker                                opcode,
307*795d594fSAndroid Build Coastguard Worker                                VRegA_31c(),
308*795d594fSAndroid Build Coastguard Worker                                string_idx,
309*795d594fSAndroid Build Coastguard Worker                                string_idx);
310*795d594fSAndroid Build Coastguard Worker           }
311*795d594fSAndroid Build Coastguard Worker         } else {
312*795d594fSAndroid Build Coastguard Worker           os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx);
313*795d594fSAndroid Build Coastguard Worker         }
314*795d594fSAndroid Build Coastguard Worker       } else {
315*795d594fSAndroid Build Coastguard Worker         os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break;
316*795d594fSAndroid Build Coastguard Worker       }
317*795d594fSAndroid Build Coastguard Worker       break;
318*795d594fSAndroid Build Coastguard Worker     case k35c: {
319*795d594fSAndroid Build Coastguard Worker       uint32_t arg[kMaxVarArgRegs];
320*795d594fSAndroid Build Coastguard Worker       GetVarArgs(arg);
321*795d594fSAndroid Build Coastguard Worker       auto DumpArgs = [&](size_t count) {
322*795d594fSAndroid Build Coastguard Worker         for (size_t i = 0; i < count; ++i) {
323*795d594fSAndroid Build Coastguard Worker           if (i != 0) {
324*795d594fSAndroid Build Coastguard Worker             os << ", ";
325*795d594fSAndroid Build Coastguard Worker           }
326*795d594fSAndroid Build Coastguard Worker           os << "v" << arg[i];
327*795d594fSAndroid Build Coastguard Worker         }
328*795d594fSAndroid Build Coastguard Worker       };
329*795d594fSAndroid Build Coastguard Worker       switch (Opcode()) {
330*795d594fSAndroid Build Coastguard Worker         case FILLED_NEW_ARRAY:
331*795d594fSAndroid Build Coastguard Worker         {
332*795d594fSAndroid Build Coastguard Worker           os << opcode << " {";
333*795d594fSAndroid Build Coastguard Worker           DumpArgs(VRegA_35c());
334*795d594fSAndroid Build Coastguard Worker           os << "}, type@" << VRegB_35c();
335*795d594fSAndroid Build Coastguard Worker         }
336*795d594fSAndroid Build Coastguard Worker         break;
337*795d594fSAndroid Build Coastguard Worker 
338*795d594fSAndroid Build Coastguard Worker         case INVOKE_VIRTUAL:
339*795d594fSAndroid Build Coastguard Worker         case INVOKE_SUPER:
340*795d594fSAndroid Build Coastguard Worker         case INVOKE_DIRECT:
341*795d594fSAndroid Build Coastguard Worker         case INVOKE_STATIC:
342*795d594fSAndroid Build Coastguard Worker         case INVOKE_INTERFACE:
343*795d594fSAndroid Build Coastguard Worker           if (file != nullptr) {
344*795d594fSAndroid Build Coastguard Worker             os << opcode << " {";
345*795d594fSAndroid Build Coastguard Worker             uint32_t method_idx = VRegB_35c();
346*795d594fSAndroid Build Coastguard Worker             DumpArgs(VRegA_35c());
347*795d594fSAndroid Build Coastguard Worker             os << "}, " << file->PrettyMethod(method_idx) << " // method@" << method_idx;
348*795d594fSAndroid Build Coastguard Worker             break;
349*795d594fSAndroid Build Coastguard Worker           }
350*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
351*795d594fSAndroid Build Coastguard Worker         case INVOKE_CUSTOM:
352*795d594fSAndroid Build Coastguard Worker           if (file != nullptr) {
353*795d594fSAndroid Build Coastguard Worker             os << opcode << " {";
354*795d594fSAndroid Build Coastguard Worker             uint32_t call_site_idx = VRegB_35c();
355*795d594fSAndroid Build Coastguard Worker             DumpArgs(VRegA_35c());
356*795d594fSAndroid Build Coastguard Worker             os << "},  // call_site@" << call_site_idx;
357*795d594fSAndroid Build Coastguard Worker             break;
358*795d594fSAndroid Build Coastguard Worker           }
359*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
360*795d594fSAndroid Build Coastguard Worker         default:
361*795d594fSAndroid Build Coastguard Worker           os << opcode << " {";
362*795d594fSAndroid Build Coastguard Worker           DumpArgs(VRegA_35c());
363*795d594fSAndroid Build Coastguard Worker           os << "}, thing@" << VRegB_35c();
364*795d594fSAndroid Build Coastguard Worker           break;
365*795d594fSAndroid Build Coastguard Worker       }
366*795d594fSAndroid Build Coastguard Worker       break;
367*795d594fSAndroid Build Coastguard Worker     }
368*795d594fSAndroid Build Coastguard Worker     case k3rc: {
369*795d594fSAndroid Build Coastguard Worker       uint16_t first_reg = VRegC_3rc();
370*795d594fSAndroid Build Coastguard Worker       uint16_t last_reg =  VRegC_3rc() + VRegA_3rc() - 1;
371*795d594fSAndroid Build Coastguard Worker       switch (Opcode()) {
372*795d594fSAndroid Build Coastguard Worker         case INVOKE_VIRTUAL_RANGE:
373*795d594fSAndroid Build Coastguard Worker         case INVOKE_SUPER_RANGE:
374*795d594fSAndroid Build Coastguard Worker         case INVOKE_DIRECT_RANGE:
375*795d594fSAndroid Build Coastguard Worker         case INVOKE_STATIC_RANGE:
376*795d594fSAndroid Build Coastguard Worker         case INVOKE_INTERFACE_RANGE:
377*795d594fSAndroid Build Coastguard Worker           if (file != nullptr) {
378*795d594fSAndroid Build Coastguard Worker             uint32_t method_idx = VRegB_3rc();
379*795d594fSAndroid Build Coastguard Worker             os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
380*795d594fSAndroid Build Coastguard Worker                << file->PrettyMethod(method_idx) << " // method@" << method_idx;
381*795d594fSAndroid Build Coastguard Worker             break;
382*795d594fSAndroid Build Coastguard Worker           }
383*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
384*795d594fSAndroid Build Coastguard Worker         case INVOKE_CUSTOM_RANGE:
385*795d594fSAndroid Build Coastguard Worker           if (file != nullptr) {
386*795d594fSAndroid Build Coastguard Worker             uint32_t call_site_idx = VRegB_3rc();
387*795d594fSAndroid Build Coastguard Worker             os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
388*795d594fSAndroid Build Coastguard Worker                << "// call_site@" << call_site_idx;
389*795d594fSAndroid Build Coastguard Worker             break;
390*795d594fSAndroid Build Coastguard Worker           }
391*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
392*795d594fSAndroid Build Coastguard Worker         default:
393*795d594fSAndroid Build Coastguard Worker           os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
394*795d594fSAndroid Build Coastguard Worker              << "thing@" << VRegB_3rc();
395*795d594fSAndroid Build Coastguard Worker           break;
396*795d594fSAndroid Build Coastguard Worker       }
397*795d594fSAndroid Build Coastguard Worker       break;
398*795d594fSAndroid Build Coastguard Worker     }
399*795d594fSAndroid Build Coastguard Worker     case k45cc: {
400*795d594fSAndroid Build Coastguard Worker       uint32_t arg[kMaxVarArgRegs];
401*795d594fSAndroid Build Coastguard Worker       GetVarArgs(arg);
402*795d594fSAndroid Build Coastguard Worker       uint16_t method_idx = VRegB_45cc();
403*795d594fSAndroid Build Coastguard Worker       dex::ProtoIndex proto_idx(VRegH_45cc());
404*795d594fSAndroid Build Coastguard Worker       os << opcode << " {";
405*795d594fSAndroid Build Coastguard Worker       for (uint32_t i = 0; i < VRegA_45cc(); ++i) {
406*795d594fSAndroid Build Coastguard Worker         if (i != 0) {
407*795d594fSAndroid Build Coastguard Worker           os << ", ";
408*795d594fSAndroid Build Coastguard Worker         }
409*795d594fSAndroid Build Coastguard Worker         os << "v" << arg[i];
410*795d594fSAndroid Build Coastguard Worker       }
411*795d594fSAndroid Build Coastguard Worker       os << "}";
412*795d594fSAndroid Build Coastguard Worker       if (file != nullptr) {
413*795d594fSAndroid Build Coastguard Worker         os << ", " << file->PrettyMethod(method_idx)
414*795d594fSAndroid Build Coastguard Worker            << ", " << file->GetShorty(proto_idx)
415*795d594fSAndroid Build Coastguard Worker            << " // ";
416*795d594fSAndroid Build Coastguard Worker       } else {
417*795d594fSAndroid Build Coastguard Worker         os << ", ";
418*795d594fSAndroid Build Coastguard Worker       }
419*795d594fSAndroid Build Coastguard Worker       os << "method@" << method_idx << ", proto@" << proto_idx;
420*795d594fSAndroid Build Coastguard Worker       break;
421*795d594fSAndroid Build Coastguard Worker     }
422*795d594fSAndroid Build Coastguard Worker     case k4rcc:
423*795d594fSAndroid Build Coastguard Worker       switch (Opcode()) {
424*795d594fSAndroid Build Coastguard Worker         case INVOKE_POLYMORPHIC_RANGE: {
425*795d594fSAndroid Build Coastguard Worker           if (file != nullptr) {
426*795d594fSAndroid Build Coastguard Worker             uint16_t method_idx = VRegB_4rcc();
427*795d594fSAndroid Build Coastguard Worker             dex::ProtoIndex proto_idx(VRegH_4rcc());
428*795d594fSAndroid Build Coastguard Worker             os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc())
429*795d594fSAndroid Build Coastguard Worker                << "}, " << file->PrettyMethod(method_idx)
430*795d594fSAndroid Build Coastguard Worker                << ", " << file->GetShorty(dex::ProtoIndex(proto_idx))
431*795d594fSAndroid Build Coastguard Worker                << " // method@" << method_idx << ", proto@" << proto_idx;
432*795d594fSAndroid Build Coastguard Worker             break;
433*795d594fSAndroid Build Coastguard Worker           }
434*795d594fSAndroid Build Coastguard Worker         }
435*795d594fSAndroid Build Coastguard Worker         FALLTHROUGH_INTENDED;
436*795d594fSAndroid Build Coastguard Worker         default: {
437*795d594fSAndroid Build Coastguard Worker           uint16_t method_idx = VRegB_4rcc();
438*795d594fSAndroid Build Coastguard Worker           dex::ProtoIndex proto_idx(VRegH_4rcc());
439*795d594fSAndroid Build Coastguard Worker           os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc())
440*795d594fSAndroid Build Coastguard Worker              << "}, method@" << method_idx << ", proto@" << proto_idx;
441*795d594fSAndroid Build Coastguard Worker         }
442*795d594fSAndroid Build Coastguard Worker       }
443*795d594fSAndroid Build Coastguard Worker       break;
444*795d594fSAndroid Build Coastguard Worker     case k51l: os << StringPrintf("%s v%d, #%+" PRId64, opcode, VRegA_51l(), VRegB_51l()); break;
445*795d594fSAndroid Build Coastguard Worker     case kInvalidFormat: os << "<invalid-opcode-format>";
446*795d594fSAndroid Build Coastguard Worker   }
447*795d594fSAndroid Build Coastguard Worker   return os.str();
448*795d594fSAndroid Build Coastguard Worker }
449*795d594fSAndroid Build Coastguard Worker 
450*795d594fSAndroid Build Coastguard Worker // Add some checks that ensure the flags make sense. We need a subclass to be in the context of
451*795d594fSAndroid Build Coastguard Worker // Instruction. Otherwise the flags from the instruction list don't work.
452*795d594fSAndroid Build Coastguard Worker struct InstructionStaticAsserts : private Instruction {
453*795d594fSAndroid Build Coastguard Worker   #define IMPLIES(a, b) (!(a) || (b))
454*795d594fSAndroid Build Coastguard Worker 
455*795d594fSAndroid Build Coastguard Worker   #define VAR_ARGS_CHECK(o, c, pname, f, i, a, e, v) \
456*795d594fSAndroid Build Coastguard Worker     static_assert(IMPLIES((f) == k35c || (f) == k45cc, \
457*795d594fSAndroid Build Coastguard Worker                           ((v) & (kVerifyVarArg | kVerifyVarArgNonZero)) != 0), \
458*795d594fSAndroid Build Coastguard Worker                   "Missing var-arg verification");
459*795d594fSAndroid Build Coastguard Worker     DEX_INSTRUCTION_LIST(VAR_ARGS_CHECK)
460*795d594fSAndroid Build Coastguard Worker   #undef VAR_ARGS_CHECK
461*795d594fSAndroid Build Coastguard Worker 
462*795d594fSAndroid Build Coastguard Worker   #define VAR_ARGS_RANGE_CHECK(o, c, pname, f, i, a, e, v) \
463*795d594fSAndroid Build Coastguard Worker     static_assert(IMPLIES((f) == k3rc || (f) == k4rcc, \
464*795d594fSAndroid Build Coastguard Worker                           ((v) & (kVerifyVarArgRange | kVerifyVarArgRangeNonZero)) != 0), \
465*795d594fSAndroid Build Coastguard Worker                   "Missing var-arg verification");
466*795d594fSAndroid Build Coastguard Worker     DEX_INSTRUCTION_LIST(VAR_ARGS_RANGE_CHECK)
467*795d594fSAndroid Build Coastguard Worker   #undef VAR_ARGS_RANGE_CHECK
468*795d594fSAndroid Build Coastguard Worker 
469*795d594fSAndroid Build Coastguard Worker   #define EXPERIMENTAL_CHECK(o, c, pname, f, i, a, e, v) \
470*795d594fSAndroid Build Coastguard Worker     static_assert(kHaveExperimentalInstructions || (((a) & kExperimental) == 0), \
471*795d594fSAndroid Build Coastguard Worker                   "Unexpected experimental instruction.");
472*795d594fSAndroid Build Coastguard Worker   DEX_INSTRUCTION_LIST(EXPERIMENTAL_CHECK)
473*795d594fSAndroid Build Coastguard Worker   #undef EXPERIMENTAL_CHECK
474*795d594fSAndroid Build Coastguard Worker };
475*795d594fSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,Instruction::Code code)476*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, Instruction::Code code) {
477*795d594fSAndroid Build Coastguard Worker   return os << Instruction::Name(code);
478*795d594fSAndroid Build Coastguard Worker }
479*795d594fSAndroid Build Coastguard Worker 
GetOperand(size_t operand_index) const480*795d594fSAndroid Build Coastguard Worker uint32_t RangeInstructionOperands::GetOperand(size_t operand_index) const {
481*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(operand_index, GetNumberOfOperands());
482*795d594fSAndroid Build Coastguard Worker   return first_operand_ + operand_index;
483*795d594fSAndroid Build Coastguard Worker }
484*795d594fSAndroid Build Coastguard Worker 
GetOperand(size_t operand_index) const485*795d594fSAndroid Build Coastguard Worker uint32_t VarArgsInstructionOperands::GetOperand(size_t operand_index) const {
486*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(operand_index, GetNumberOfOperands());
487*795d594fSAndroid Build Coastguard Worker   return operands_[operand_index];
488*795d594fSAndroid Build Coastguard Worker }
489*795d594fSAndroid Build Coastguard Worker 
GetOperand(size_t operand_index) const490*795d594fSAndroid Build Coastguard Worker uint32_t NoReceiverInstructionOperands::GetOperand(size_t operand_index) const {
491*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(GetNumberOfOperands(), inner_->GetNumberOfOperands());
492*795d594fSAndroid Build Coastguard Worker   // The receiver is the first operand and since we're skipping it, we need to
493*795d594fSAndroid Build Coastguard Worker   // add 1 to the operand_index.
494*795d594fSAndroid Build Coastguard Worker   return inner_->GetOperand(operand_index + 1);
495*795d594fSAndroid Build Coastguard Worker }
496*795d594fSAndroid Build Coastguard Worker 
497*795d594fSAndroid Build Coastguard Worker }  // namespace art
498