Extend the instruction class with instruction attributes.

Change-Id: I52a4f640bd45d1891050876a7a0c031ec3a58974
diff --git a/src/dex_instruction.cc b/src/dex_instruction.cc
index 83ebddc..37585a6 100644
--- a/src/dex_instruction.cc
+++ b/src/dex_instruction.cc
@@ -1,24 +1,94 @@
 // Copyright 2011 Google Inc. All Rights Reserved.
 
-#include "libdex/InstrUtils.h"
-#undef LOG
-#undef LOG_FATAL
-
 #include "src/dex_instruction.h"
 
 namespace art {
 
-size_t Instruction::Size() {
+const char* const Instruction::kInstructionNames[] = {
+#define INSTRUCTION_NAME(o, c, pname, f, r, i, a) pname,
+#include "src/dex_instruction_list.h"
+  DEX_INSTRUCTION_LIST(INSTRUCTION_NAME)
+#undef DEX_INSTRUCTION_LIST
+#undef INSTRUCTION_NAME
+};
+
+Instruction::InstructionFormat const Instruction::kInstructionFormats[] = {
+#define INSTRUCTION_FORMAT(o, c, p, format, r, i, a) format,
+#include "src/dex_instruction_list.h"
+  DEX_INSTRUCTION_LIST(INSTRUCTION_FORMAT)
+#undef DEX_INSTRUCTION_LIST
+#undef INSTRUCTION_FORMAT
+};
+
+int const Instruction::kInstructionFlags[] = {
+#define INSTRUCTION_FLAGS(o, c, p, f, r, i, flags) flags,
+#include "src/dex_instruction_list.h"
+  DEX_INSTRUCTION_LIST(INSTRUCTION_FLAGS)
+#undef DEX_INSTRUCTION_LIST
+#undef INSTRUCTION_FLAGS
+};
+
+size_t Instruction::Size() const {
   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
-  return dexGetWidthFromInstruction(insns) * sizeof(uint16_t);
+  size_t size = 0;
+  if (*insns == kPackedSwitchSignature) {
+    size = 4 + insns[1] * 2;
+  } else if (*insns == kSparseSwitchSignature) {
+    size = 2 + insns[1] * 4;
+  } else if (*insns == kArrayDataSignature) {
+    uint16_t element_size = insns[1];
+    uint32_t length = insns[2] | (((uint32_t)insns[3]) << 16);
+    // The plus 1 is to round up for odd size and width.
+    return 4 + (element_size * length + 1) / 2;
+  } else {
+    switch (Format()) {
+      case k10x:
+      case k12x:
+      case k11n:
+      case k11x:
+      case k10t:
+        size = 1;
+        break;
+      case k20t:
+      case k22x:
+      case k21t:
+      case k21s:
+      case k21h:
+      case k21c:
+      case k23x:
+      case k22b:
+      case k22t:
+      case k22s:
+      case k22c:
+        size = 2;
+        break;
+      case k32x:
+      case k30t:
+      case k31t:
+      case k31i:
+      case k31c:
+      case k35c:
+      case k3rc:
+        size = 3;
+        break;
+      case k51l:
+        size = 5;
+        break;
+      default:
+        LOG(FATAL) << "Unreachable";
+    }
+  }
+  size *= sizeof(uint16_t);
+  return size;
 }
 
-Instruction::Code Instruction::Opcode() {
+Instruction::Code Instruction::Opcode() const {
   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
-  return (Instruction::Code)dexOpcodeFromCodeUnit(*insns);
+  int opcode = *insns & 0xFF;
+  return static_cast<Code>(opcode);
 }
 
-const Instruction* Instruction::Next() {
+const Instruction* Instruction::Next() const {
   size_t current_size = Size();
   const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
   return reinterpret_cast<const Instruction*>(ptr + current_size);
diff --git a/src/dex_instruction.h b/src/dex_instruction.h
index b233ad5..f1bb7bf 100644
--- a/src/dex_instruction.h
+++ b/src/dex_instruction.h
@@ -11,22 +11,71 @@
 
 class Instruction {
  public:
+  // NOP-encoded switch-statement signatures.
+  enum {
+    kPackedSwitchSignature = 0x0100,
+    kSparseSwitchSignature = 0x0200,
+    kArrayDataSignature = 0x0300
+  };
+
   enum Code {
-#define INSTRUCTION_ENUM(cname, opcode) cname = opcode,
+#define INSTRUCTION_ENUM(opcode, cname, p, f, r, i, a) cname = opcode,
 #include "src/dex_instruction_list.h"
     DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM)
 #undef DEX_INSTRUCTION_LIST
 #undef INSTRUCTION_ENUM
   };
 
+  enum InstructionFormat {
+    k10x,  // op
+    k12x,  // op vA, vB
+    k11n,  // op vA, #+B
+    k11x,  // op vAA
+    k10t,  // op +AA
+    k20t,  // op +AAAA
+    k22x,  // op vAA, vBBBB
+    k21t,  // op vAA, +BBBB
+    k21s,  // op vAA, #+BBBB
+    k21h,  // op vAA, #+BBBB00000[00000000]
+    k21c,  // op vAA, thing@BBBB
+    k23x,  // op vAA, vBB, vCC
+    k22b,  // op vAA, vBB, #+CC
+    k22t,  // op vA, vB, +CCCC
+    k22s,  // op vA, vB, #+CCCC
+    k22c,  // op vA, vB, thing@CCCC
+    k32x,  // op vAAAA, vBBBB
+    k30t,  // op +AAAAAAAA
+    k31t,  // op vAA, +BBBBBBBB
+    k31i,  // op vAA, #+BBBBBBBB
+    k31c,  // op vAA, thing@BBBBBBBB
+    k35c,  // op {vC, vD, vE, vF, vG}, thing@BBBB (B: count, A: vG)
+    k3rc,  // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
+    k51l,  // op vAA, #+BBBBBBBBBBBBBBBB
+  };
+
+  enum Flags {
+    kBranch   = 0x01,  // conditional or unconditional branch
+    kContinue = 0x02,  // flow can continue to next statement
+    kSwitch   = 0x04,  // switch statement
+    kThrow    = 0x08,  // could cause an exception to be thrown
+    kReturn   = 0x10,  // returns, no additional statements
+    kInvoke   = 0x20,  // a flavor of invoke
+    // TODO: kUnconditional
+  };
+
   // Returns the size in bytes of this instruction.
-  size_t Size();
+  size_t Size() const;
 
   // Returns a pointer to the next instruction in the stream.
-  const Instruction* Next();
+  const Instruction* Next() const;
+
+  // Name of the instruction.
+  const char* Name() const {
+    return kInstructionNames[Opcode()];
+  }
 
   // Returns the opcode field of the instruction.
-  Code Opcode();
+  Code Opcode() const;
 
   // Reads an instruction out of the stream at the specified address.
   static Instruction* At(byte* code) {
@@ -34,7 +83,35 @@
     return reinterpret_cast<Instruction*>(code);
   }
 
+  // Returns the format of the current instruction.
+  InstructionFormat Format() const {
+    return kInstructionFormats[Opcode()];
+  }
+
+  // Returns true if this instruction is a branch.
+  bool IsBranch() const {
+    return (kInstructionFlags[Opcode()] & kBranch) != 0;
+  }
+
+  // Determine if the instruction is any of 'return' instructions.
+  bool IsReturn() const {
+    return (kInstructionFlags[Opcode()] & kReturn) != 0;
+  }
+
+  // Determine if this instruction ends execution of its basic block.
+  bool IsBasicBlockEnd() const {
+    return IsBranch() || IsReturn() || Opcode() == THROW;
+  }
+
+  // Determine if this instruction is an invoke.
+  bool IsInvoke() const {
+    return (kInstructionFlags[Opcode()] & kInvoke) != 0;
+  }
+
  private:
+  static const char* const kInstructionNames[];
+  static InstructionFormat const kInstructionFormats[];
+  static int const kInstructionFlags[];
   DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction);
 };
 
diff --git a/src/dex_instruction_list.h b/src/dex_instruction_list.h
index 9c626f8..b2c1fa6 100644
--- a/src/dex_instruction_list.h
+++ b/src/dex_instruction_list.h
@@ -1,221 +1,259 @@
 // Copyright 2011 Google Inc. All Rights Reserved.
 
 #define DEX_INSTRUCTION_LIST(V) \
-  V(NOP, 0x0) \
-  V(MOVE, 0x1) \
-  V(MOVE_FROM16, 0x2) \
-  V(MOVE_16, 0x3) \
-  V(MOVE_WIDE, 0x4) \
-  V(MOVE_WIDE_FROM16, 0x5) \
-  V(MOVE_WIDE_16, 0x6) \
-  V(MOVE_OBJECT, 0x7) \
-  V(MOVE_OBJECT_FROM16, 0x8) \
-  V(MOVE_OBJECT_16, 0x9) \
-  V(MOVE_RESULT, 0xA) \
-  V(MOVE_RESULT_WIDE, 0xB) \
-  V(MOVE_RESULT_OBJECT, 0xC) \
-  V(MOVE_EXCEPTION, 0xD) \
-  V(RETURN_VOID, 0xE) \
-  V(RETURN, 0xF) \
-  V(RETURN_WIDE, 0x10) \
-  V(RETURN_OBJECT, 0x11) \
-  V(CONST_4, 0x12) \
-  V(CONST_16, 0x13) \
-  V(CONST, 0x14) \
-  V(CONST_HIGH16, 0x15) \
-  V(CONST_WIDE_16, 0x16) \
-  V(CONST_WIDE_32, 0x17) \
-  V(CONST_WIDE, 0x18) \
-  V(CONST_WIDE_HIGH16, 0x19) \
-  V(CONST_STRING, 0x1A) \
-  V(CONST_STRING_JUMBO, 0x1B) \
-  V(CONST_CLASS, 0x1C) \
-  V(MONITOR_ENTER, 0x1D) \
-  V(MONITOR_EXIT, 0x1E) \
-  V(CHECK_CAST, 0x1F) \
-  V(INSTANCE_OF, 0x20) \
-  V(ARRAY_LENGTH, 0x21) \
-  V(NEW_INSTANCE, 0x22) \
-  V(NEW_ARRAY, 0x23) \
-  V(FILLED_NEW_ARRAY, 0x24) \
-  V(FILLED_NEW_ARRAY_RANGE, 0x25) \
-  V(FILL_ARRAY_DATA, 0x26) \
-  V(THROW, 0x27) \
-  V(GOTO, 0x28) \
-  V(GOTO_16, 0x29) \
-  V(GOTO_32, 0x2A) \
-  V(PACKED_SWITCH, 0x2B) \
-  V(SPARSE_SWITCH, 0x2C) \
-  V(CMPL_FLOAT, 0x2D) \
-  V(CMPG_FLOAT, 0x2E) \
-  V(CMPL_DOUBLE, 0x2F) \
-  V(CMPG_DOUBLE, 0x30) \
-  V(CMP_LONG, 0x31) \
-  V(IF_EQ, 0x32) \
-  V(IF_NE, 0x33) \
-  V(IF_LT, 0x34) \
-  V(IF_GE, 0x35) \
-  V(IF_GT, 0x36) \
-  V(IF_LE, 0x37) \
-  V(IF_EQZ, 0x38) \
-  V(IF_NEZ, 0x39) \
-  V(IF_LTZ, 0x3A) \
-  V(IF_GEZ, 0x3B) \
-  V(IF_GTZ, 0x3C) \
-  V(IF_LEZ, 0x3D) \
-  V(AGET, 0x44) \
-  V(AGET_WIDE, 0x45) \
-  V(AGET_OBJECT, 0x46) \
-  V(AGET_BOOLEAN, 0x47) \
-  V(AGET_BYTE, 0x48) \
-  V(AGET_CHAR, 0x49) \
-  V(AGET_SHORT, 0x4A) \
-  V(APUT, 0x4B) \
-  V(APUT_WIDE, 0x4C) \
-  V(APUT_OBJECT, 0x4D) \
-  V(APUT_BOOLEAN, 0x4E) \
-  V(APUT_BYTE, 0x4F) \
-  V(APUT_CHAR, 0x50) \
-  V(APUT_SHORT, 0x51) \
-  V(IGET, 0x52) \
-  V(IGET_WIDE, 0x53) \
-  V(IGET_OBJECT, 0x54) \
-  V(IGET_BOOLEAN, 0x55) \
-  V(IGET_BYTE, 0x56) \
-  V(IGET_CHAR, 0x57) \
-  V(IGET_SHORT, 0x58) \
-  V(IPUT, 0x59) \
-  V(IPUT_WIDE, 0x5A) \
-  V(IPUT_OBJECT, 0x5B) \
-  V(IPUT_BOOLEAN, 0x5C) \
-  V(IPUT_BYTE, 0x5D) \
-  V(IPUT_CHAR, 0x5E) \
-  V(IPUT_SHORT, 0x5F) \
-  V(SGET, 0x60) \
-  V(SGET_WIDE, 0x61) \
-  V(SGET_OBJECT, 0x62) \
-  V(SGET_BOOLEAN, 0x63) \
-  V(SGET_BYTE, 0x64) \
-  V(SGET_CHAR, 0x65) \
-  V(SGET_SHORT, 0x66) \
-  V(SPUT, 0x67) \
-  V(SPUT_WIDE, 0x68) \
-  V(SPUT_OBJECT, 0x69) \
-  V(SPUT_BOOLEAN, 0x6A) \
-  V(SPUT_BYTE, 0x6B) \
-  V(SPUT_CHAR, 0x6C) \
-  V(SPUT_SHORT, 0x6D) \
-  V(INVOKE_VIRTUAL, 0x6E) \
-  V(INVOKE_SUPER, 0x6F) \
-  V(INVOKE_DIRECT, 0x70) \
-  V(INVOKE_STATIC, 0x71) \
-  V(INVOKE_INTERFACE, 0x72) \
-  V(INVOKE_VIRTUAL_RANGE, 0x74) \
-  V(INVOKE_SUPER_RANGE, 0x75) \
-  V(INVOKE_DIRECT_RANGE, 0x76) \
-  V(INVOKE_STATIC_RANGE, 0x77) \
-  V(INVOKE_INTERFACE_RANGE, 0x78) \
-  V(NEG_INT, 0x7B) \
-  V(NOT_INT, 0x7C) \
-  V(NEG_LONG, 0x7D) \
-  V(NOT_LONG, 0x7E) \
-  V(NEG_FLOAT, 0x7F) \
-  V(NEG_DOUBLE, 0x80) \
-  V(INT_TO_LONG, 0x81) \
-  V(INT_TO_FLOAT, 0x82) \
-  V(INT_TO_DOUBLE, 0x83) \
-  V(LONG_TO_INT, 0x84) \
-  V(LONG_TO_FLOAT, 0x85) \
-  V(LONG_TO_DOUBLE, 0x86) \
-  V(FLOAT_TO_INT, 0x87) \
-  V(FLOAT_TO_LONG, 0x88) \
-  V(FLOAT_TO_DOUBLE, 0x89) \
-  V(DOUBLE_TO_INT, 0x8A) \
-  V(DOUBLE_TO_LONG, 0x8B) \
-  V(DOUBLE_TO_FLOAT, 0x8C) \
-  V(INT_TO_BYTE, 0x8D) \
-  V(INT_TO_CHAR, 0x8E) \
-  V(INT_TO_SHORT, 0x8F) \
-  V(ADD_INT, 0x90) \
-  V(SUB_INT, 0x91) \
-  V(MUL_INT, 0x92) \
-  V(DIV_INT, 0x93) \
-  V(REM_INT, 0x94) \
-  V(AND_INT, 0x95) \
-  V(OR_INT, 0x96) \
-  V(XOR_INT, 0x97) \
-  V(SHL_INT, 0x98) \
-  V(SHR_INT, 0x99) \
-  V(USHR_INT, 0x9A) \
-  V(ADD_LONG, 0x9B) \
-  V(SUB_LONG, 0x9C) \
-  V(MUL_LONG, 0x9D) \
-  V(DIV_LONG, 0x9E) \
-  V(REM_LONG, 0x9F) \
-  V(AND_LONG, 0xA0) \
-  V(OR_LONG, 0xA1) \
-  V(XOR_LONG, 0xA2) \
-  V(SHL_LONG, 0xA3) \
-  V(SHR_LONG, 0xA4) \
-  V(USHR_LONG, 0xA5) \
-  V(ADD_FLOAT, 0xA6) \
-  V(SUB_FLOAT, 0xA7) \
-  V(MUL_FLOAT, 0xA8) \
-  V(DIV_FLOAT, 0xA9) \
-  V(REM_FLOAT, 0xAA) \
-  V(ADD_DOUBLE, 0xAB) \
-  V(SUB_DOUBLE, 0xAC) \
-  V(MUL_DOUBLE, 0xAD) \
-  V(DIV_DOUBLE, 0xAE) \
-  V(REM_DOUBLE, 0xAF) \
-  V(ADD_INT_2ADDR, 0xB0) \
-  V(SUB_INT_2ADDR, 0xB1) \
-  V(MUL_INT_2ADDR, 0xB2) \
-  V(DIV_INT_2ADDR, 0xB3) \
-  V(REM_INT_2ADDR, 0xB4) \
-  V(AND_INT_2ADDR, 0xB5) \
-  V(OR_INT_2ADDR, 0xB6) \
-  V(XOR_INT_2ADDR, 0xB7) \
-  V(SHL_INT_2ADDR, 0xB8) \
-  V(SHR_INT_2ADDR, 0xB9) \
-  V(USHR_INT_2ADDR, 0xBA) \
-  V(ADD_LONG_2ADDR, 0xBB) \
-  V(SUB_LONG_2ADDR, 0xBC) \
-  V(MUL_LONG_2ADDR, 0xBD) \
-  V(DIV_LONG_2ADDR, 0xBE) \
-  V(REM_LONG_2ADDR, 0xBF) \
-  V(AND_LONG_2ADDR, 0xC0) \
-  V(OR_LONG_2ADDR, 0xC1) \
-  V(XOR_LONG_2ADDR, 0xC2) \
-  V(SHL_LONG_2ADDR, 0xC3) \
-  V(SHR_LONG_2ADDR, 0xC4) \
-  V(USHR_LONG_2ADDR, 0xC5) \
-  V(ADD_FLOAT_2ADDR, 0xC6) \
-  V(SUB_FLOAT_2ADDR, 0xC7) \
-  V(MUL_FLOAT_2ADDR, 0xC8) \
-  V(DIV_FLOAT_2ADDR, 0xC9) \
-  V(REM_FLOAT_2ADDR, 0xCA) \
-  V(ADD_DOUBLE_2ADDR, 0xCB) \
-  V(SUB_DOUBLE_2ADDR, 0xCC) \
-  V(MUL_DOUBLE_2ADDR, 0xCD) \
-  V(DIV_DOUBLE_2ADDR, 0xCE) \
-  V(REM_DOUBLE_2ADDR, 0xCF) \
-  V(ADD_INT_LIT16, 0xD0) \
-  V(RSUB_INT, 0xD1) \
-  V(MUL_INT_LIT16, 0xD2) \
-  V(DIV_INT_LIT16, 0xD3) \
-  V(REM_INT_LIT16, 0xD4) \
-  V(AND_INT_LIT16, 0xD5) \
-  V(OR_INT_LIT16, 0xD6) \
-  V(XOR_INT_LIT16, 0xD7) \
-  V(ADD_INT_LIT8, 0xD8) \
-  V(RSUB_INT_LIT8, 0xD9) \
-  V(MUL_INT_LIT8, 0xDA) \
-  V(DIV_INT_LIT8, 0xDB) \
-  V(REM_INT_LIT8, 0xDC) \
-  V(AND_INT_LIT8, 0xDD) \
-  V(OR_INT_LIT8, 0xDE) \
-  V(XOR_INT_LIT8, 0xDF) \
-  V(SHL_INT_LIT8, 0xE0) \
-  V(SHR_INT_LIT8, 0xE1) \
-  V(USHR_INT_LIT8, 0xE2)
+  V(0x00, NOP, "nop", k10x, false, kNone, kContinue) \
+  V(0x01, MOVE, "move", k12x, true, kNone, kContinue) \
+  V(0x02, MOVE_FROM16, "move/from16", k22x, true, kNone, kContinue) \
+  V(0x03, MOVE_16, "move/16", k32x, true, kNone, kContinue) \
+  V(0x04, MOVE_WIDE, "move-wide", k12x, true, kNone, kContinue) \
+  V(0x05, MOVE_WIDE_FROM16, "move-wide/from16", k22x, true, kNone, kContinue) \
+  V(0x06, MOVE_WIDE_16, "move-wide/16", k32x, true, kNone, kContinue) \
+  V(0x07, MOVE_OBJECT, "move-object", k12x, true, kNone, kContinue) \
+  V(0x08, MOVE_OBJECT_FROM16, "move-object/from16", k22x, true, kNone, kContinue) \
+  V(0x09, MOVE_OBJECT_16, "move-object/16", k32x, true, kNone, kContinue) \
+  V(0x0A, MOVE_RESULT, "move-result", k11x, true, kNone, kContinue) \
+  V(0x0B, MOVE_RESULT_WIDE, "move-result-wide", k11x, true, kNone, kContinue) \
+  V(0x0C, MOVE_RESULT_OBJECT, "move-result-object", k11x, true, kNone, kContinue) \
+  V(0x0D, MOVE_EXCEPTION, "move-exception", k11x, true, kNone, kContinue) \
+  V(0x0E, RETURN_VOID, "return-void", k10x, false, kNone, kReturn) \
+  V(0x0F, RETURN, "return", k11x, false, kNone, kReturn) \
+  V(0x10, RETURN_WIDE, "return-wide", k11x, false, kNone, kReturn) \
+  V(0x11, RETURN_OBJECT, "return-object", k11x, false, kNone, kReturn) \
+  V(0x12, CONST_4, "const/4", k11n, true, kNone, kContinue) \
+  V(0x13, CONST_16, "const/16", k21s, true, kNone, kContinue) \
+  V(0x14, CONST, "const", k31i, true, kNone, kContinue) \
+  V(0x15, CONST_HIGH16, "const/high16", k21h, true, kNone, kContinue) \
+  V(0x16, CONST_WIDE_16, "const-wide/16", k21s, true, kNone, kContinue) \
+  V(0x17, CONST_WIDE_32, "const-wide/32", k31i, true, kNone, kContinue) \
+  V(0x18, CONST_WIDE, "const-wide", k51l, true, kNone, kContinue) \
+  V(0x19, CONST_WIDE_HIGH16, "const-wide/high16", k21h, true, kNone, kContinue) \
+  V(0x1A, CONST_STRING, "const-string", k21c, true, kStringRef, kContinue | kThrow) \
+  V(0x1B, CONST_STRING_JUMBO, "const-string/jumbo", k31c, true, kStringRef, kContinue | kThrow) \
+  V(0x1C, CONST_CLASS, "const-class", k21c, true, kTypeRef, kContinue | kThrow) \
+  V(0x1D, MONITOR_ENTER, "monitor-enter", k11x, false, kNone, kContinue | kThrow) \
+  V(0x1E, MONITOR_EXIT, "monitor-exit", k11x, false, kNone, kContinue | kThrow) \
+  V(0x1F, CHECK_CAST, "check-cast", k21c, true, kTypeRef, kContinue | kThrow) \
+  V(0x20, INSTANCE_OF, "instance-of", k22c, true, kTypeRef, kContinue | kThrow) \
+  V(0x21, ARRAY_LENGTH, "array-length", k12x, true, kNone, kContinue | kThrow) \
+  V(0x22, NEW_INSTANCE, "new-instance", k21c, true, kTypeRef, kContinue | kThrow) \
+  V(0x23, NEW_ARRAY, "new-array", k22c, true, kTypeRef, kContinue | kThrow) \
+  V(0x24, FILLED_NEW_ARRAY, "filled-new-array", k35c, false, kTypeRef, kContinue | kThrow) \
+  V(0x25, FILLED_NEW_ARRAY_RANGE, "filled-new-array/range", k3rc, false, kTypeRef, kContinue | kThrow) \
+  V(0x26, FILL_ARRAY_DATA, "fill-array-data", k31t, false, kNone, kContinue) \
+  V(0x27, THROW, "throw", k11x, false, kNone, kThrow) \
+  V(0x28, GOTO, "goto", k10t, false, kNone, kBranch) \
+  V(0x29, GOTO_16, "goto/16", k20t, false, kNone, kBranch) \
+  V(0x2A, GOTO_32, "goto/32", k30t, false, kNone, kBranch) \
+  V(0x2B, PACKED_SWITCH, "packed-switch", k31t, false, kNone, kContinue | kSwitch) \
+  V(0x2C, SPARSE_SWITCH, "sparse-switch", k31t, false, kNone, kContinue | kSwitch) \
+  V(0x2D, CMPL_FLOAT, "cmpl-float", k23x, true, kNone, kContinue) \
+  V(0x2E, CMPG_FLOAT, "cmpg-float", k23x, true, kNone, kContinue) \
+  V(0x2F, CMPL_DOUBLE, "cmpl-double", k23x, true, kNone, kContinue) \
+  V(0x30, CMPG_DOUBLE, "cmpg-double", k23x, true, kNone, kContinue) \
+  V(0x31, CMP_LONG, "cmp-long", k23x, true, kNone, kContinue) \
+  V(0x32, IF_EQ, "if-eq", k22t, false, kNone, kContinue | kBranch) \
+  V(0x33, IF_NE, "if-ne", k22t, false, kNone, kContinue | kBranch) \
+  V(0x34, IF_LT, "if-lt", k22t, false, kNone, kContinue | kBranch) \
+  V(0x35, IF_GE, "if-ge", k22t, false, kNone, kContinue | kBranch) \
+  V(0x36, IF_GT, "if-gt", k22t, false, kNone, kContinue | kBranch) \
+  V(0x37, IF_LE, "if-le", k22t, false, kNone, kContinue | kBranch) \
+  V(0x38, IF_EQZ, "if-eqz", k21t, false, kNone, kContinue | kBranch) \
+  V(0x39, IF_NEZ, "if-nez", k21t, false, kNone, kContinue | kBranch) \
+  V(0x3A, IF_LTZ, "if-ltz", k21t, false, kNone, kContinue | kBranch) \
+  V(0x3B, IF_GEZ, "if-gez", k21t, false, kNone, kContinue | kBranch) \
+  V(0x3C, IF_GTZ, "if-gtz", k21t, false, kNone, kContinue | kBranch) \
+  V(0x3D, IF_LEZ, "if-lez", k21t, false, kNone, kContinue | kBranch) \
+  V(0x3E, UNUSED_3E, "unused-3e", k10x, false, kUnknown, 0) \
+  V(0x3F, UNUSED_3F, "unused-3f", k10x, false, kUnknown, 0) \
+  V(0x40, UNUSED_40, "unused-40", k10x, false, kUnknown, 0) \
+  V(0x41, UNUSED_41, "unused-41", k10x, false, kUnknown, 0) \
+  V(0x42, UNUSED_42, "unused-42", k10x, false, kUnknown, 0) \
+  V(0x43, UNUSED_43, "unused-43", k10x, false, kUnknown, 0) \
+  V(0x44, AGET, "aget", k23x, true, kNone, kContinue | kThrow) \
+  V(0x45, AGET_WIDE, "aget-wide", k23x, true, kNone, kContinue | kThrow) \
+  V(0x46, AGET_OBJECT, "aget-object", k23x, true, kNone, kContinue | kThrow) \
+  V(0x47, AGET_BOOLEAN, "aget-boolean", k23x, true, kNone, kContinue | kThrow) \
+  V(0x48, AGET_BYTE, "aget-byte", k23x, true, kNone, kContinue | kThrow) \
+  V(0x49, AGET_CHAR, "aget-char", k23x, true, kNone, kContinue | kThrow) \
+  V(0x4A, AGET_SHORT, "aget-short", k23x, true, kNone, kContinue | kThrow) \
+  V(0x4B, APUT, "aput", k23x, false, kNone, kContinue | kThrow) \
+  V(0x4C, APUT_WIDE, "aput-wide", k23x, false, kNone, kContinue | kThrow) \
+  V(0x4D, APUT_OBJECT, "aput-object", k23x, false, kNone, kContinue | kThrow) \
+  V(0x4E, APUT_BOOLEAN, "aput-boolean", k23x, false, kNone, kContinue | kThrow) \
+  V(0x4F, APUT_BYTE, "aput-byte", k23x, false, kNone, kContinue | kThrow) \
+  V(0x50, APUT_CHAR, "aput-char", k23x, false, kNone, kContinue | kThrow) \
+  V(0x51, APUT_SHORT, "aput-short", k23x, false, kNone, kContinue | kThrow) \
+  V(0x52, IGET, "iget", k22c, true, kFieldRef, kContinue | kThrow) \
+  V(0x53, IGET_WIDE, "iget-wide", k22c, true, kFieldRef, kContinue | kThrow) \
+  V(0x54, IGET_OBJECT, "iget-object", k22c, true, kFieldRef, kContinue | kThrow) \
+  V(0x55, IGET_BOOLEAN, "iget-boolean", k22c, true, kFieldRef, kContinue | kThrow) \
+  V(0x56, IGET_BYTE, "iget-byte", k22c, true, kFieldRef, kContinue | kThrow) \
+  V(0x57, IGET_CHAR, "iget-char", k22c, true, kFieldRef, kContinue | kThrow) \
+  V(0x58, IGET_SHORT, "iget-short", k22c, true, kFieldRef, kContinue | kThrow) \
+  V(0x59, IPUT, "iput", k22c, false, kFieldRef, kContinue | kThrow) \
+  V(0x5A, IPUT_WIDE, "iput-wide", k22c, false, kFieldRef, kContinue | kThrow) \
+  V(0x5B, IPUT_OBJECT, "iput-object", k22c, false, kFieldRef, kContinue | kThrow) \
+  V(0x5C, IPUT_BOOLEAN, "iput-boolean", k22c, false, kFieldRef, kContinue | kThrow) \
+  V(0x5D, IPUT_BYTE, "iput-byte", k22c, false, kFieldRef, kContinue | kThrow) \
+  V(0x5E, IPUT_CHAR, "iput-char", k22c, false, kFieldRef, kContinue | kThrow) \
+  V(0x5F, IPUT_SHORT, "iput-short", k22c, false, kFieldRef, kContinue | kThrow) \
+  V(0x60, SGET, "sget", k21c, true, kFieldRef, kContinue | kThrow) \
+  V(0x61, SGET_WIDE, "sget-wide", k21c, true, kFieldRef, kContinue | kThrow) \
+  V(0x62, SGET_OBJECT, "sget-object", k21c, true, kFieldRef, kContinue | kThrow) \
+  V(0x63, SGET_BOOLEAN, "sget-boolean", k21c, true, kFieldRef, kContinue | kThrow) \
+  V(0x64, SGET_BYTE, "sget-byte", k21c, true, kFieldRef, kContinue | kThrow) \
+  V(0x65, SGET_CHAR, "sget-char", k21c, true, kFieldRef, kContinue | kThrow) \
+  V(0x66, SGET_SHORT, "sget-short", k21c, true, kFieldRef, kContinue | kThrow) \
+  V(0x67, SPUT, "sput", k21c, false, kFieldRef, kContinue | kThrow) \
+  V(0x68, SPUT_WIDE, "sput-wide", k21c, false, kFieldRef, kContinue | kThrow) \
+  V(0x69, SPUT_OBJECT, "sput-object", k21c, false, kFieldRef, kContinue | kThrow) \
+  V(0x6A, SPUT_BOOLEAN, "sput-boolean", k21c, false, kFieldRef, kContinue | kThrow) \
+  V(0x6B, SPUT_BYTE, "sput-byte", k21c, false, kFieldRef, kContinue | kThrow) \
+  V(0x6C, SPUT_CHAR, "sput-char", k21c, false, kFieldRef, kContinue | kThrow) \
+  V(0x6D, SPUT_SHORT, "sput-short", k21c, false, kFieldRef, kContinue | kThrow) \
+  V(0x6E, INVOKE_VIRTUAL, "invoke-virtual", k35c, false, kMethodRef, kContinue | kThrow | kInvoke) \
+  V(0x6F, INVOKE_SUPER, "invoke-super", k35c, false, kMethodRef, kContinue | kThrow | kInvoke) \
+  V(0x70, INVOKE_DIRECT, "invoke-direct", k35c, false, kMethodRef, kContinue | kThrow | kInvoke) \
+  V(0x71, INVOKE_STATIC, "invoke-static", k35c, false, kMethodRef, kContinue | kThrow | kInvoke) \
+  V(0x72, INVOKE_INTERFACE, "invoke-interface", k35c, false, kMethodRef, kContinue | kThrow | kInvoke) \
+  V(0x73, UNUSED_73, "unused-73", k10x, false, kUnknown, 0) \
+  V(0x74, INVOKE_VIRTUAL_RANGE, "invoke-virtual/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke) \
+  V(0x75, INVOKE_SUPER_RANGE, "invoke-super/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke) \
+  V(0x76, INVOKE_DIRECT_RANGE, "invoke-direct/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke) \
+  V(0x77, INVOKE_STATIC_RANGE, "invoke-static/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke) \
+  V(0x78, INVOKE_INTERFACE_RANGE, "invoke-interface/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke) \
+  V(0x79, UNUSED_79, "unused-79", k10x, false, kUnknown, 0) \
+  V(0x7A, UNUSED_7A, "unused-7a", k10x, false, kUnknown, 0) \
+  V(0x7B, NEG_INT, "neg-int", k12x, true, kNone, kContinue) \
+  V(0x7C, NOT_INT, "not-int", k12x, true, kNone, kContinue) \
+  V(0x7D, NEG_LONG, "neg-long", k12x, true, kNone, kContinue) \
+  V(0x7E, NOT_LONG, "not-long", k12x, true, kNone, kContinue) \
+  V(0x7F, NEG_FLOAT, "neg-float", k12x, true, kNone, kContinue) \
+  V(0x80, NEG_DOUBLE, "neg-double", k12x, true, kNone, kContinue) \
+  V(0x81, INT_TO_LONG, "int-to-long", k12x, true, kNone, kContinue) \
+  V(0x82, INT_TO_FLOAT, "int-to-float", k12x, true, kNone, kContinue) \
+  V(0x83, INT_TO_DOUBLE, "int-to-double", k12x, true, kNone, kContinue) \
+  V(0x84, LONG_TO_INT, "long-to-int", k12x, true, kNone, kContinue) \
+  V(0x85, LONG_TO_FLOAT, "long-to-float", k12x, true, kNone, kContinue) \
+  V(0x86, LONG_TO_DOUBLE, "long-to-double", k12x, true, kNone, kContinue) \
+  V(0x87, FLOAT_TO_INT, "float-to-int", k12x, true, kNone, kContinue) \
+  V(0x88, FLOAT_TO_LONG, "float-to-long", k12x, true, kNone, kContinue) \
+  V(0x89, FLOAT_TO_DOUBLE, "float-to-double", k12x, true, kNone, kContinue) \
+  V(0x8A, DOUBLE_TO_INT, "double-to-int", k12x, true, kNone, kContinue) \
+  V(0x8B, DOUBLE_TO_LONG, "double-to-long", k12x, true, kNone, kContinue) \
+  V(0x8C, DOUBLE_TO_FLOAT, "double-to-float", k12x, true, kNone, kContinue) \
+  V(0x8D, INT_TO_BYTE, "int-to-byte", k12x, true, kNone, kContinue) \
+  V(0x8E, INT_TO_CHAR, "int-to-char", k12x, true, kNone, kContinue) \
+  V(0x8F, INT_TO_SHORT, "int-to-short", k12x, true, kNone, kContinue) \
+  V(0x90, ADD_INT, "add-int", k23x, true, kNone, kContinue) \
+  V(0x91, SUB_INT, "sub-int", k23x, true, kNone, kContinue) \
+  V(0x92, MUL_INT, "mul-int", k23x, true, kNone, kContinue) \
+  V(0x93, DIV_INT, "div-int", k23x, true, kNone, kContinue | kThrow) \
+  V(0x94, REM_INT, "rem-int", k23x, true, kNone, kContinue | kThrow) \
+  V(0x95, AND_INT, "and-int", k23x, true, kNone, kContinue) \
+  V(0x96, OR_INT, "or-int", k23x, true, kNone, kContinue) \
+  V(0x97, XOR_INT, "xor-int", k23x, true, kNone, kContinue) \
+  V(0x98, SHL_INT, "shl-int", k23x, true, kNone, kContinue) \
+  V(0x99, SHR_INT, "shr-int", k23x, true, kNone, kContinue) \
+  V(0x9A, USHR_INT, "ushr-int", k23x, true, kNone, kContinue) \
+  V(0x9B, ADD_LONG, "add-long", k23x, true, kNone, kContinue) \
+  V(0x9C, SUB_LONG, "sub-long", k23x, true, kNone, kContinue) \
+  V(0x9D, MUL_LONG, "mul-long", k23x, true, kNone, kContinue) \
+  V(0x9E, DIV_LONG, "div-long", k23x, true, kNone, kContinue | kThrow) \
+  V(0x9F, REM_LONG, "rem-long", k23x, true, kNone, kContinue | kThrow) \
+  V(0xA0, AND_LONG, "and-long", k23x, true, kNone, kContinue) \
+  V(0xA1, OR_LONG, "or-long", k23x, true, kNone, kContinue) \
+  V(0xA2, XOR_LONG, "xor-long", k23x, true, kNone, kContinue) \
+  V(0xA3, SHL_LONG, "shl-long", k23x, true, kNone, kContinue) \
+  V(0xA4, SHR_LONG, "shr-long", k23x, true, kNone, kContinue) \
+  V(0xA5, USHR_LONG, "ushr-long", k23x, true, kNone, kContinue) \
+  V(0xA6, ADD_FLOAT, "add-float", k23x, true, kNone, kContinue) \
+  V(0xA7, SUB_FLOAT, "sub-float", k23x, true, kNone, kContinue) \
+  V(0xA8, MUL_FLOAT, "mul-float", k23x, true, kNone, kContinue) \
+  V(0xA9, DIV_FLOAT, "div-float", k23x, true, kNone, kContinue) \
+  V(0xAA, REM_FLOAT, "rem-float", k23x, true, kNone, kContinue) \
+  V(0xAB, ADD_DOUBLE, "add-double", k23x, true, kNone, kContinue) \
+  V(0xAC, SUB_DOUBLE, "sub-double", k23x, true, kNone, kContinue) \
+  V(0xAD, MUL_DOUBLE, "mul-double", k23x, true, kNone, kContinue) \
+  V(0xAE, DIV_DOUBLE, "div-double", k23x, true, kNone, kContinue) \
+  V(0xAF, REM_DOUBLE, "rem-double", k23x, true, kNone, kContinue) \
+  V(0xB0, ADD_INT_2ADDR, "add-int/2addr", k12x, true, kNone, kContinue) \
+  V(0xB1, SUB_INT_2ADDR, "sub-int/2addr", k12x, true, kNone, kContinue) \
+  V(0xB2, MUL_INT_2ADDR, "mul-int/2addr", k12x, true, kNone, kContinue) \
+  V(0xB3, DIV_INT_2ADDR, "div-int/2addr", k12x, true, kNone, kContinue | kThrow) \
+  V(0xB4, REM_INT_2ADDR, "rem-int/2addr", k12x, true, kNone, kContinue | kThrow) \
+  V(0xB5, AND_INT_2ADDR, "and-int/2addr", k12x, true, kNone, kContinue) \
+  V(0xB6, OR_INT_2ADDR, "or-int/2addr", k12x, true, kNone, kContinue) \
+  V(0xB7, XOR_INT_2ADDR, "xor-int/2addr", k12x, true, kNone, kContinue) \
+  V(0xB8, SHL_INT_2ADDR, "shl-int/2addr", k12x, true, kNone, kContinue) \
+  V(0xB9, SHR_INT_2ADDR, "shr-int/2addr", k12x, true, kNone, kContinue) \
+  V(0xBA, USHR_INT_2ADDR, "ushr-int/2addr", k12x, true, kNone, kContinue) \
+  V(0xBB, ADD_LONG_2ADDR, "add-long/2addr", k12x, true, kNone, kContinue) \
+  V(0xBC, SUB_LONG_2ADDR, "sub-long/2addr", k12x, true, kNone, kContinue) \
+  V(0xBD, MUL_LONG_2ADDR, "mul-long/2addr", k12x, true, kNone, kContinue) \
+  V(0xBE, DIV_LONG_2ADDR, "div-long/2addr", k12x, true, kNone, kContinue | kThrow) \
+  V(0xBF, REM_LONG_2ADDR, "rem-long/2addr", k12x, true, kNone, kContinue | kThrow) \
+  V(0xC0, AND_LONG_2ADDR, "and-long/2addr", k12x, true, kNone, kContinue) \
+  V(0xC1, OR_LONG_2ADDR, "or-long/2addr", k12x, true, kNone, kContinue) \
+  V(0xC2, XOR_LONG_2ADDR, "xor-long/2addr", k12x, true, kNone, kContinue) \
+  V(0xC3, SHL_LONG_2ADDR, "shl-long/2addr", k12x, true, kNone, kContinue) \
+  V(0xC4, SHR_LONG_2ADDR, "shr-long/2addr", k12x, true, kNone, kContinue) \
+  V(0xC5, USHR_LONG_2ADDR, "ushr-long/2addr", k12x, true, kNone, kContinue) \
+  V(0xC6, ADD_FLOAT_2ADDR, "add-float/2addr", k12x, true, kNone, kContinue) \
+  V(0xC7, SUB_FLOAT_2ADDR, "sub-float/2addr", k12x, true, kNone, kContinue) \
+  V(0xC8, MUL_FLOAT_2ADDR, "mul-float/2addr", k12x, true, kNone, kContinue) \
+  V(0xC9, DIV_FLOAT_2ADDR, "div-float/2addr", k12x, true, kNone, kContinue) \
+  V(0xCA, REM_FLOAT_2ADDR, "rem-float/2addr", k12x, true, kNone, kContinue) \
+  V(0xCB, ADD_DOUBLE_2ADDR, "add-double/2addr", k12x, true, kNone, kContinue) \
+  V(0xCC, SUB_DOUBLE_2ADDR, "sub-double/2addr", k12x, true, kNone, kContinue) \
+  V(0xCD, MUL_DOUBLE_2ADDR, "mul-double/2addr", k12x, true, kNone, kContinue) \
+  V(0xCE, DIV_DOUBLE_2ADDR, "div-double/2addr", k12x, true, kNone, kContinue) \
+  V(0xCF, REM_DOUBLE_2ADDR, "rem-double/2addr", k12x, true, kNone, kContinue) \
+  V(0xD0, ADD_INT_LIT16, "add-int/lit16", k22s, true, kNone, kContinue) \
+  V(0xD1, RSUB_INT, "rsub-int", k22s, true, kNone, kContinue) \
+  V(0xD2, MUL_INT_LIT16, "mul-int/lit16", k22s, true, kNone, kContinue) \
+  V(0xD3, DIV_INT_LIT16, "div-int/lit16", k22s, true, kNone, kContinue | kThrow) \
+  V(0xD4, REM_INT_LIT16, "rem-int/lit16", k22s, true, kNone, kContinue | kThrow) \
+  V(0xD5, AND_INT_LIT16, "and-int/lit16", k22s, true, kNone, kContinue) \
+  V(0xD6, OR_INT_LIT16, "or-int/lit16", k22s, true, kNone, kContinue) \
+  V(0xD7, XOR_INT_LIT16, "xor-int/lit16", k22s, true, kNone, kContinue) \
+  V(0xD8, ADD_INT_LIT8, "add-int/lit8", k22b, true, kNone, kContinue) \
+  V(0xD9, RSUB_INT_LIT8, "rsub-int/lit8", k22b, true, kNone, kContinue) \
+  V(0xDA, MUL_INT_LIT8, "mul-int/lit8", k22b, true, kNone, kContinue) \
+  V(0xDB, DIV_INT_LIT8, "div-int/lit8", k22b, true, kNone, kContinue | kThrow) \
+  V(0xDC, REM_INT_LIT8, "rem-int/lit8", k22b, true, kNone, kContinue | kThrow) \
+  V(0xDD, AND_INT_LIT8, "and-int/lit8", k22b, true, kNone, kContinue) \
+  V(0xDE, OR_INT_LIT8, "or-int/lit8", k22b, true, kNone, kContinue) \
+  V(0xDF, XOR_INT_LIT8, "xor-int/lit8", k22b, true, kNone, kContinue) \
+  V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, true, kNone, kContinue) \
+  V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, true, kNone, kContinue) \
+  V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, true, kNone, kContinue) \
+  V(0xE3, UNUSED_E3, "unused-e3", k10x, false, kUnknown, 0) \
+  V(0xE4, UNUSED_E4, "unused-e4", k10x, false, kUnknown, 0) \
+  V(0xE5, UNUSED_E5, "unused-e5", k10x, false, kUnknown, 0) \
+  V(0xE6, UNUSED_E6, "unused-e6", k10x, false, kUnknown, 0) \
+  V(0xE7, UNUSED_E7, "unused-e7", k10x, false, kUnknown, 0) \
+  V(0xE8, UNUSED_E8, "unused-e8", k10x, false, kUnknown, 0) \
+  V(0xE9, UNUSED_E9, "unused-e9", k10x, false, kUnknown, 0) \
+  V(0xEA, UNUSED_EA, "unused-ea", k10x, false, kUnknown, 0) \
+  V(0xEB, UNUSED_EB, "unused-eb", k10x, false, kUnknown, 0) \
+  V(0xEC, UNUSED_EC, "unused-ec", k10x, false, kUnknown, 0) \
+  V(0xED, UNUSED_ED, "unused-ed", k10x, false, kUnknown, 0) \
+  V(0xEE, UNUSED_EE, "unused-ee", k10x, false, kUnknown, 0) \
+  V(0xEF, UNUSED_EF, "unused-ef", k10x, false, kUnknown, 0) \
+  V(0xF0, UNUSED_F0, "unused-f0", k10x, false, kUnknown, 0) \
+  V(0xF1, UNUSED_F1, "unused-f1", k10x, false, kUnknown, 0) \
+  V(0xF2, UNUSED_F2, "unused-f2", k10x, false, kUnknown, 0) \
+  V(0xF3, UNUSED_F3, "unused-f3", k10x, false, kUnknown, 0) \
+  V(0xF4, UNUSED_F4, "unused-f4", k10x, false, kUnknown, 0) \
+  V(0xF5, UNUSED_F5, "unused-f5", k10x, false, kUnknown, 0) \
+  V(0xF6, UNUSED_F6, "unused-f6", k10x, false, kUnknown, 0) \
+  V(0xF7, UNUSED_F7, "unused-f7", k10x, false, kUnknown, 0) \
+  V(0xF8, UNUSED_F8, "unused-f8", k10x, false, kUnknown, 0) \
+  V(0xF9, UNUSED_F9, "unused-f9", k10x, false, kUnknown, 0) \
+  V(0xFA, UNUSED_FA, "unused-fa", k10x, false, kUnknown, 0) \
+  V(0xFB, UNUSED_FB, "unused-fb", k10x, false, kUnknown, 0) \
+  V(0xFC, UNUSED_FC, "unused-fc", k10x, false, kUnknown, 0) \
+  V(0xFD, UNUSED_FD, "unused-fd", k10x, false, kUnknown, 0) \
+  V(0xFE, UNUSED_FE, "unused-fe", k10x, false, kUnknown, 0) \
+  V(0xFF, UNUSED_FF, "unused-ff", k10x, false, kUnknown, 0)
diff --git a/src/dex_instruction_visitor.h b/src/dex_instruction_visitor.h
index ff45a4c..2af26e3 100644
--- a/src/dex_instruction_visitor.h
+++ b/src/dex_instruction_visitor.h
@@ -18,7 +18,7 @@
     while (ptr != end) {
       Instruction* inst = Instruction::At(ptr);
       switch (inst->Opcode()) {
-#define INSTRUCTION_CASE(cname, value)             \
+#define INSTRUCTION_CASE(o, cname, p, f, r, i, a)  \
         case Instruction::cname: {                 \
           derived->Do_ ## cname(inst);             \
           break;                                   \
@@ -37,10 +37,10 @@
 
  private:
   // Specific handlers for each instruction.
-#define INSTRUCTION_VISITOR(cname, value) \
-  void Do_ ## cname(Instruction* inst) {  \
-    T* derived = static_cast<T*>(this);   \
-    derived->Do_Default(inst);            \
+#define INSTRUCTION_VISITOR(o, cname, p, f, r, i, a)    \
+  void Do_ ## cname(Instruction* inst) {                \
+    T* derived = static_cast<T*>(this);                 \
+    derived->Do_Default(inst);                          \
   };
 #include "src/dex_instruction_list.h"
   DEX_INSTRUCTION_LIST(INSTRUCTION_VISITOR)