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