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 #ifndef ART_RUNTIME_DEX_INSTRUCTION_H_ 18 #define ART_RUNTIME_DEX_INSTRUCTION_H_ 19 20 #include "base/logging.h" 21 #include "base/macros.h" 22 #include "globals.h" 23 24 typedef uint8_t uint4_t; 25 typedef int8_t int4_t; 26 27 namespace art { 28 29 class DexFile; 30 31 enum { 32 kNumPackedOpcodes = 0x100 33 }; 34 35 class Instruction { 36 public: 37 // NOP-encoded switch-statement signatures. 38 enum Signatures { 39 kPackedSwitchSignature = 0x0100, 40 kSparseSwitchSignature = 0x0200, 41 kArrayDataSignature = 0x0300, 42 }; 43 44 struct PACKED(4) PackedSwitchPayload { 45 const uint16_t ident; 46 const uint16_t case_count; 47 const int32_t first_key; 48 const int32_t targets[]; 49 50 private: 51 DISALLOW_COPY_AND_ASSIGN(PackedSwitchPayload); 52 }; 53 54 struct PACKED(4) SparseSwitchPayload { 55 const uint16_t ident; 56 const uint16_t case_count; 57 const int32_t keys_and_targets[]; 58 59 public: 60 const int32_t* GetKeys() const { 61 return keys_and_targets; 62 } 63 64 const int32_t* GetTargets() const { 65 return keys_and_targets + case_count; 66 } 67 68 private: 69 DISALLOW_COPY_AND_ASSIGN(SparseSwitchPayload); 70 }; 71 72 struct PACKED(4) ArrayDataPayload { 73 const uint16_t ident; 74 const uint16_t element_width; 75 const uint32_t element_count; 76 const uint8_t data[]; 77 78 private: 79 DISALLOW_COPY_AND_ASSIGN(ArrayDataPayload); 80 }; 81 82 enum Code { // private marker to avoid generate-operator-out.py from processing. 83 #define INSTRUCTION_ENUM(opcode, cname, p, f, r, i, a, v) cname = opcode, 84 #include "dex_instruction_list.h" 85 DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM) 86 #undef DEX_INSTRUCTION_LIST 87 #undef INSTRUCTION_ENUM 88 RSUB_INT_LIT16 = RSUB_INT, 89 }; 90 91 enum Format { 92 k10x, // op 93 k12x, // op vA, vB 94 k11n, // op vA, #+B 95 k11x, // op vAA 96 k10t, // op +AA 97 k20t, // op +AAAA 98 k22x, // op vAA, vBBBB 99 k21t, // op vAA, +BBBB 100 k21s, // op vAA, #+BBBB 101 k21h, // op vAA, #+BBBB00000[00000000] 102 k21c, // op vAA, thing@BBBB 103 k23x, // op vAA, vBB, vCC 104 k22b, // op vAA, vBB, #+CC 105 k22t, // op vA, vB, +CCCC 106 k22s, // op vA, vB, #+CCCC 107 k22c, // op vA, vB, thing@CCCC 108 k25x, // op vC, {vD, vE, vF, vG} (B: count) 109 k32x, // op vAAAA, vBBBB 110 k30t, // op +AAAAAAAA 111 k31t, // op vAA, +BBBBBBBB 112 k31i, // op vAA, #+BBBBBBBB 113 k31c, // op vAA, thing@BBBBBBBB 114 k35c, // op {vC, vD, vE, vF, vG}, thing@BBBB (B: count, A: vG) 115 k3rc, // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB 116 k51l, // op vAA, #+BBBBBBBBBBBBBBBB 117 }; 118 119 enum IndexType { 120 kIndexUnknown = 0, 121 kIndexNone, // has no index 122 kIndexTypeRef, // type reference index 123 kIndexStringRef, // string reference index 124 kIndexMethodRef, // method reference index 125 kIndexFieldRef, // field reference index 126 kIndexFieldOffset, // field offset (for static linked fields) 127 kIndexVtableOffset // vtable offset (for static linked methods) 128 }; 129 130 enum Flags { 131 kBranch = 0x0000001, // conditional or unconditional branch 132 kContinue = 0x0000002, // flow can continue to next statement 133 kSwitch = 0x0000004, // switch statement 134 kThrow = 0x0000008, // could cause an exception to be thrown 135 kReturn = 0x0000010, // returns, no additional statements 136 kInvoke = 0x0000020, // a flavor of invoke 137 kUnconditional = 0x0000040, // unconditional branch 138 kAdd = 0x0000080, // addition 139 kSubtract = 0x0000100, // subtract 140 kMultiply = 0x0000200, // multiply 141 kDivide = 0x0000400, // division 142 kRemainder = 0x0000800, // remainder 143 kAnd = 0x0001000, // and 144 kOr = 0x0002000, // or 145 kXor = 0x0004000, // xor 146 kShl = 0x0008000, // shl 147 kShr = 0x0010000, // shr 148 kUshr = 0x0020000, // ushr 149 kCast = 0x0040000, // cast 150 kStore = 0x0080000, // store opcode 151 kLoad = 0x0100000, // load opcode 152 kClobber = 0x0200000, // clobbers memory in a big way (not just a write) 153 kRegCFieldOrConstant = 0x0400000, // is the third virtual register a field or literal constant (vC) 154 kRegBFieldOrConstant = 0x0800000, // is the second virtual register a field or literal constant (vB) 155 kExperimental = 0x1000000, // is an experimental opcode 156 }; 157 158 enum VerifyFlag { 159 kVerifyNone = 0x000000, 160 kVerifyRegA = 0x000001, 161 kVerifyRegAWide = 0x000002, 162 kVerifyRegB = 0x000004, 163 kVerifyRegBField = 0x000008, 164 kVerifyRegBMethod = 0x000010, 165 kVerifyRegBNewInstance = 0x000020, 166 kVerifyRegBString = 0x000040, 167 kVerifyRegBType = 0x000080, 168 kVerifyRegBWide = 0x000100, 169 kVerifyRegC = 0x000200, 170 kVerifyRegCField = 0x000400, 171 kVerifyRegCNewArray = 0x000800, 172 kVerifyRegCType = 0x001000, 173 kVerifyRegCWide = 0x002000, 174 kVerifyArrayData = 0x004000, 175 kVerifyBranchTarget = 0x008000, 176 kVerifySwitchTargets = 0x010000, 177 kVerifyVarArg = 0x020000, 178 kVerifyVarArgNonZero = 0x040000, 179 kVerifyVarArgRange = 0x080000, 180 kVerifyVarArgRangeNonZero = 0x100000, 181 kVerifyRuntimeOnly = 0x200000, 182 kVerifyError = 0x400000, 183 kVerifyRegCString = 0x800000, 184 }; 185 186 static constexpr uint32_t kMaxVarArgRegs = 5; 187 static constexpr uint32_t kMaxVarArgRegs25x = 6; // lambdas are 2 registers. 188 static constexpr uint32_t kLambdaVirtualRegisterWidth = 2; 189 190 // Returns the size (in 2 byte code units) of this instruction. 191 size_t SizeInCodeUnits() const { 192 int result = kInstructionSizeInCodeUnits[Opcode()]; 193 if (UNLIKELY(result < 0)) { 194 return SizeInCodeUnitsComplexOpcode(); 195 } else { 196 return static_cast<size_t>(result); 197 } 198 } 199 200 // Reads an instruction out of the stream at the specified address. 201 static const Instruction* At(const uint16_t* code) { 202 DCHECK(code != nullptr); 203 return reinterpret_cast<const Instruction*>(code); 204 } 205 206 // Reads an instruction out of the stream from the current address plus an offset. 207 const Instruction* RelativeAt(int32_t offset) const WARN_UNUSED { 208 return At(reinterpret_cast<const uint16_t*>(this) + offset); 209 } 210 211 // Returns a pointer to the next instruction in the stream. 212 const Instruction* Next() const { 213 return RelativeAt(SizeInCodeUnits()); 214 } 215 216 // Returns a pointer to the instruction after this 1xx instruction in the stream. 217 const Instruction* Next_1xx() const { 218 DCHECK(FormatOf(Opcode()) >= k10x && FormatOf(Opcode()) <= k10t); 219 return RelativeAt(1); 220 } 221 222 // Returns a pointer to the instruction after this 2xx instruction in the stream. 223 const Instruction* Next_2xx() const { 224 DCHECK(FormatOf(Opcode()) >= k20t && FormatOf(Opcode()) <= k25x); 225 return RelativeAt(2); 226 } 227 228 // Returns a pointer to the instruction after this 3xx instruction in the stream. 229 const Instruction* Next_3xx() const { 230 DCHECK(FormatOf(Opcode()) >= k32x && FormatOf(Opcode()) <= k3rc); 231 return RelativeAt(3); 232 } 233 234 // Returns a pointer to the instruction after this 51l instruction in the stream. 235 const Instruction* Next_51l() const { 236 DCHECK(FormatOf(Opcode()) == k51l); 237 return RelativeAt(5); 238 } 239 240 // Returns the name of this instruction's opcode. 241 const char* Name() const { 242 return Instruction::Name(Opcode()); 243 } 244 245 // Returns the name of the given opcode. 246 static const char* Name(Code opcode) { 247 return kInstructionNames[opcode]; 248 } 249 250 // VRegA 251 bool HasVRegA() const; 252 ALWAYS_INLINE int32_t VRegA() const; 253 254 int8_t VRegA_10t() const { 255 return VRegA_10t(Fetch16(0)); 256 } 257 uint8_t VRegA_10x() const { 258 return VRegA_10x(Fetch16(0)); 259 } 260 uint4_t VRegA_11n() const { 261 return VRegA_11n(Fetch16(0)); 262 } 263 uint8_t VRegA_11x() const { 264 return VRegA_11x(Fetch16(0)); 265 } 266 uint4_t VRegA_12x() const { 267 return VRegA_12x(Fetch16(0)); 268 } 269 int16_t VRegA_20t() const; 270 uint8_t VRegA_21c() const { 271 return VRegA_21c(Fetch16(0)); 272 } 273 uint8_t VRegA_21h() const { 274 return VRegA_21h(Fetch16(0)); 275 } 276 uint8_t VRegA_21s() const { 277 return VRegA_21s(Fetch16(0)); 278 } 279 uint8_t VRegA_21t() const { 280 return VRegA_21t(Fetch16(0)); 281 } 282 uint8_t VRegA_22b() const { 283 return VRegA_22b(Fetch16(0)); 284 } 285 uint4_t VRegA_22c() const { 286 return VRegA_22c(Fetch16(0)); 287 } 288 uint4_t VRegA_22s() const { 289 return VRegA_22s(Fetch16(0)); 290 } 291 uint4_t VRegA_22t() const { 292 return VRegA_22t(Fetch16(0)); 293 } 294 uint8_t VRegA_22x() const { 295 return VRegA_22x(Fetch16(0)); 296 } 297 uint8_t VRegA_23x() const { 298 return VRegA_23x(Fetch16(0)); 299 } 300 int32_t VRegA_30t() const; 301 uint8_t VRegA_31c() const { 302 return VRegA_31c(Fetch16(0)); 303 } 304 uint8_t VRegA_31i() const { 305 return VRegA_31i(Fetch16(0)); 306 } 307 uint8_t VRegA_31t() const { 308 return VRegA_31t(Fetch16(0)); 309 } 310 uint16_t VRegA_32x() const; 311 uint4_t VRegA_35c() const { 312 return VRegA_35c(Fetch16(0)); 313 } 314 uint8_t VRegA_3rc() const { 315 return VRegA_3rc(Fetch16(0)); 316 } 317 uint8_t VRegA_51l() const { 318 return VRegA_51l(Fetch16(0)); 319 } 320 321 // The following methods return the vA operand for various instruction formats. The "inst_data" 322 // parameter holds the first 16 bits of instruction which the returned value is decoded from. 323 int8_t VRegA_10t(uint16_t inst_data) const; 324 uint8_t VRegA_10x(uint16_t inst_data) const; 325 uint4_t VRegA_11n(uint16_t inst_data) const; 326 uint8_t VRegA_11x(uint16_t inst_data) const; 327 uint4_t VRegA_12x(uint16_t inst_data) const; 328 uint8_t VRegA_21c(uint16_t inst_data) const; 329 uint8_t VRegA_21h(uint16_t inst_data) const; 330 uint8_t VRegA_21s(uint16_t inst_data) const; 331 uint8_t VRegA_21t(uint16_t inst_data) const; 332 uint8_t VRegA_22b(uint16_t inst_data) const; 333 uint4_t VRegA_22c(uint16_t inst_data) const; 334 uint4_t VRegA_22s(uint16_t inst_data) const; 335 uint4_t VRegA_22t(uint16_t inst_data) const; 336 uint8_t VRegA_22x(uint16_t inst_data) const; 337 uint8_t VRegA_23x(uint16_t inst_data) const; 338 uint8_t VRegA_31c(uint16_t inst_data) const; 339 uint8_t VRegA_31i(uint16_t inst_data) const; 340 uint8_t VRegA_31t(uint16_t inst_data) const; 341 uint4_t VRegA_35c(uint16_t inst_data) const; 342 uint8_t VRegA_3rc(uint16_t inst_data) const; 343 uint8_t VRegA_51l(uint16_t inst_data) const; 344 345 // VRegB 346 bool HasVRegB() const; 347 int32_t VRegB() const; 348 349 bool HasWideVRegB() const; 350 uint64_t WideVRegB() const; 351 352 int4_t VRegB_11n() const { 353 return VRegB_11n(Fetch16(0)); 354 } 355 uint4_t VRegB_12x() const { 356 return VRegB_12x(Fetch16(0)); 357 } 358 uint16_t VRegB_21c() const; 359 uint16_t VRegB_21h() const; 360 int16_t VRegB_21s() const; 361 int16_t VRegB_21t() const; 362 uint8_t VRegB_22b() const; 363 uint4_t VRegB_22c() const { 364 return VRegB_22c(Fetch16(0)); 365 } 366 uint4_t VRegB_22s() const { 367 return VRegB_22s(Fetch16(0)); 368 } 369 uint4_t VRegB_22t() const { 370 return VRegB_22t(Fetch16(0)); 371 } 372 uint16_t VRegB_22x() const; 373 uint8_t VRegB_23x() const; 374 uint4_t VRegB_25x() const; 375 uint32_t VRegB_31c() const; 376 int32_t VRegB_31i() const; 377 int32_t VRegB_31t() const; 378 uint16_t VRegB_32x() const; 379 uint16_t VRegB_35c() const; 380 uint16_t VRegB_3rc() const; 381 uint64_t VRegB_51l() const; // vB_wide 382 383 // The following methods return the vB operand for all instruction formats where it is encoded in 384 // the first 16 bits of instruction. The "inst_data" parameter holds these 16 bits. The returned 385 // value is decoded from it. 386 int4_t VRegB_11n(uint16_t inst_data) const; 387 uint4_t VRegB_12x(uint16_t inst_data) const; 388 uint4_t VRegB_22c(uint16_t inst_data) const; 389 uint4_t VRegB_22s(uint16_t inst_data) const; 390 uint4_t VRegB_22t(uint16_t inst_data) const; 391 392 // VRegC 393 bool HasVRegC() const; 394 int32_t VRegC() const; 395 396 int8_t VRegC_22b() const; 397 uint16_t VRegC_22c() const; 398 int16_t VRegC_22s() const; 399 int16_t VRegC_22t() const; 400 uint8_t VRegC_23x() const; 401 uint4_t VRegC_25x() const; 402 uint4_t VRegC_35c() const; 403 uint16_t VRegC_3rc() const; 404 405 // Fills the given array with the 'arg' array of the instruction. 406 bool HasVarArgs35c() const; 407 bool HasVarArgs25x() const; 408 409 // TODO(iam): Make this name more consistent with GetAllArgs25x by including the opcode format. 410 void GetVarArgs(uint32_t args[kMaxVarArgRegs], uint16_t inst_data) const; 411 void GetVarArgs(uint32_t args[kMaxVarArgRegs]) const { 412 return GetVarArgs(args, Fetch16(0)); 413 } 414 void GetAllArgs25x(uint32_t (&args)[kMaxVarArgRegs25x]) const; 415 416 // Returns the opcode field of the instruction. The given "inst_data" parameter must be the first 417 // 16 bits of instruction. 418 Code Opcode(uint16_t inst_data) const { 419 DCHECK_EQ(inst_data, Fetch16(0)); 420 return static_cast<Code>(inst_data & 0xFF); 421 } 422 423 // Returns the opcode field of the instruction from the first 16 bits of instruction. 424 Code Opcode() const { 425 return Opcode(Fetch16(0)); 426 } 427 428 void SetOpcode(Code opcode) { 429 DCHECK_LT(static_cast<uint16_t>(opcode), 256u); 430 uint16_t* insns = reinterpret_cast<uint16_t*>(this); 431 insns[0] = (insns[0] & 0xff00) | static_cast<uint16_t>(opcode); 432 } 433 434 void SetVRegA_10x(uint8_t val) { 435 DCHECK(FormatOf(Opcode()) == k10x); 436 uint16_t* insns = reinterpret_cast<uint16_t*>(this); 437 insns[0] = (val << 8) | (insns[0] & 0x00ff); 438 } 439 440 void SetVRegB_3rc(uint16_t val) { 441 DCHECK(FormatOf(Opcode()) == k3rc); 442 uint16_t* insns = reinterpret_cast<uint16_t*>(this); 443 insns[1] = val; 444 } 445 446 void SetVRegB_35c(uint16_t val) { 447 DCHECK(FormatOf(Opcode()) == k35c); 448 uint16_t* insns = reinterpret_cast<uint16_t*>(this); 449 insns[1] = val; 450 } 451 452 void SetVRegC_22c(uint16_t val) { 453 DCHECK(FormatOf(Opcode()) == k22c); 454 uint16_t* insns = reinterpret_cast<uint16_t*>(this); 455 insns[1] = val; 456 } 457 458 // Returns the format of the given opcode. 459 static Format FormatOf(Code opcode) { 460 return kInstructionFormats[opcode]; 461 } 462 463 // Returns the index type of the given opcode. 464 static IndexType IndexTypeOf(Code opcode) { 465 return kInstructionIndexTypes[opcode]; 466 } 467 468 // Returns the flags for the given opcode. 469 static int FlagsOf(Code opcode) { 470 return kInstructionFlags[opcode]; 471 } 472 473 // Return the verify flags for the given opcode. 474 static int VerifyFlagsOf(Code opcode) { 475 return kInstructionVerifyFlags[opcode]; 476 } 477 478 // Returns true if this instruction is a branch. 479 bool IsBranch() const { 480 return (kInstructionFlags[Opcode()] & kBranch) != 0; 481 } 482 483 // Returns true if this instruction is a unconditional branch. 484 bool IsUnconditional() const { 485 return (kInstructionFlags[Opcode()] & kUnconditional) != 0; 486 } 487 488 // Returns the branch offset if this instruction is a branch. 489 int32_t GetTargetOffset() const; 490 491 // Returns true if the instruction allows control flow to go to the following instruction. 492 bool CanFlowThrough() const; 493 494 // Returns true if the instruction is a quickened instruction. 495 bool IsQuickened() const { 496 return (kInstructionIndexTypes[Opcode()] == kIndexFieldOffset) || 497 (kInstructionIndexTypes[Opcode()] == kIndexVtableOffset); 498 } 499 500 // Returns true if this instruction is a switch. 501 bool IsSwitch() const { 502 return (kInstructionFlags[Opcode()] & kSwitch) != 0; 503 } 504 505 // Returns true if this instruction can throw. 506 bool IsThrow() const { 507 return (kInstructionFlags[Opcode()] & kThrow) != 0; 508 } 509 510 // Determine if the instruction is any of 'return' instructions. 511 bool IsReturn() const { 512 return (kInstructionFlags[Opcode()] & kReturn) != 0; 513 } 514 515 // Determine if this instruction ends execution of its basic block. 516 bool IsBasicBlockEnd() const { 517 return IsBranch() || IsReturn() || Opcode() == THROW; 518 } 519 520 // Determine if this instruction is an invoke. 521 bool IsInvoke() const { 522 return (kInstructionFlags[Opcode()] & kInvoke) != 0; 523 } 524 525 // Determine if this instruction is experimental. 526 bool IsExperimental() const { 527 return (kInstructionFlags[Opcode()] & kExperimental) != 0; 528 } 529 530 int GetVerifyTypeArgumentA() const { 531 return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegA | kVerifyRegAWide)); 532 } 533 534 int GetVerifyTypeArgumentB() const { 535 return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegB | kVerifyRegBField | 536 kVerifyRegBMethod | kVerifyRegBNewInstance | kVerifyRegBString | kVerifyRegBType | 537 kVerifyRegBWide)); 538 } 539 540 int GetVerifyTypeArgumentC() const { 541 return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegC | kVerifyRegCField | 542 kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide | kVerifyRegCString)); 543 } 544 545 int GetVerifyExtraFlags() const { 546 return (kInstructionVerifyFlags[Opcode()] & (kVerifyArrayData | kVerifyBranchTarget | 547 kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgNonZero | kVerifyVarArgRange | 548 kVerifyVarArgRangeNonZero | kVerifyError)); 549 } 550 551 bool GetVerifyIsRuntimeOnly() const { 552 return (kInstructionVerifyFlags[Opcode()] & kVerifyRuntimeOnly) != 0; 553 } 554 555 // Get the dex PC of this instruction as a offset in code units from the beginning of insns. 556 uint32_t GetDexPc(const uint16_t* insns) const { 557 return (reinterpret_cast<const uint16_t*>(this) - insns); 558 } 559 560 // Dump decoded version of instruction 561 std::string DumpString(const DexFile*) const; 562 563 // Dump code_units worth of this instruction, padding to code_units for shorter instructions 564 std::string DumpHex(size_t code_units) const; 565 566 // Little-endian dump code_units worth of this instruction, padding to code_units for 567 // shorter instructions 568 std::string DumpHexLE(size_t instr_code_units) const; 569 570 uint16_t Fetch16(size_t offset) const { 571 const uint16_t* insns = reinterpret_cast<const uint16_t*>(this); 572 return insns[offset]; 573 } 574 575 private: 576 size_t SizeInCodeUnitsComplexOpcode() const; 577 578 uint32_t Fetch32(size_t offset) const { 579 return (Fetch16(offset) | ((uint32_t) Fetch16(offset + 1) << 16)); 580 } 581 582 uint4_t InstA() const { 583 return InstA(Fetch16(0)); 584 } 585 586 uint4_t InstB() const { 587 return InstB(Fetch16(0)); 588 } 589 590 uint8_t InstAA() const { 591 return InstAA(Fetch16(0)); 592 } 593 594 uint4_t InstA(uint16_t inst_data) const { 595 DCHECK_EQ(inst_data, Fetch16(0)); 596 return static_cast<uint4_t>((inst_data >> 8) & 0x0f); 597 } 598 599 uint4_t InstB(uint16_t inst_data) const { 600 DCHECK_EQ(inst_data, Fetch16(0)); 601 return static_cast<uint4_t>(inst_data >> 12); 602 } 603 604 uint8_t InstAA(uint16_t inst_data) const { 605 DCHECK_EQ(inst_data, Fetch16(0)); 606 return static_cast<uint8_t>(inst_data >> 8); 607 } 608 609 static const char* const kInstructionNames[]; 610 static Format const kInstructionFormats[]; 611 static IndexType const kInstructionIndexTypes[]; 612 static int const kInstructionFlags[]; 613 static int const kInstructionVerifyFlags[]; 614 static int const kInstructionSizeInCodeUnits[]; 615 DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction); 616 }; 617 std::ostream& operator<<(std::ostream& os, const Instruction::Code& code); 618 std::ostream& operator<<(std::ostream& os, const Instruction::Format& format); 619 std::ostream& operator<<(std::ostream& os, const Instruction::Flags& flags); 620 std::ostream& operator<<(std::ostream& os, const Instruction::VerifyFlag& vflags); 621 622 } // namespace art 623 624 #endif // ART_RUNTIME_DEX_INSTRUCTION_H_ 625