text: /*
   * Copyright (C) 2008 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  /*
   * Dalvik instruction utility functions.
   */
  #include "InstrUtils.h"
  
  #include <stdlib.h>
  
  
  /*
   * Generate a table that holds the width of all instructions.
   *
   * Standard instructions have positive values, optimizer instructions
   * have negative values, unimplemented instructions have a width of zero.
   *
   * I'm doing it with a giant switch statement because it's easier to
   * maintain and update than a static table with 256 unadorned integers,
   * and if we're missing a case gcc emits a "warning: enumeration value not
   * handled" message.
   *
   * (To save space in the binary we could generate a static table with a
   * command-line utility.)
   */
  InstructionWidth* dexCreateInstrWidthTable(void)
  {
  #ifdef __ARM_ARCH_7A__
      /* hack to work around mysterious problem on emulator */
      LOGD("creating instr width table\n");
  #endif
      InstructionWidth* instrWidth;
      int i;
  
      instrWidth = malloc(sizeof(InstructionWidth) * kNumDalvikInstructions);
      if (instrWidth == NULL)
          return NULL;
  
      for (i = 0; i < kNumDalvikInstructions; i++) {
          OpCode opc = (OpCode) i;
          int width = 0;
  
          switch (opc) {
          case OP_NOP:    /* note data for e.g. switch-* encoded "inside" a NOP */
          case OP_MOVE:
          case OP_MOVE_WIDE:
          case OP_MOVE_OBJECT:
          case OP_MOVE_RESULT:
          case OP_MOVE_RESULT_WIDE:
          case OP_MOVE_RESULT_OBJECT:
          case OP_MOVE_EXCEPTION:
          case OP_RETURN_VOID:
          case OP_RETURN:
          case OP_RETURN_WIDE:
          case OP_RETURN_OBJECT:
          case OP_CONST_4:
          case OP_MONITOR_ENTER:
          case OP_MONITOR_EXIT:
          case OP_ARRAY_LENGTH:
          case OP_THROW:
          case OP_GOTO:
          case OP_NEG_INT:
          case OP_NOT_INT:
          case OP_NEG_LONG:
          case OP_NOT_LONG:
          case OP_NEG_FLOAT:
          case OP_NEG_DOUBLE:
          case OP_INT_TO_LONG:
          case OP_INT_TO_FLOAT:
          case OP_INT_TO_DOUBLE:
          case OP_LONG_TO_INT:
          case OP_LONG_TO_FLOAT:
          case OP_LONG_TO_DOUBLE:
          case OP_FLOAT_TO_INT:
          case OP_FLOAT_TO_LONG:
          case OP_FLOAT_TO_DOUBLE:
          case OP_DOUBLE_TO_INT:
          case OP_DOUBLE_TO_LONG:
          case OP_DOUBLE_TO_FLOAT:
          case OP_INT_TO_BYTE:
          case OP_INT_TO_CHAR:
          case OP_INT_TO_SHORT:
          case OP_ADD_INT_2ADDR:
          case OP_SUB_INT_2ADDR:
          case OP_MUL_INT_2ADDR:
          case OP_DIV_INT_2ADDR:
          case OP_REM_INT_2ADDR:
          case OP_AND_INT_2ADDR:
          case OP_OR_INT_2ADDR:
          case OP_XOR_INT_2ADDR:
          case OP_SHL_INT_2ADDR:
          case OP_SHR_INT_2ADDR:
          case OP_USHR_INT_2ADDR:
          case OP_ADD_LONG_2ADDR:
          case OP_SUB_LONG_2ADDR:
          case OP_MUL_LONG_2ADDR:
          case OP_DIV_LONG_2ADDR:
          case OP_REM_LONG_2ADDR:
          case OP_AND_LONG_2ADDR:
          case OP_OR_LONG_2ADDR:
          case OP_XOR_LONG_2ADDR:
          case OP_SHL_LONG_2ADDR:
          case OP_SHR_LONG_2ADDR:
          case OP_USHR_LONG_2ADDR:
          case OP_ADD_FLOAT_2ADDR:
          case OP_SUB_FLOAT_2ADDR:
          case OP_MUL_FLOAT_2ADDR:
          case OP_DIV_FLOAT_2ADDR:
          case OP_REM_FLOAT_2ADDR:
          case OP_ADD_DOUBLE_2ADDR:
          case OP_SUB_DOUBLE_2ADDR:
          case OP_MUL_DOUBLE_2ADDR:
          case OP_DIV_DOUBLE_2ADDR:
          case OP_REM_DOUBLE_2ADDR:
              width = 1;
              break;
  
          case OP_MOVE_FROM16:
          case OP_MOVE_WIDE_FROM16:
          case OP_MOVE_OBJECT_FROM16:
          case OP_CONST_16:
          case OP_CONST_HIGH16:
          case OP_CONST_WIDE_16:
          case OP_CONST_WIDE_HIGH16:
          case OP_CONST_STRING:
          case OP_CONST_CLASS:
          case OP_CHECK_CAST:
          case OP_INSTANCE_OF:
          case OP_NEW_INSTANCE:
          case OP_NEW_ARRAY:
          case OP_CMPL_FLOAT:
          case OP_CMPG_FLOAT:
          case OP_CMPL_DOUBLE:
          case OP_CMPG_DOUBLE:
          case OP_CMP_LONG:
          case OP_GOTO_16:
          case OP_IF_EQ:
          case OP_IF_NE:
          case OP_IF_LT:
          case OP_IF_GE:
          case OP_IF_GT:
          case OP_IF_LE:
          case OP_IF_EQZ:
          case OP_IF_NEZ:
          case OP_IF_LTZ:
          case OP_IF_GEZ:
          case OP_IF_GTZ:
          case OP_IF_LEZ:
          case OP_AGET:
          case OP_AGET_WIDE:
          case OP_AGET_OBJECT:
          case OP_AGET_BOOLEAN:
          case OP_AGET_BYTE:
          case OP_AGET_CHAR:
          case OP_AGET_SHORT:
          case OP_APUT:
          case OP_APUT_WIDE:
          case OP_APUT_OBJECT:
          case OP_APUT_BOOLEAN:
          case OP_APUT_BYTE:
          case OP_APUT_CHAR:
          case OP_APUT_SHORT:
          case OP_IGET:
          case OP_IGET_WIDE:
          case OP_IGET_OBJECT:
          case OP_IGET_BOOLEAN:
          case OP_IGET_BYTE:
          case OP_IGET_CHAR:
          case OP_IGET_SHORT:
          case OP_IPUT:
          case OP_IPUT_WIDE:
          case OP_IPUT_OBJECT:
          case OP_IPUT_BOOLEAN:
          case OP_IPUT_BYTE:
          case OP_IPUT_CHAR:
          case OP_IPUT_SHORT:
          case OP_SGET:
          case OP_SGET_WIDE:
          case OP_SGET_OBJECT:
          case OP_SGET_BOOLEAN:
          case OP_SGET_BYTE:
          case OP_SGET_CHAR:
          case OP_SGET_SHORT:
          case OP_SPUT:
          case OP_SPUT_WIDE:
          case OP_SPUT_OBJECT:
          case OP_SPUT_BOOLEAN:
          case OP_SPUT_BYTE:
          case OP_SPUT_CHAR:
          case OP_SPUT_SHORT:
          case OP_ADD_INT:
          case OP_SUB_INT:
          case OP_MUL_INT:
          case OP_DIV_INT:
          case OP_REM_INT:
          case OP_AND_INT:
          case OP_OR_INT:
          case OP_XOR_INT:
          case OP_SHL_INT:
          case OP_SHR_INT:
          case OP_USHR_INT:
          case OP_ADD_LONG:
          case OP_SUB_LONG:
          case OP_MUL_LONG:
          case OP_DIV_LONG:
          case OP_REM_LONG:
          case OP_AND_LONG:
          case OP_OR_LONG:
          case OP_XOR_LONG:
          case OP_SHL_LONG:
          case OP_SHR_LONG:
          case OP_USHR_LONG:
          case OP_ADD_FLOAT:
          case OP_SUB_FLOAT:
          case OP_MUL_FLOAT:
          case OP_DIV_FLOAT:
          case OP_REM_FLOAT:
          case OP_ADD_DOUBLE:
          case OP_SUB_DOUBLE:
          case OP_MUL_DOUBLE:
          case OP_DIV_DOUBLE:
          case OP_REM_DOUBLE:
          case OP_ADD_INT_LIT16:
          case OP_RSUB_INT:
          case OP_MUL_INT_LIT16:
          case OP_DIV_INT_LIT16:
          case OP_REM_INT_LIT16:
          case OP_AND_INT_LIT16:
          case OP_OR_INT_LIT16:
          case OP_XOR_INT_LIT16:
          case OP_ADD_INT_LIT8:
          case OP_RSUB_INT_LIT8:
          case OP_MUL_INT_LIT8:
          case OP_DIV_INT_LIT8:
          case OP_REM_INT_LIT8:
          case OP_AND_INT_LIT8:
          case OP_OR_INT_LIT8:
          case OP_XOR_INT_LIT8:
          case OP_SHL_INT_LIT8:
          case OP_SHR_INT_LIT8:
          case OP_USHR_INT_LIT8:
              width = 2;
              break;
  
          case OP_MOVE_16:
          case OP_MOVE_WIDE_16:
          case OP_MOVE_OBJECT_16:
          case OP_CONST:
          case OP_CONST_WIDE_32:
          case OP_CONST_STRING_JUMBO:
          case OP_GOTO_32:
          case OP_FILLED_NEW_ARRAY:
          case OP_FILLED_NEW_ARRAY_RANGE:
          case OP_FILL_ARRAY_DATA:
          case OP_PACKED_SWITCH:
          case OP_SPARSE_SWITCH:
          case OP_INVOKE_VIRTUAL:
          case OP_INVOKE_SUPER:
          case OP_INVOKE_DIRECT:
          case OP_INVOKE_STATIC:
          case OP_INVOKE_INTERFACE:
          case OP_INVOKE_VIRTUAL_RANGE:
          case OP_INVOKE_SUPER_RANGE:
          case OP_INVOKE_DIRECT_RANGE:
          case OP_INVOKE_STATIC_RANGE:
          case OP_INVOKE_INTERFACE_RANGE:
              width = 3;
              break;
  
          case OP_CONST_WIDE:
              width = 5;
              break;
  
          /*
           * Optimized instructions.  We return negative size values for these
           * to distinguish them.
           */
          case OP_IGET_QUICK:
          case OP_IGET_WIDE_QUICK:
          case OP_IGET_OBJECT_QUICK:
          case OP_IPUT_QUICK:
          case OP_IPUT_WIDE_QUICK:
          case OP_IPUT_OBJECT_QUICK:
          case OP_THROW_VERIFICATION_ERROR:
              width = -2;
              break;
          case OP_INVOKE_VIRTUAL_QUICK:
          case OP_INVOKE_VIRTUAL_QUICK_RANGE:
          case OP_INVOKE_SUPER_QUICK:
          case OP_INVOKE_SUPER_QUICK_RANGE:
          case OP_EXECUTE_INLINE:
          case OP_EXECUTE_INLINE_RANGE:
          case OP_INVOKE_DIRECT_EMPTY:
              width = -3;
              break;
  
          /* these should never appear when scanning bytecode */
          case OP_UNUSED_3E:
          case OP_UNUSED_3F:
          case OP_UNUSED_40:
          case OP_UNUSED_41:
          case OP_UNUSED_42:
          case OP_UNUSED_43:
          case OP_UNUSED_73:
          case OP_UNUSED_79:
          case OP_UNUSED_7A:
          case OP_UNUSED_E3:
          case OP_UNUSED_E4:
          case OP_UNUSED_E5:
          case OP_UNUSED_E6:
          case OP_UNUSED_E7:
          case OP_UNUSED_E8:
          case OP_UNUSED_E9:
          case OP_UNUSED_EA:
          case OP_UNUSED_EB:
          case OP_BREAKPOINT:
          case OP_UNUSED_F1:
          case OP_UNUSED_FC:
          case OP_UNUSED_FD:
          case OP_UNUSED_FE:
          case OP_UNUSED_FF:
              assert(width == 0);
              break;
  
          /*
           * DO NOT add a "default" clause here.  Without it the compiler will
           * complain if an instruction is missing (which is desirable).
           */
          }
  
          instrWidth[opc] = width;
      }
  
      return instrWidth;
  }
  
  /*
   * Generate a table that holds instruction flags.
   */
  InstructionFlags* dexCreateInstrFlagsTable(void)
  {
      InstructionFlags* instrFlags;
      int i;
  
      instrFlags = malloc(sizeof(InstructionFlags) * kNumDalvikInstructions);
      if (instrFlags == NULL)
          return NULL;
  
      for (i = 0; i < kNumDalvikInstructions; i++) {
          OpCode opc = (OpCode) i;
          InstructionFlags flags = 0;
  
          switch (opc) {
          /* these don't affect the PC and can't cause an exception */
          case OP_NOP:
          case OP_MOVE:
          case OP_MOVE_FROM16:
          case OP_MOVE_16:
          case OP_MOVE_WIDE:
          case OP_MOVE_WIDE_FROM16:
          case OP_MOVE_WIDE_16:
          case OP_MOVE_OBJECT:
          case OP_MOVE_OBJECT_FROM16:
          case OP_MOVE_OBJECT_16:
          case OP_MOVE_RESULT:
          case OP_MOVE_RESULT_WIDE:
          case OP_MOVE_RESULT_OBJECT:
          case OP_MOVE_EXCEPTION:
          case OP_CONST_4:
          case OP_CONST_16:
          case OP_CONST:
          case OP_CONST_HIGH16:
          case OP_CONST_WIDE_16:
          case OP_CONST_WIDE_32:
          case OP_CONST_WIDE:
          case OP_CONST_WIDE_HIGH16:
          case OP_FILL_ARRAY_DATA:
          case OP_CMPL_FLOAT:
          case OP_CMPG_FLOAT:
          case OP_CMPL_DOUBLE:
          case OP_CMPG_DOUBLE:
          case OP_CMP_LONG:
          case OP_NEG_INT:
          case OP_NOT_INT:
          case OP_NEG_LONG:
          case OP_NOT_LONG:
          case OP_NEG_FLOAT:
          case OP_NEG_DOUBLE:
          case OP_INT_TO_LONG:
          case OP_INT_TO_FLOAT:
          case OP_INT_TO_DOUBLE:
          case OP_LONG_TO_INT:
          case OP_LONG_TO_FLOAT:
          case OP_LONG_TO_DOUBLE:
          case OP_FLOAT_TO_INT:
          case OP_FLOAT_TO_LONG:
          case OP_FLOAT_TO_DOUBLE:
          case OP_DOUBLE_TO_INT:
          case OP_DOUBLE_TO_LONG:
          case OP_DOUBLE_TO_FLOAT:
          case OP_INT_TO_BYTE:
          case OP_INT_TO_CHAR:
          case OP_INT_TO_SHORT:
          case OP_ADD_INT:
          case OP_SUB_INT:
          case OP_MUL_INT:
          case OP_AND_INT:
          case OP_OR_INT:
          case OP_XOR_INT:
          case OP_SHL_INT:
          case OP_SHR_INT:
          case OP_USHR_INT:
          case OP_ADD_LONG:
          case OP_SUB_LONG:
          case OP_MUL_LONG:
          case OP_AND_LONG:
          case OP_OR_LONG:
          case OP_XOR_LONG:
          case OP_SHL_LONG:
          case OP_SHR_LONG:
          case OP_USHR_LONG:
          case OP_ADD_FLOAT:
          case OP_SUB_FLOAT:
          case OP_MUL_FLOAT:
          case OP_DIV_FLOAT:
          case OP_REM_FLOAT:
          case OP_ADD_DOUBLE:
          case OP_SUB_DOUBLE:
          case OP_MUL_DOUBLE:
          case OP_DIV_DOUBLE:         // div by zero just returns NaN
          case OP_REM_DOUBLE:
          case OP_ADD_INT_2ADDR:
          case OP_SUB_INT_2ADDR:
          case OP_MUL_INT_2ADDR:
          case OP_AND_INT_2ADDR:
          case OP_OR_INT_2ADDR:
          case OP_XOR_INT_2ADDR:
          case OP_SHL_INT_2ADDR:
          case OP_SHR_INT_2ADDR:
          case OP_USHR_INT_2ADDR:
          case OP_ADD_LONG_2ADDR:
          case OP_SUB_LONG_2ADDR:
          case OP_MUL_LONG_2ADDR:
          case OP_AND_LONG_2ADDR:
          case OP_OR_LONG_2ADDR:
          case OP_XOR_LONG_2ADDR:
          case OP_SHL_LONG_2ADDR:
          case OP_SHR_LONG_2ADDR:
          case OP_USHR_LONG_2ADDR:
          case OP_ADD_FLOAT_2ADDR:
          case OP_SUB_FLOAT_2ADDR:
          case OP_MUL_FLOAT_2ADDR:
          case OP_DIV_FLOAT_2ADDR:
          case OP_REM_FLOAT_2ADDR:
          case OP_ADD_DOUBLE_2ADDR:
          case OP_SUB_DOUBLE_2ADDR:
          case OP_MUL_DOUBLE_2ADDR:
          case OP_DIV_DOUBLE_2ADDR:
          case OP_REM_DOUBLE_2ADDR:
          case OP_ADD_INT_LIT16:
          case OP_RSUB_INT:
          case OP_MUL_INT_LIT16:
          case OP_AND_INT_LIT16:
          case OP_OR_INT_LIT16:
          case OP_XOR_INT_LIT16:
          case OP_ADD_INT_LIT8:
          case OP_RSUB_INT_LIT8:
          case OP_MUL_INT_LIT8:
          case OP_AND_INT_LIT8:
          case OP_OR_INT_LIT8:
          case OP_XOR_INT_LIT8:
          case OP_SHL_INT_LIT8:
          case OP_SHR_INT_LIT8:
          case OP_USHR_INT_LIT8:
              flags = kInstrCanContinue;
              break;
  
          /* these don't affect the PC, but can cause exceptions */
          case OP_CONST_STRING:
          case OP_CONST_STRING_JUMBO:
          case OP_CONST_CLASS:
          case OP_MONITOR_ENTER:
          case OP_MONITOR_EXIT:
          case OP_CHECK_CAST:
          case OP_INSTANCE_OF:
          case OP_ARRAY_LENGTH:
          case OP_NEW_INSTANCE:
          case OP_NEW_ARRAY:
          case OP_FILLED_NEW_ARRAY:
          case OP_FILLED_NEW_ARRAY_RANGE:
          case OP_AGET:
          case OP_AGET_BOOLEAN:
          case OP_AGET_BYTE:
          case OP_AGET_CHAR:
          case OP_AGET_SHORT:
          case OP_AGET_WIDE:
          case OP_AGET_OBJECT:
          case OP_APUT:
          case OP_APUT_BOOLEAN:
          case OP_APUT_BYTE:
          case OP_APUT_CHAR:
          case OP_APUT_SHORT:
          case OP_APUT_WIDE:
          case OP_APUT_OBJECT:
          case OP_IGET:
          case OP_IGET_BOOLEAN:
          case OP_IGET_BYTE:
          case OP_IGET_CHAR:
          case OP_IGET_SHORT:
          case OP_IGET_WIDE:
          case OP_IGET_OBJECT:
          case OP_IPUT:
          case OP_IPUT_BOOLEAN:
          case OP_IPUT_BYTE:
          case OP_IPUT_CHAR:
          case OP_IPUT_SHORT:
          case OP_IPUT_WIDE:
          case OP_IPUT_OBJECT:
          case OP_SGET:
          case OP_SGET_BOOLEAN:
          case OP_SGET_BYTE:
          case OP_SGET_CHAR:
          case OP_SGET_SHORT:
          case OP_SGET_WIDE:
          case OP_SGET_OBJECT:
          case OP_SPUT:
          case OP_SPUT_BOOLEAN:
          case OP_SPUT_BYTE:
          case OP_SPUT_CHAR:
          case OP_SPUT_SHORT:
          case OP_SPUT_WIDE:
          case OP_SPUT_OBJECT:
          case OP_DIV_INT:
          case OP_REM_INT:
          case OP_DIV_LONG:
          case OP_REM_LONG:
          case OP_DIV_INT_2ADDR:
          case OP_REM_INT_2ADDR:
          case OP_DIV_LONG_2ADDR:
          case OP_REM_LONG_2ADDR:
          case OP_DIV_INT_LIT16:
          case OP_REM_INT_LIT16:
          case OP_DIV_INT_LIT8:
          case OP_REM_INT_LIT8:
              flags = kInstrCanContinue | kInstrCanThrow;
              break;
  
          case OP_INVOKE_VIRTUAL:
          case OP_INVOKE_VIRTUAL_RANGE:
          case OP_INVOKE_SUPER:
          case OP_INVOKE_SUPER_RANGE:
          case OP_INVOKE_DIRECT:
          case OP_INVOKE_DIRECT_RANGE:
          case OP_INVOKE_STATIC:
          case OP_INVOKE_STATIC_RANGE:
          case OP_INVOKE_INTERFACE:
          case OP_INVOKE_INTERFACE_RANGE:
              flags = kInstrCanContinue | kInstrCanThrow | kInstrInvoke;
              break;
  
          case OP_RETURN_VOID:
          case OP_RETURN:
          case OP_RETURN_WIDE:
          case OP_RETURN_OBJECT:
              flags = kInstrCanReturn;
              break;
  
          case OP_THROW:
              flags = kInstrCanThrow;
              break;
  
          /* unconditional branches */
          case OP_GOTO:
          case OP_GOTO_16:
          case OP_GOTO_32:
              flags = kInstrCanBranch | kInstrUnconditional;
              break;
  
          /* conditional branches */
          case OP_IF_EQ:
          case OP_IF_NE:
          case OP_IF_LT:
          case OP_IF_GE:
          case OP_IF_GT:
          case OP_IF_LE:
          case OP_IF_EQZ:
          case OP_IF_NEZ:
          case OP_IF_LTZ:
          case OP_IF_GEZ:
          case OP_IF_GTZ:
          case OP_IF_LEZ:
              flags = kInstrCanBranch | kInstrCanContinue;
              break;
  
          /* switch statements; if value not in switch, it continues */
          case OP_PACKED_SWITCH:
          case OP_SPARSE_SWITCH:
              flags = kInstrCanSwitch | kInstrCanContinue;
              break;
  
          /* verifier/optimizer-generated instructions */
          case OP_THROW_VERIFICATION_ERROR:
              flags = kInstrCanThrow;
              break;
          case OP_EXECUTE_INLINE:
          case OP_EXECUTE_INLINE_RANGE:
              flags = kInstrCanContinue | kInstrCanThrow;
              break;
          case OP_IGET_QUICK:
          case OP_IGET_WIDE_QUICK:
          case OP_IGET_OBJECT_QUICK:
          case OP_IPUT_QUICK:
          case OP_IPUT_WIDE_QUICK:
          case OP_IPUT_OBJECT_QUICK:
              flags = kInstrCanContinue | kInstrCanThrow;
              break;
  
          case OP_INVOKE_VIRTUAL_QUICK:
          case OP_INVOKE_VIRTUAL_QUICK_RANGE:
          case OP_INVOKE_SUPER_QUICK:
          case OP_INVOKE_SUPER_QUICK_RANGE:
          case OP_INVOKE_DIRECT_EMPTY:
              flags = kInstrCanContinue | kInstrCanThrow | kInstrInvoke;
              break;
  
          /* these should never appear when scanning code */
          case OP_UNUSED_3E:
          case OP_UNUSED_3F:
          case OP_UNUSED_40:
          case OP_UNUSED_41:
          case OP_UNUSED_42:
          case OP_UNUSED_43:
          case OP_UNUSED_73:
          case OP_UNUSED_79:
          case OP_UNUSED_7A:
          case OP_UNUSED_E3:
          case OP_UNUSED_E4:
          case OP_UNUSED_E5:
          case OP_UNUSED_E6:
          case OP_UNUSED_E7:
          case OP_UNUSED_E8:
          case OP_UNUSED_E9:
          case OP_UNUSED_EA:
          case OP_UNUSED_EB:
          case OP_BREAKPOINT:
          case OP_UNUSED_F1:
          case OP_UNUSED_FC:
          case OP_UNUSED_FD:
          case OP_UNUSED_FE:
          case OP_UNUSED_FF:
              break;
  
          /*
           * DO NOT add a "default" clause here.  Without it the compiler will
           * complain if an instruction is missing (which is desirable).
           */
          }
  
          instrFlags[opc] = flags;
      }
  
      return instrFlags;
  }
  
  /*
   * Allocate and populate a 256-element array with instruction formats.
   * Used in conjunction with dexDecodeInstruction.
   */
  InstructionFormat* dexCreateInstrFormatTable(void)
  {
      InstructionFormat* instFmt;
      int i;
  
      instFmt = malloc(sizeof(InstructionFormat) * kNumDalvikInstructions);
      if (instFmt == NULL)
          return NULL;
  
      for (i = 0; i < kNumDalvikInstructions; i++) {
          OpCode opc = (OpCode) i;
          InstructionFormat fmt = kFmtUnknown;
  
          switch (opc) {
          case OP_GOTO:
              fmt = kFmt10t;
              break;
          case OP_NOP:
          case OP_RETURN_VOID:
              fmt = kFmt10x;
              break;
          case OP_CONST_4:
              fmt = kFmt11n;
              break;
          case OP_CONST_HIGH16:
          case OP_CONST_WIDE_HIGH16:
              fmt = kFmt21h;
              break;
          case OP_MOVE_RESULT:
          case OP_MOVE_RESULT_WIDE:
          case OP_MOVE_RESULT_OBJECT:
          case OP_MOVE_EXCEPTION:
          case OP_RETURN:
          case OP_RETURN_WIDE:
          case OP_RETURN_OBJECT:
          case OP_MONITOR_ENTER:
          case OP_MONITOR_EXIT:
          case OP_THROW:
              fmt = kFmt11x;
              break;
          case OP_MOVE:
          case OP_MOVE_WIDE:
          case OP_MOVE_OBJECT:
          case OP_ARRAY_LENGTH:
          case OP_NEG_INT:
          case OP_NOT_INT:
          case OP_NEG_LONG:
          case OP_NOT_LONG:
          case OP_NEG_FLOAT:
          case OP_NEG_DOUBLE:
          case OP_INT_TO_LONG:
          case OP_INT_TO_FLOAT:
          case OP_INT_TO_DOUBLE:
          case OP_LONG_TO_INT:
          case OP_LONG_TO_FLOAT:
          case OP_LONG_TO_DOUBLE:
          case OP_FLOAT_TO_INT:
          case OP_FLOAT_TO_LONG:
          case OP_FLOAT_TO_DOUBLE:
          case OP_DOUBLE_TO_INT:
          case OP_DOUBLE_TO_LONG:
          case OP_DOUBLE_TO_FLOAT:
          case OP_INT_TO_BYTE:
          case OP_INT_TO_CHAR:
          case OP_INT_TO_SHORT:
          case OP_ADD_INT_2ADDR:
          case OP_SUB_INT_2ADDR:
          case OP_MUL_INT_2ADDR:
          case OP_DIV_INT_2ADDR:
          case OP_REM_INT_2ADDR:
          case OP_AND_INT_2ADDR:
          case OP_OR_INT_2ADDR:
          case OP_XOR_INT_2ADDR:
          case OP_SHL_INT_2ADDR:
          case OP_SHR_INT_2ADDR:
          case OP_USHR_INT_2ADDR:
          case OP_ADD_LONG_2ADDR:
          case OP_SUB_LONG_2ADDR:
          case OP_MUL_LONG_2ADDR:
          case OP_DIV_LONG_2ADDR:
          case OP_REM_LONG_2ADDR:
          case OP_AND_LONG_2ADDR:
          case OP_OR_LONG_2ADDR:
          case OP_XOR_LONG_2ADDR:
          case OP_SHL_LONG_2ADDR:
          case OP_SHR_LONG_2ADDR:
          case OP_USHR_LONG_2ADDR:
          case OP_ADD_FLOAT_2ADDR:
          case OP_SUB_FLOAT_2ADDR:
          case OP_MUL_FLOAT_2ADDR:
          case OP_DIV_FLOAT_2ADDR:
          case OP_REM_FLOAT_2ADDR:
          case OP_ADD_DOUBLE_2ADDR:
          case OP_SUB_DOUBLE_2ADDR:
          case OP_MUL_DOUBLE_2ADDR:
          case OP_DIV_DOUBLE_2ADDR:
          case OP_REM_DOUBLE_2ADDR:
              fmt = kFmt12x;
              break;
          case OP_GOTO_16:
              fmt = kFmt20t;
              break;
          case OP_GOTO_32:
              fmt = kFmt30t;
              break;
          case OP_CONST_STRING:
          case OP_CONST_CLASS:
          case OP_CHECK_CAST:
          case OP_NEW_INSTANCE:
          case OP_SGET:
          case OP_SGET_WIDE:
          case OP_SGET_OBJECT:
          case OP_SGET_BOOLEAN:
          case OP_SGET_BYTE:
          case OP_SGET_CHAR:
          case OP_SGET_SHORT:
          case OP_SPUT:
          case OP_SPUT_WIDE:
          case OP_SPUT_OBJECT:
          case OP_SPUT_BOOLEAN:
          case OP_SPUT_BYTE:
          case OP_SPUT_CHAR:
          case OP_SPUT_SHORT:
              fmt = kFmt21c;
              break;
          case OP_CONST_16:
          case OP_CONST_WIDE_16:
              fmt = kFmt21s;
              break;
          case OP_IF_EQZ:
          case OP_IF_NEZ:
          case OP_IF_LTZ:
          case OP_IF_GEZ:
          case OP_IF_GTZ:
          case OP_IF_LEZ:
              fmt = kFmt21t;
              break;
          case OP_FILL_ARRAY_DATA:
          case OP_PACKED_SWITCH:
          case OP_SPARSE_SWITCH:
              fmt = kFmt31t;
              break;
          case OP_ADD_INT_LIT8:
          case OP_RSUB_INT_LIT8:
          case OP_MUL_INT_LIT8:
          case OP_DIV_INT_LIT8:
          case OP_REM_INT_LIT8:
          case OP_AND_INT_LIT8:
          case OP_OR_INT_LIT8:
          case OP_XOR_INT_LIT8:
          case OP_SHL_INT_LIT8:
          case OP_SHR_INT_LIT8:
          case OP_USHR_INT_LIT8:
              fmt = kFmt22b;
              break;
          case OP_INSTANCE_OF:
          case OP_NEW_ARRAY:
          case OP_IGET:
          case OP_IGET_WIDE:
          case OP_IGET_OBJECT:
          case OP_IGET_BOOLEAN:
          case OP_IGET_BYTE:
          case OP_IGET_CHAR:
          case OP_IGET_SHORT:
          case OP_IPUT:
          case OP_IPUT_WIDE:
          case OP_IPUT_OBJECT:
          case OP_IPUT_BOOLEAN:
          case OP_IPUT_BYTE:
          case OP_IPUT_CHAR:
          case OP_IPUT_SHORT:
              fmt = kFmt22c;
              break;
          case OP_ADD_INT_LIT16:
          case OP_RSUB_INT:
          case OP_MUL_INT_LIT16:
          case OP_DIV_INT_LIT16:
          case OP_REM_INT_LIT16:
          case OP_AND_INT_LIT16:
          case OP_OR_INT_LIT16:
          case OP_XOR_INT_LIT16:
              fmt = kFmt22s;
              break;
          case OP_IF_EQ:
          case OP_IF_NE:
          case OP_IF_LT:
          case OP_IF_GE:
          case OP_IF_GT:
          case OP_IF_LE:
              fmt = kFmt22t;
              break;
          case OP_MOVE_FROM16:
          case OP_MOVE_WIDE_FROM16:
          case OP_MOVE_OBJECT_FROM16:
              fmt = kFmt22x;
              break;
          case OP_CMPL_FLOAT:
          case OP_CMPG_FLOAT:
          case OP_CMPL_DOUBLE:
          case OP_CMPG_DOUBLE:
          case OP_CMP_LONG:
          case OP_AGET:
          case OP_AGET_WIDE:
          case OP_AGET_OBJECT:
          case OP_AGET_BOOLEAN:
          case OP_AGET_BYTE:
          case OP_AGET_CHAR:
          case OP_AGET_SHORT:
          case OP_APUT:
          case OP_APUT_WIDE:
          case OP_APUT_OBJECT:
          case OP_APUT_BOOLEAN:
          case OP_APUT_BYTE:
          case OP_APUT_CHAR:
          case OP_APUT_SHORT:
          case OP_ADD_INT:
          case OP_SUB_INT:
          case OP_MUL_INT:
          case OP_DIV_INT:
          case OP_REM_INT:
          case OP_AND_INT:
          case OP_OR_INT:
          case OP_XOR_INT:
          case OP_SHL_INT:
          case OP_SHR_INT:
          case OP_USHR_INT:
          case OP_ADD_LONG:
          case OP_SUB_LONG:
          case OP_MUL_LONG:
          case OP_DIV_LONG:
          case OP_REM_LONG:
          case OP_AND_LONG:
          case OP_OR_LONG:
          case OP_XOR_LONG:
          case OP_SHL_LONG:
          case OP_SHR_LONG:
          case OP_USHR_LONG:
          case OP_ADD_FLOAT:
          case OP_SUB_FLOAT:
          case OP_MUL_FLOAT:
          case OP_DIV_FLOAT:
          case OP_REM_FLOAT:
          case OP_ADD_DOUBLE:
          case OP_SUB_DOUBLE:
          case OP_MUL_DOUBLE:
          case OP_DIV_DOUBLE:
          case OP_REM_DOUBLE:
              fmt = kFmt23x;
              break;
          case OP_CONST:
          case OP_CONST_WIDE_32:
              fmt = kFmt31i;
              break;
          case OP_CONST_STRING_JUMBO:
              fmt = kFmt31c;
              break;
          case OP_MOVE_16:
          case OP_MOVE_WIDE_16:
          case OP_MOVE_OBJECT_16:
              fmt = kFmt32x;
              break;
          case OP_FILLED_NEW_ARRAY:
          case OP_INVOKE_VIRTUAL:
          case OP_INVOKE_SUPER:
          case OP_INVOKE_DIRECT:
          case OP_INVOKE_STATIC:
          case OP_INVOKE_INTERFACE:
              fmt = kFmt35c;
              break;
          case OP_FILLED_NEW_ARRAY_RANGE:
          case OP_INVOKE_VIRTUAL_RANGE:
          case OP_INVOKE_SUPER_RANGE:
          case OP_INVOKE_DIRECT_RANGE:
          case OP_INVOKE_STATIC_RANGE:
          case OP_INVOKE_INTERFACE_RANGE:
              fmt = kFmt3rc;
              break;
          case OP_CONST_WIDE:
              fmt = kFmt51l;
              break;
  
          /*
           * Optimized instructions.
           */
          case OP_THROW_VERIFICATION_ERROR:
              fmt = kFmt20bc;
              break;
          case OP_IGET_QUICK:
          case OP_IGET_WIDE_QUICK:
          case OP_IGET_OBJECT_QUICK:
          case OP_IPUT_QUICK:
          case OP_IPUT_WIDE_QUICK:
          case OP_IPUT_OBJECT_QUICK:
              fmt = kFmt22cs;
              break;
          case OP_INVOKE_VIRTUAL_QUICK:
          case OP_INVOKE_SUPER_QUICK:
              fmt = kFmt35ms;
              break;
          case OP_INVOKE_VIRTUAL_QUICK_RANGE:
          case OP_INVOKE_SUPER_QUICK_RANGE:
              fmt = kFmt3rms;
              break;
          case OP_EXECUTE_INLINE:
              fmt = kFmt3inline;
              break;
          case OP_EXECUTE_INLINE_RANGE:
              fmt = kFmt3rinline;
              break;
          case OP_INVOKE_DIRECT_EMPTY:
              fmt = kFmt35c;
              break;
  
          /* these should never appear when scanning code */
          case OP_UNUSED_3E:
          case OP_UNUSED_3F:
          case OP_UNUSED_40:
          case OP_UNUSED_41:
          case OP_UNUSED_42:
          case OP_UNUSED_43:
          case OP_UNUSED_73:
          case OP_UNUSED_79:
          case OP_UNUSED_7A:
          case OP_UNUSED_E3:
          case OP_UNUSED_E4:
          case OP_UNUSED_E5:
          case OP_UNUSED_E6:
          case OP_UNUSED_E7:
          case OP_UNUSED_E8:
          case OP_UNUSED_E9:
          case OP_UNUSED_EA:
          case OP_UNUSED_EB:
          case OP_BREAKPOINT:
          case OP_UNUSED_F1:
          case OP_UNUSED_FC:
          case OP_UNUSED_FD:
          case OP_UNUSED_FE:
          case OP_UNUSED_FF:
              fmt = kFmtUnknown;
              break;
  
          /*
           * DO NOT add a "default" clause here.  Without it the compiler will
           * complain if an instruction is missing (which is desirable).
           */
          }
  
          instFmt[opc] = fmt;
      }
  
      return instFmt;
  }
  
  /*
   * Copied from InterpCore.h.  Used for instruction decoding.
   */
  #define FETCH(_offset)      (insns[(_offset)])
  #define INST_INST(_inst)    ((_inst) & 0xff)
  #define INST_A(_inst)       (((u2)(_inst) >> 8) & 0x0f)
  #define INST_B(_inst)       ((u2)(_inst) >> 12)
  #define INST_AA(_inst)      ((_inst) >> 8)
  
  /*
   * Decode the instruction pointed to by "insns".
   *
   * Fills out the pieces of "pDec" that are affected by the current
   * instruction.  Does not touch anything else.
   */
  void dexDecodeInstruction(const InstructionFormat* fmts, const u2* insns,
      DecodedInstruction* pDec)
  {
      u2 inst = *insns;
  
      pDec->opCode = (OpCode) INST_INST(inst);
  
      switch (dexGetInstrFormat(fmts, pDec->opCode)) {
      case kFmt10x:       // op
          /* nothing to do; copy the AA bits out for the verifier */
          pDec->vA = INST_AA(inst);
          break;
      case kFmt12x:       // op vA, vB
          pDec->vA = INST_A(inst);
          pDec->vB = INST_B(inst);
          break;
      case kFmt11n:       // op vA, #+B
          pDec->vA = INST_A(inst); 
          pDec->vB = (s4) (INST_B(inst) << 28) >> 28; // sign extend 4-bit value
          break;
      case kFmt11x:       // op vAA
          pDec->vA = INST_AA(inst);
          break;
      case kFmt10t:       // op +AA
          pDec->vA = (s1) INST_AA(inst);              // sign-extend 8-bit value
          break;
      case kFmt20t:       // op +AAAA
          pDec->vA = (s2) FETCH(1);                   // sign-extend 16-bit value
          break;
      case kFmt20bc:      // op AA, thing@BBBB
      case kFmt21c:       // op vAA, thing@BBBB
      case kFmt22x:       // op vAA, vBBBB
          pDec->vA = INST_AA(inst);
          pDec->vB = FETCH(1);
          break;
      case kFmt21s:       // op vAA, #+BBBB
      case kFmt21t:       // op vAA, +BBBB
          pDec->vA = INST_AA(inst);
          pDec->vB = (s2) FETCH(1);                   // sign-extend 16-bit value
          break;
      case kFmt21h:       // op vAA, #+BBBB0000[00000000]
          pDec->vA = INST_AA(inst);
          /*
           * The value should be treated as right-zero-extended, but we don't
           * actually do that here. Among other things, we don't know if it's
           * the top bits of a 32- or 64-bit value.
           */
          pDec->vB = FETCH(1);
          break;
      case kFmt23x:       // op vAA, vBB, vCC
          pDec->vA = INST_AA(inst);
          pDec->vB = FETCH(1) & 0xff;
          pDec->vC = FETCH(1) >> 8;
          break;
      case kFmt22b:       // op vAA, vBB, #+CC
          pDec->vA = INST_AA(inst);
          pDec->vB = FETCH(1) & 0xff;
          pDec->vC = (s1) (FETCH(1) >> 8);            // sign-extend 8-bit value
          break;
      case kFmt22s:       // op vA, vB, #+CCCC
      case kFmt22t:       // op vA, vB, +CCCC
          pDec->vA = INST_A(inst);
          pDec->vB = INST_B(inst);
          pDec->vC = (s2) FETCH(1);                   // sign-extend 16-bit value
          break;
      case kFmt22c:       // op vA, vB, thing@CCCC
      case kFmt22cs:      // [opt] op vA, vB, field offset CCCC
          pDec->vA = INST_A(inst);
          pDec->vB = INST_B(inst);
          pDec->vC = FETCH(1);
          break;
      case kFmt30t:        // op +AAAAAAAA
          pDec->vA = FETCH(1) | ((u4) FETCH(2) << 16); // signed 32-bit value
          break;
      case kFmt31t:       // op vAA, +BBBBBBBB
      case kFmt31c:       // op vAA, thing@BBBBBBBB
          pDec->vA = INST_AA(inst);
          pDec->vB = FETCH(1) | ((u4) FETCH(2) << 16); // 32-bit value
          break;
      case kFmt32x:       // op vAAAA, vBBBB
          pDec->vA = FETCH(1);
          pDec->vB = FETCH(2);
          break;
      case kFmt31i:       // op vAA, #+BBBBBBBB
          pDec->vA = INST_AA(inst);
          pDec->vB = FETCH(1) | ((u4) FETCH(2) << 16);
          break;
      case kFmt35c:       // op vB, {vD..vG,vA}, thing@CCCC
      case kFmt35ms:      // [opt] invoke-virtual+super
          {
              /*
               * The lettering changes that came about when we went from 4 args
               * to 5 made the "range" versions of the calls different from
               * the non-range versions.  We have the choice between decoding
               * them the way the spec shows and having lots of conditionals
               * in the verifier, or mapping the values onto their original
               * registers and leaving the verifier intact.
               *
               * Current plan is to leave the verifier alone.  We can fix it
               * later if it's architecturally unbearable.
               *
               * Bottom line: method constant is always in vB.
               */
              u2 regList;
              int i, count;
  
              pDec->vA = INST_B(inst);
              pDec->vB = FETCH(1);
              regList = FETCH(2);
  
              if (pDec->vA > 5) {
                  LOGW("Invalid arg count in 35c/35ms (%d)\n", pDec->vA);
                  goto bail;
              }
              count = pDec->vA;
              if (count == 5) {
                  /* 5th arg comes from A field in instruction */
                  pDec->arg[4] = INST_A(inst);
                  count--;
              }
              for (i = 0; i < count; i++) {
                  pDec->arg[i] = regList & 0x0f;
                  regList >>= 4;
              }
              /* copy arg[0] to vC; we don't have vD/vE/vF, so ignore those */
              if (pDec->vA > 0)
                  pDec->vC = pDec->arg[0];
          }
          break;
      case kFmt3inline:   // [opt] inline invoke
          {
              u2 regList;
              int i;
  
              pDec->vA = INST_B(inst);
              pDec->vB = FETCH(1);
              regList = FETCH(2);
  
              if (pDec->vA > 4) {
                  LOGW("Invalid arg count in 3inline (%d)\n", pDec->vA);
                  goto bail;
              }
              for (i = 0; i < (int) pDec->vA; i++) {
                  pDec->arg[i] = regList & 0x0f;
                  regList >>= 4;
              }
              /* copy arg[0] to vC; we don't have vD/vE/vF, so ignore those */
              if (pDec->vA > 0)
                  pDec->vC = pDec->arg[0];
          }
          break;
      case kFmt35fs:      // [opt] invoke-interface
          assert(false);  // TODO
          break;
      case kFmt3rc:       // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
      case kFmt3rms:      // [opt] invoke-virtual+super/range
      case kFmt3rinline:  // [opt] execute-inline/range
          pDec->vA = INST_AA(inst);
          pDec->vB = FETCH(1);
          pDec->vC = FETCH(2);
          break;
      case kFmt3rfs:      // [opt] invoke-interface/range
          assert(false);  // TODO
          break;
      case kFmt51l:       // op vAA, #+BBBBBBBBBBBBBBBB
          pDec->vA = INST_AA(inst);
          pDec->vB_wide = FETCH(1);
          pDec->vB_wide |= (u8)FETCH(2) << 16;
          pDec->vB_wide |= (u8)FETCH(3) << 32;
          pDec->vB_wide |= (u8)FETCH(4) << 48;
          break;
      default:
          LOGW("Can't decode unexpected format %d (op=%d)\n",
              dexGetInstrFormat(fmts, pDec->opCode), pDec->opCode);
          assert(false);
          break;
      }
  
  bail:
      ;
  }
  
  /*
   * Return the width of the specified instruction, or 0 if not defined.  Also
   * works for special OP_NOP entries, including switch statement data tables
   * and array data.
   */
  int dexGetInstrOrTableWidthAbs(const InstructionWidth* widths, const u2* insns)
  {
      int width;
  
      if (*insns == kPackedSwitchSignature) {
          width = 4 + insns[1] * 2;
      } else if (*insns == kSparseSwitchSignature) {
          width = 2 + insns[1] * 4;
      } else if (*insns == kArrayDataSignature) {
          u2 elemWidth = insns[1];
          u4 len = insns[2] | (((u4)insns[3]) << 16);
          width = 4 + (elemWidth * len + 1) / 2;
      } else {
          width = dexGetInstrWidthAbs(widths, INST_INST(insns[0]));
      }
      return width;
  }
  