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