1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "dex_instruction-inl.h" 18 19 #include "dex_file-inl.h" 20 #include "utils.h" 21 #include <iomanip> 22 23 namespace art { 24 25 const char* const Instruction::kInstructionNames[] = { 26 #define INSTRUCTION_NAME(o, c, pname, f, r, i, a, v) pname, 27 #include "dex_instruction_list.h" 28 DEX_INSTRUCTION_LIST(INSTRUCTION_NAME) 29 #undef DEX_INSTRUCTION_LIST 30 #undef INSTRUCTION_NAME 31 }; 32 33 Instruction::Format const Instruction::kInstructionFormats[] = { 34 #define INSTRUCTION_FORMAT(o, c, p, format, r, i, a, v) format, 35 #include "dex_instruction_list.h" 36 DEX_INSTRUCTION_LIST(INSTRUCTION_FORMAT) 37 #undef DEX_INSTRUCTION_LIST 38 #undef INSTRUCTION_FORMAT 39 }; 40 41 int const Instruction::kInstructionFlags[] = { 42 #define INSTRUCTION_FLAGS(o, c, p, f, r, i, flags, v) flags, 43 #include "dex_instruction_list.h" 44 DEX_INSTRUCTION_LIST(INSTRUCTION_FLAGS) 45 #undef DEX_INSTRUCTION_LIST 46 #undef INSTRUCTION_FLAGS 47 }; 48 49 int const Instruction::kInstructionVerifyFlags[] = { 50 #define INSTRUCTION_VERIFY_FLAGS(o, c, p, f, r, i, a, vflags) vflags, 51 #include "dex_instruction_list.h" 52 DEX_INSTRUCTION_LIST(INSTRUCTION_VERIFY_FLAGS) 53 #undef DEX_INSTRUCTION_LIST 54 #undef INSTRUCTION_VERIFY_FLAGS 55 }; 56 57 int const Instruction::kInstructionSizeInCodeUnits[] = { 58 #define INSTRUCTION_SIZE(opcode, c, p, format, r, i, a, v) \ 59 ((opcode == NOP) ? -1 : \ 60 ((format >= k10x) && (format <= k10t)) ? 1 : \ 61 ((format >= k20t) && (format <= k22c)) ? 2 : \ 62 ((format >= k32x) && (format <= k3rc)) ? 3 : \ 63 (format == k51l) ? 5 : -1), 64 #include "dex_instruction_list.h" 65 DEX_INSTRUCTION_LIST(INSTRUCTION_SIZE) 66 #undef DEX_INSTRUCTION_LIST 67 #undef INSTRUCTION_SIZE 68 }; 69 70 /* 71 * Handy macros for helping decode instructions. 72 */ 73 #define FETCH(_offset) (insns[(_offset)]) 74 #define FETCH_uint32(_offset) (fetch_uint32_impl((_offset), insns)) 75 #define INST_A(_insn) (((uint16_t)(_insn) >> 8) & 0x0f) 76 #define INST_B(_insn) ((uint16_t)(_insn) >> 12) 77 #define INST_AA(_insn) ((_insn) >> 8) 78 79 /* Helper for FETCH_uint32, above. */ 80 static inline uint32_t fetch_uint32_impl(uint32_t offset, const uint16_t* insns) { 81 return insns[offset] | ((uint32_t) insns[offset+1] << 16); 82 } 83 84 85 bool Instruction::HasVRegC() const { 86 switch (FormatOf(Opcode())) { 87 case k23x: return true; 88 case k35c: return true; 89 case k3rc: return true; 90 default: return false; 91 } 92 } 93 94 bool Instruction::HasVRegB() const { 95 switch (FormatOf(Opcode())) { 96 case k12x: return true; 97 case k22b: return true; 98 case k22c: return true; 99 case k22s: return true; 100 case k22t: return true; 101 case k22x: return true; 102 case k23x: return true; 103 case k32x: return true; 104 default: return false; 105 } 106 } 107 108 bool Instruction::HasVRegA() const { 109 switch (FormatOf(Opcode())) { 110 case k11n: return true; 111 case k11x: return true; 112 case k12x: return true; 113 case k21c: return true; 114 case k21h: return true; 115 case k21s: return true; 116 case k21t: return true; 117 case k22b: return true; 118 case k22c: return true; 119 case k22s: return true; 120 case k22t: return true; 121 case k22x: return true; 122 case k23x: return true; 123 case k31c: return true; 124 case k31i: return true; 125 case k31t: return true; 126 case k32x: return true; 127 case k51l: return true; 128 default: return false; 129 } 130 } 131 132 int32_t Instruction::VRegC() const { 133 switch (FormatOf(Opcode())) { 134 case k23x: return VRegC_23x(); 135 case k35c: return VRegC_35c(); 136 case k3rc: return VRegC_3rc(); 137 default: LOG(FATAL) << "Tried to access vC of instruction " << Name() << 138 " which has no C operand."; 139 } 140 return -1; 141 } 142 143 int32_t Instruction::VRegB() const { 144 switch (FormatOf(Opcode())) { 145 case k12x: return VRegB_12x(); 146 case k22b: return VRegB_22b(); 147 case k22c: return VRegB_22c(); 148 case k22s: return VRegB_22s(); 149 case k22t: return VRegB_22t(); 150 case k22x: return VRegB_22x(); 151 case k23x: return VRegB_23x(); 152 case k32x: return VRegB_32x(); 153 default: LOG(FATAL) << "Tried to access vB of instruction " << Name() << 154 " which has no B operand."; 155 } 156 return -1; 157 } 158 159 int32_t Instruction::VRegA() const { 160 switch (FormatOf(Opcode())) { 161 case k11n: return VRegA_11n(); 162 case k11x: return VRegA_11x(); 163 case k12x: return VRegA_12x(); 164 case k21c: return VRegA_21c(); 165 case k21h: return VRegA_21h(); 166 case k21s: return VRegA_21s(); 167 case k21t: return VRegA_21t(); 168 case k22b: return VRegA_22b(); 169 case k22c: return VRegA_22c(); 170 case k22s: return VRegA_22s(); 171 case k22t: return VRegA_22t(); 172 case k22x: return VRegA_22x(); 173 case k23x: return VRegA_23x(); 174 case k31c: return VRegA_31c(); 175 case k31i: return VRegA_31i(); 176 case k31t: return VRegA_31t(); 177 case k32x: return VRegA_32x(); 178 case k51l: return VRegA_51l(); 179 default: LOG(FATAL) << "Tried to access vA of instruction " << Name() << 180 " which has no A operand."; 181 } 182 return -1; 183 } 184 185 int32_t Instruction::GetTargetOffset() const { 186 switch (FormatOf(Opcode())) { 187 // Cases for conditional branches follow. 188 case k22t: return VRegC_22t(); 189 case k21t: return VRegB_21t(); 190 // Cases for unconditional branches follow. 191 case k10t: return VRegA_10t(); 192 case k20t: return VRegA_20t(); 193 case k30t: return VRegA_30t(); 194 default: LOG(FATAL) << "Tried to access the branch offset of an instruction " << Name() << 195 " which does not have a target operand."; 196 } 197 return 0; 198 } 199 200 bool Instruction::CanFlowThrough() const { 201 const uint16_t* insns = reinterpret_cast<const uint16_t*>(this); 202 uint16_t insn = *insns; 203 Code opcode = static_cast<Code>(insn & 0xFF); 204 return FlagsOf(opcode) & Instruction::kContinue; 205 } 206 207 void Instruction::Decode(uint32_t &vA, uint32_t &vB, uint64_t &vB_wide, uint32_t &vC, uint32_t arg[]) const { 208 const uint16_t* insns = reinterpret_cast<const uint16_t*>(this); 209 uint16_t insn = *insns; 210 Code opcode = static_cast<Code>(insn & 0xFF); 211 212 switch (FormatOf(opcode)) { 213 case k10x: // op 214 /* nothing to do; copy the AA bits out for the verifier */ 215 vA = INST_AA(insn); 216 break; 217 case k12x: // op vA, vB 218 vA = INST_A(insn); 219 vB = INST_B(insn); 220 break; 221 case k11n: // op vA, #+B 222 vA = INST_A(insn); 223 vB = (int32_t) (INST_B(insn) << 28) >> 28; // sign extend 4-bit value 224 break; 225 case k11x: // op vAA 226 vA = INST_AA(insn); 227 break; 228 case k10t: // op +AA 229 vA = (int8_t) INST_AA(insn); // sign-extend 8-bit value 230 break; 231 case k20t: // op +AAAA 232 vA = (int16_t) FETCH(1); // sign-extend 16-bit value 233 break; 234 case k21c: // op vAA, thing@BBBB 235 case k22x: // op vAA, vBBBB 236 vA = INST_AA(insn); 237 vB = FETCH(1); 238 break; 239 case k21s: // op vAA, #+BBBB 240 case k21t: // op vAA, +BBBB 241 vA = INST_AA(insn); 242 vB = (int16_t) FETCH(1); // sign-extend 16-bit value 243 break; 244 case k21h: // op vAA, #+BBBB0000[00000000] 245 vA = INST_AA(insn); 246 /* 247 * The value should be treated as right-zero-extended, but we don't 248 * actually do that here. Among other things, we don't know if it's 249 * the top bits of a 32- or 64-bit value. 250 */ 251 vB = FETCH(1); 252 break; 253 case k23x: // op vAA, vBB, vCC 254 vA = INST_AA(insn); 255 vB = FETCH(1) & 0xff; 256 vC = FETCH(1) >> 8; 257 break; 258 case k22b: // op vAA, vBB, #+CC 259 vA = INST_AA(insn); 260 vB = FETCH(1) & 0xff; 261 vC = (int8_t) (FETCH(1) >> 8); // sign-extend 8-bit value 262 break; 263 case k22s: // op vA, vB, #+CCCC 264 case k22t: // op vA, vB, +CCCC 265 vA = INST_A(insn); 266 vB = INST_B(insn); 267 vC = (int16_t) FETCH(1); // sign-extend 16-bit value 268 break; 269 case k22c: // op vA, vB, thing@CCCC 270 vA = INST_A(insn); 271 vB = INST_B(insn); 272 vC = FETCH(1); 273 break; 274 case k30t: // op +AAAAAAAA 275 vA = FETCH_uint32(1); // signed 32-bit value 276 break; 277 case k31t: // op vAA, +BBBBBBBB 278 case k31c: // op vAA, string@BBBBBBBB 279 vA = INST_AA(insn); 280 vB = FETCH_uint32(1); // 32-bit value 281 break; 282 case k32x: // op vAAAA, vBBBB 283 vA = FETCH(1); 284 vB = FETCH(2); 285 break; 286 case k31i: // op vAA, #+BBBBBBBB 287 vA = INST_AA(insn); 288 vB = FETCH_uint32(1); // signed 32-bit value 289 break; 290 case k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB 291 { 292 /* 293 * Note that the fields mentioned in the spec don't appear in 294 * their "usual" positions here compared to most formats. This 295 * was done so that the field names for the argument count and 296 * reference index match between this format and the corresponding 297 * range formats (3rc and friends). 298 * 299 * Bottom line: The argument count is always in vA, and the 300 * method constant (or equivalent) is always in vB. 301 */ 302 uint16_t regList; 303 int count; 304 305 vA = INST_B(insn); // This is labeled A in the spec. 306 vB = FETCH(1); 307 regList = FETCH(2); 308 309 count = vA; 310 311 /* 312 * Copy the argument registers into the arg[] array, and 313 * also copy the first argument (if any) into vC. (The 314 * DecodedInstruction structure doesn't have separate 315 * fields for {vD, vE, vF, vG}, so there's no need to make 316 * copies of those.) Note that cases 5..2 fall through. 317 */ 318 switch (count) { 319 case 5: arg[4] = INST_A(insn); 320 case 4: arg[3] = (regList >> 12) & 0x0f; 321 case 3: arg[2] = (regList >> 8) & 0x0f; 322 case 2: arg[1] = (regList >> 4) & 0x0f; 323 case 1: vC = arg[0] = regList & 0x0f; break; 324 case 0: break; // Valid, but no need to do anything. 325 default: 326 LOG(ERROR) << "Invalid arg count in 35c (" << count << ")"; 327 return; 328 } 329 } 330 break; 331 case k3rc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB 332 vA = INST_AA(insn); 333 vB = FETCH(1); 334 vC = FETCH(2); 335 break; 336 case k51l: // op vAA, #+BBBBBBBBBBBBBBBB 337 vA = INST_AA(insn); 338 vB_wide = FETCH_uint32(1) | ((uint64_t) FETCH_uint32(3) << 32); 339 break; 340 default: 341 LOG(ERROR) << "Can't decode unexpected format " << FormatOf(opcode) << " (op=" << opcode << ")"; 342 return; 343 } 344 } 345 346 size_t Instruction::SizeInCodeUnitsComplexOpcode() const { 347 const uint16_t* insns = reinterpret_cast<const uint16_t*>(this); 348 // Handle special NOP encoded variable length sequences. 349 switch (*insns) { 350 case kPackedSwitchSignature: 351 return (4 + insns[1] * 2); 352 case kSparseSwitchSignature: 353 return (2 + insns[1] * 4); 354 case kArrayDataSignature: { 355 uint16_t element_size = insns[1]; 356 uint32_t length = insns[2] | (((uint32_t)insns[3]) << 16); 357 // The plus 1 is to round up for odd size and width. 358 return (4 + (element_size * length + 1) / 2); 359 } 360 default: 361 if ((*insns & 0xFF) == 0) { 362 return 1; // NOP. 363 } else { 364 LOG(FATAL) << "Unreachable: " << DumpString(NULL); 365 return 0; 366 } 367 } 368 } 369 370 std::string Instruction::DumpHex(size_t code_units) const { 371 size_t inst_length = SizeInCodeUnits(); 372 if (inst_length > code_units) { 373 inst_length = code_units; 374 } 375 std::ostringstream os; 376 const uint16_t* insn = reinterpret_cast<const uint16_t*>(this); 377 for (size_t i = 0; i < inst_length; i++) { 378 os << StringPrintf("0x%04x", insn[i]) << " "; 379 } 380 for (size_t i = inst_length; i < code_units; i++) { 381 os << " "; 382 } 383 return os.str(); 384 } 385 386 std::string Instruction::DumpString(const DexFile* file) const { 387 std::ostringstream os; 388 const char* opcode = kInstructionNames[Opcode()]; 389 switch (FormatOf(Opcode())) { 390 case k10x: os << opcode; break; 391 case k12x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_12x(), VRegB_12x()); break; 392 case k11n: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_11n(), VRegB_11n()); break; 393 case k11x: os << StringPrintf("%s v%d", opcode, VRegA_11x()); break; 394 case k10t: os << StringPrintf("%s %+d", opcode, VRegA_10t()); break; 395 case k20t: os << StringPrintf("%s %+d", opcode, VRegA_20t()); break; 396 case k22x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_22x(), VRegB_22x()); break; 397 case k21t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_21t(), VRegB_21t()); break; 398 case k21s: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_21s(), VRegB_21s()); break; 399 case k21h: { 400 // op vAA, #+BBBB0000[00000000] 401 if (Opcode() == CONST_HIGH16) { 402 uint32_t value = VRegB_21h() << 16; 403 os << StringPrintf("%s v%d, #int %+d // 0x%x", opcode, VRegA_21h(), value, value); 404 } else { 405 uint64_t value = static_cast<uint64_t>(VRegB_21h()) << 48; 406 os << StringPrintf("%s v%d, #long %+lld // 0x%llx", opcode, VRegA_21h(), value, value); 407 } 408 } 409 break; 410 case k21c: { 411 switch (Opcode()) { 412 case CONST_STRING: 413 if (file != NULL) { 414 uint32_t string_idx = VRegB_21c(); 415 os << StringPrintf("const-string v%d, %s // string@%d", VRegA_21c(), 416 PrintableString(file->StringDataByIdx(string_idx)).c_str(), string_idx); 417 break; 418 } // else fall-through 419 case CHECK_CAST: 420 case CONST_CLASS: 421 case NEW_INSTANCE: 422 if (file != NULL) { 423 uint32_t type_idx = VRegB_21c(); 424 os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyType(type_idx, *file) 425 << " // type@" << type_idx; 426 break; 427 } // else fall-through 428 case SGET: 429 case SGET_WIDE: 430 case SGET_OBJECT: 431 case SGET_BOOLEAN: 432 case SGET_BYTE: 433 case SGET_CHAR: 434 case SGET_SHORT: 435 if (file != NULL) { 436 uint32_t field_idx = VRegB_21c(); 437 os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true) 438 << " // field@" << field_idx; 439 break; 440 } // else fall-through 441 case SPUT: 442 case SPUT_WIDE: 443 case SPUT_OBJECT: 444 case SPUT_BOOLEAN: 445 case SPUT_BYTE: 446 case SPUT_CHAR: 447 case SPUT_SHORT: 448 if (file != NULL) { 449 uint32_t field_idx = VRegB_21c(); 450 os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true) 451 << " // field@" << field_idx; 452 break; 453 } // else fall-through 454 default: 455 os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c()); 456 break; 457 } 458 break; 459 } 460 case k23x: os << StringPrintf("%s v%d, v%d, v%d", opcode, VRegA_23x(), VRegB_23x(), VRegC_23x()); break; 461 case k22b: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22b(), VRegB_22b(), VRegC_22b()); break; 462 case k22t: os << StringPrintf("%s v%d, v%d, %+d", opcode, VRegA_22t(), VRegB_22t(), VRegC_22t()); break; 463 case k22s: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22s(), VRegB_22s(), VRegC_22s()); break; 464 case k22c: { 465 switch (Opcode()) { 466 case IGET: 467 case IGET_WIDE: 468 case IGET_OBJECT: 469 case IGET_BOOLEAN: 470 case IGET_BYTE: 471 case IGET_CHAR: 472 case IGET_SHORT: 473 if (file != NULL) { 474 uint32_t field_idx = VRegC_22c(); 475 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 476 << PrettyField(field_idx, *file, true) << " // field@" << field_idx; 477 break; 478 } // else fall-through 479 case IGET_QUICK: 480 case IGET_OBJECT_QUICK: 481 if (file != NULL) { 482 uint32_t field_idx = VRegC_22c(); 483 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 484 << "// offset@" << field_idx; 485 break; 486 } // else fall-through 487 case IPUT: 488 case IPUT_WIDE: 489 case IPUT_OBJECT: 490 case IPUT_BOOLEAN: 491 case IPUT_BYTE: 492 case IPUT_CHAR: 493 case IPUT_SHORT: 494 if (file != NULL) { 495 uint32_t field_idx = VRegC_22c(); 496 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 497 << PrettyField(field_idx, *file, true) << " // field@" << field_idx; 498 break; 499 } // else fall-through 500 case IPUT_QUICK: 501 case IPUT_OBJECT_QUICK: 502 if (file != NULL) { 503 uint32_t field_idx = VRegC_22c(); 504 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 505 << "// offset@" << field_idx; 506 break; 507 } // else fall-through 508 case INSTANCE_OF: 509 if (file != NULL) { 510 uint32_t type_idx = VRegC_22c(); 511 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 512 << PrettyType(type_idx, *file) << " // type@" << type_idx; 513 break; 514 } 515 case NEW_ARRAY: 516 if (file != NULL) { 517 uint32_t type_idx = VRegC_22c(); 518 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 519 << PrettyType(type_idx, *file) << " // type@" << type_idx; 520 break; 521 } // else fall-through 522 default: 523 os << StringPrintf("%s v%d, v%d, thing@%d", opcode, VRegA_22c(), VRegB_22c(), VRegC_22c()); 524 break; 525 } 526 break; 527 } 528 case k32x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_32x(), VRegB_32x()); break; 529 case k30t: os << StringPrintf("%s %+d", opcode, VRegA_30t()); break; 530 case k31t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break; 531 case k31i: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_31i(), VRegB_31i()); break; 532 case k31c: 533 if (Opcode() == CONST_STRING_JUMBO) { 534 uint32_t string_idx = VRegB_31c(); 535 if (file != NULL) { 536 os << StringPrintf("%s v%d, %s // string@%d", opcode, VRegA_31c(), 537 PrintableString(file->StringDataByIdx(string_idx)).c_str(), 538 string_idx); 539 } else { 540 os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx); 541 } 542 } else { 543 os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break; 544 } 545 break; 546 case k35c: { 547 uint32_t arg[5]; 548 GetArgs(arg); 549 switch (Opcode()) { 550 case INVOKE_VIRTUAL: 551 case INVOKE_SUPER: 552 case INVOKE_DIRECT: 553 case INVOKE_STATIC: 554 case INVOKE_INTERFACE: 555 if (file != NULL) { 556 os << opcode << " {"; 557 uint32_t method_idx = VRegB_35c(); 558 for (size_t i = 0; i < VRegA_35c(); ++i) { 559 if (i != 0) { 560 os << ", "; 561 } 562 os << "v" << arg[i]; 563 } 564 os << "}, " << PrettyMethod(method_idx, *file) << " // method@" << method_idx; 565 break; 566 } // else fall-through 567 case INVOKE_VIRTUAL_QUICK: 568 if (file != NULL) { 569 os << opcode << " {"; 570 uint32_t method_idx = VRegB_35c(); 571 for (size_t i = 0; i < VRegA_35c(); ++i) { 572 if (i != 0) { 573 os << ", "; 574 } 575 os << "v" << arg[i]; 576 } 577 os << "}, // vtable@" << method_idx; 578 break; 579 } // else fall-through 580 default: 581 os << opcode << " {v" << arg[0] << ", v" << arg[1] << ", v" << arg[2] 582 << ", v" << arg[3] << ", v" << arg[4] << "}, thing@" << VRegB_35c(); 583 break; 584 } 585 break; 586 } 587 case k3rc: { 588 switch (Opcode()) { 589 case INVOKE_VIRTUAL_RANGE: 590 case INVOKE_SUPER_RANGE: 591 case INVOKE_DIRECT_RANGE: 592 case INVOKE_STATIC_RANGE: 593 case INVOKE_INTERFACE_RANGE: 594 if (file != NULL) { 595 uint32_t method_idx = VRegB_3rc(); 596 os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1)) 597 << PrettyMethod(method_idx, *file) << " // method@" << method_idx; 598 break; 599 } // else fall-through 600 case INVOKE_VIRTUAL_RANGE_QUICK: 601 if (file != NULL) { 602 uint32_t method_idx = VRegB_3rc(); 603 os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1)) 604 << "// vtable@" << method_idx; 605 break; 606 } // else fall-through 607 default: 608 os << StringPrintf("%s, {v%d .. v%d}, thing@%d", opcode, VRegC_3rc(), 609 (VRegC_3rc() + VRegA_3rc() - 1), VRegB_3rc()); 610 break; 611 } 612 break; 613 } 614 case k51l: os << StringPrintf("%s v%d, #%+lld", opcode, VRegA_51l(), VRegB_51l()); break; 615 default: os << " unknown format (" << DumpHex(5) << ")"; break; 616 } 617 return os.str(); 618 } 619 620 std::ostream& operator<<(std::ostream& os, const Instruction::Code& code) { 621 return os << Instruction::Name(code); 622 } 623 624 } // namespace art 625