Home | History | Annotate | Download | only in runtime
      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 <inttypes.h>
     20 
     21 #include <iomanip>
     22 #include <sstream>
     23 
     24 #include "base/stringprintf.h"
     25 #include "dex_file-inl.h"
     26 #include "utils.h"
     27 
     28 namespace art {
     29 
     30 const char* const Instruction::kInstructionNames[] = {
     31 #define INSTRUCTION_NAME(o, c, pname, f, r, i, a, v) pname,
     32 #include "dex_instruction_list.h"
     33   DEX_INSTRUCTION_LIST(INSTRUCTION_NAME)
     34 #undef DEX_INSTRUCTION_LIST
     35 #undef INSTRUCTION_NAME
     36 };
     37 
     38 Instruction::Format const Instruction::kInstructionFormats[] = {
     39 #define INSTRUCTION_FORMAT(o, c, p, format, r, i, a, v) format,
     40 #include "dex_instruction_list.h"
     41   DEX_INSTRUCTION_LIST(INSTRUCTION_FORMAT)
     42 #undef DEX_INSTRUCTION_LIST
     43 #undef INSTRUCTION_FORMAT
     44 };
     45 
     46 int const Instruction::kInstructionFlags[] = {
     47 #define INSTRUCTION_FLAGS(o, c, p, f, r, i, flags, v) flags,
     48 #include "dex_instruction_list.h"
     49   DEX_INSTRUCTION_LIST(INSTRUCTION_FLAGS)
     50 #undef DEX_INSTRUCTION_LIST
     51 #undef INSTRUCTION_FLAGS
     52 };
     53 
     54 int const Instruction::kInstructionVerifyFlags[] = {
     55 #define INSTRUCTION_VERIFY_FLAGS(o, c, p, f, r, i, a, vflags) vflags,
     56 #include "dex_instruction_list.h"
     57   DEX_INSTRUCTION_LIST(INSTRUCTION_VERIFY_FLAGS)
     58 #undef DEX_INSTRUCTION_LIST
     59 #undef INSTRUCTION_VERIFY_FLAGS
     60 };
     61 
     62 int const Instruction::kInstructionSizeInCodeUnits[] = {
     63 #define INSTRUCTION_SIZE(opcode, c, p, format, r, i, a, v) \
     64     ((opcode == NOP)                        ? -1 : \
     65      ((format >= k10x) && (format <= k10t)) ?  1 : \
     66      ((format >= k20t) && (format <= k22c)) ?  2 : \
     67      ((format >= k32x) && (format <= k3rc)) ?  3 : \
     68       (format == k51l)                      ?  5 : -1),
     69 #include "dex_instruction_list.h"
     70   DEX_INSTRUCTION_LIST(INSTRUCTION_SIZE)
     71 #undef DEX_INSTRUCTION_LIST
     72 #undef INSTRUCTION_SIZE
     73 };
     74 
     75 int32_t Instruction::GetTargetOffset() const {
     76   switch (FormatOf(Opcode())) {
     77     // Cases for conditional branches follow.
     78     case k22t: return VRegC_22t();
     79     case k21t: return VRegB_21t();
     80     // Cases for unconditional branches follow.
     81     case k10t: return VRegA_10t();
     82     case k20t: return VRegA_20t();
     83     case k30t: return VRegA_30t();
     84     default: LOG(FATAL) << "Tried to access the branch offset of an instruction " << Name() <<
     85         " which does not have a target operand.";
     86   }
     87   return 0;
     88 }
     89 
     90 bool Instruction::CanFlowThrough() const {
     91   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
     92   uint16_t insn = *insns;
     93   Code opcode = static_cast<Code>(insn & 0xFF);
     94   return  FlagsOf(opcode) & Instruction::kContinue;
     95 }
     96 
     97 size_t Instruction::SizeInCodeUnitsComplexOpcode() const {
     98   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
     99   // Handle special NOP encoded variable length sequences.
    100   switch (*insns) {
    101     case kPackedSwitchSignature:
    102       return (4 + insns[1] * 2);
    103     case kSparseSwitchSignature:
    104       return (2 + insns[1] * 4);
    105     case kArrayDataSignature: {
    106       uint16_t element_size = insns[1];
    107       uint32_t length = insns[2] | (((uint32_t)insns[3]) << 16);
    108       // The plus 1 is to round up for odd size and width.
    109       return (4 + (element_size * length + 1) / 2);
    110     }
    111     default:
    112       if ((*insns & 0xFF) == 0) {
    113         return 1;  // NOP.
    114       } else {
    115         LOG(FATAL) << "Unreachable: " << DumpString(nullptr);
    116         UNREACHABLE();
    117       }
    118   }
    119 }
    120 
    121 std::string Instruction::DumpHex(size_t code_units) const {
    122   size_t inst_length = SizeInCodeUnits();
    123   if (inst_length > code_units) {
    124     inst_length = code_units;
    125   }
    126   std::ostringstream os;
    127   const uint16_t* insn = reinterpret_cast<const uint16_t*>(this);
    128   for (size_t i = 0; i < inst_length; i++) {
    129     os << StringPrintf("0x%04x", insn[i]) << " ";
    130   }
    131   for (size_t i = inst_length; i < code_units; i++) {
    132     os << "       ";
    133   }
    134   return os.str();
    135 }
    136 
    137 std::string Instruction::DumpHexLE(size_t instr_code_units) const {
    138   size_t inst_length = SizeInCodeUnits();
    139   if (inst_length > instr_code_units) {
    140     inst_length = instr_code_units;
    141   }
    142   std::ostringstream os;
    143   const uint16_t* insn = reinterpret_cast<const uint16_t*>(this);
    144   for (size_t i = 0; i < inst_length; i++) {
    145     os << StringPrintf("%02x%02x", static_cast<uint8_t>(insn[i] & 0x00FF),
    146                        static_cast<uint8_t>((insn[i] & 0xFF00) >> 8)) << " ";
    147   }
    148   for (size_t i = inst_length; i < instr_code_units; i++) {
    149     os << "     ";
    150   }
    151   return os.str();
    152 }
    153 
    154 std::string Instruction::DumpString(const DexFile* file) const {
    155   std::ostringstream os;
    156   const char* opcode = kInstructionNames[Opcode()];
    157   switch (FormatOf(Opcode())) {
    158     case k10x:  os << opcode; break;
    159     case k12x:  os << StringPrintf("%s v%d, v%d", opcode, VRegA_12x(), VRegB_12x()); break;
    160     case k11n:  os << StringPrintf("%s v%d, #%+d", opcode, VRegA_11n(), VRegB_11n()); break;
    161     case k11x:  os << StringPrintf("%s v%d", opcode, VRegA_11x()); break;
    162     case k10t:  os << StringPrintf("%s %+d", opcode, VRegA_10t()); break;
    163     case k20t:  os << StringPrintf("%s %+d", opcode, VRegA_20t()); break;
    164     case k22x:  os << StringPrintf("%s v%d, v%d", opcode, VRegA_22x(), VRegB_22x()); break;
    165     case k21t:  os << StringPrintf("%s v%d, %+d", opcode, VRegA_21t(), VRegB_21t()); break;
    166     case k21s:  os << StringPrintf("%s v%d, #%+d", opcode, VRegA_21s(), VRegB_21s()); break;
    167     case k21h: {
    168         // op vAA, #+BBBB0000[00000000]
    169         if (Opcode() == CONST_HIGH16) {
    170           uint32_t value = VRegB_21h() << 16;
    171           os << StringPrintf("%s v%d, #int %+d // 0x%x", opcode, VRegA_21h(), value, value);
    172         } else {
    173           uint64_t value = static_cast<uint64_t>(VRegB_21h()) << 48;
    174           os << StringPrintf("%s v%d, #long %+" PRId64 " // 0x%" PRIx64, opcode, VRegA_21h(),
    175                              value, value);
    176         }
    177       }
    178       break;
    179     case k21c: {
    180       switch (Opcode()) {
    181         case CONST_STRING:
    182           if (file != nullptr) {
    183             uint32_t string_idx = VRegB_21c();
    184             os << StringPrintf("const-string v%d, %s // string@%d", VRegA_21c(),
    185                                PrintableString(file->StringDataByIdx(string_idx)).c_str(), string_idx);
    186             break;
    187           }
    188           FALLTHROUGH_INTENDED;
    189         case CHECK_CAST:
    190         case CONST_CLASS:
    191         case NEW_INSTANCE:
    192           if (file != nullptr) {
    193             uint32_t type_idx = VRegB_21c();
    194             os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyType(type_idx, *file)
    195                << " // type@" << type_idx;
    196             break;
    197           }
    198           FALLTHROUGH_INTENDED;
    199         case SGET:
    200         case SGET_WIDE:
    201         case SGET_OBJECT:
    202         case SGET_BOOLEAN:
    203         case SGET_BYTE:
    204         case SGET_CHAR:
    205         case SGET_SHORT:
    206           if (file != nullptr) {
    207             uint32_t field_idx = VRegB_21c();
    208             os << opcode << "  v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
    209                << " // field@" << field_idx;
    210             break;
    211           }
    212           FALLTHROUGH_INTENDED;
    213         case SPUT:
    214         case SPUT_WIDE:
    215         case SPUT_OBJECT:
    216         case SPUT_BOOLEAN:
    217         case SPUT_BYTE:
    218         case SPUT_CHAR:
    219         case SPUT_SHORT:
    220           if (file != nullptr) {
    221             uint32_t field_idx = VRegB_21c();
    222             os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
    223                << " // field@" << field_idx;
    224             break;
    225           }
    226           FALLTHROUGH_INTENDED;
    227         default:
    228           os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c());
    229           break;
    230       }
    231       break;
    232     }
    233     case k23x:  os << StringPrintf("%s v%d, v%d, v%d", opcode, VRegA_23x(), VRegB_23x(), VRegC_23x()); break;
    234     case k22b:  os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22b(), VRegB_22b(), VRegC_22b()); break;
    235     case k22t:  os << StringPrintf("%s v%d, v%d, %+d", opcode, VRegA_22t(), VRegB_22t(), VRegC_22t()); break;
    236     case k22s:  os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22s(), VRegB_22s(), VRegC_22s()); break;
    237     case k22c: {
    238       switch (Opcode()) {
    239         case IGET:
    240         case IGET_WIDE:
    241         case IGET_OBJECT:
    242         case IGET_BOOLEAN:
    243         case IGET_BYTE:
    244         case IGET_CHAR:
    245         case IGET_SHORT:
    246           if (file != nullptr) {
    247             uint32_t field_idx = VRegC_22c();
    248             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
    249                << PrettyField(field_idx, *file, true) << " // field@" << field_idx;
    250             break;
    251           }
    252           FALLTHROUGH_INTENDED;
    253         case IGET_QUICK:
    254         case IGET_OBJECT_QUICK:
    255           if (file != nullptr) {
    256             uint32_t field_idx = VRegC_22c();
    257             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
    258                << "// offset@" << field_idx;
    259             break;
    260           }
    261           FALLTHROUGH_INTENDED;
    262         case IPUT:
    263         case IPUT_WIDE:
    264         case IPUT_OBJECT:
    265         case IPUT_BOOLEAN:
    266         case IPUT_BYTE:
    267         case IPUT_CHAR:
    268         case IPUT_SHORT:
    269           if (file != nullptr) {
    270             uint32_t field_idx = VRegC_22c();
    271             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
    272                << PrettyField(field_idx, *file, true) << " // field@" << field_idx;
    273             break;
    274           }
    275           FALLTHROUGH_INTENDED;
    276         case IPUT_QUICK:
    277         case IPUT_OBJECT_QUICK:
    278           if (file != nullptr) {
    279             uint32_t field_idx = VRegC_22c();
    280             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
    281                << "// offset@" << field_idx;
    282             break;
    283           }
    284           FALLTHROUGH_INTENDED;
    285         case INSTANCE_OF:
    286           if (file != nullptr) {
    287             uint32_t type_idx = VRegC_22c();
    288             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
    289                << PrettyType(type_idx, *file) << " // type@" << type_idx;
    290             break;
    291           }
    292           FALLTHROUGH_INTENDED;
    293         case NEW_ARRAY:
    294           if (file != nullptr) {
    295             uint32_t type_idx = VRegC_22c();
    296             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
    297                << PrettyType(type_idx, *file) << " // type@" << type_idx;
    298             break;
    299           }
    300           FALLTHROUGH_INTENDED;
    301         default:
    302           os << StringPrintf("%s v%d, v%d, thing@%d", opcode, VRegA_22c(), VRegB_22c(), VRegC_22c());
    303           break;
    304       }
    305       break;
    306     }
    307     case k32x:  os << StringPrintf("%s v%d, v%d", opcode, VRegA_32x(), VRegB_32x()); break;
    308     case k30t:  os << StringPrintf("%s %+d", opcode, VRegA_30t()); break;
    309     case k31t:  os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break;
    310     case k31i:  os << StringPrintf("%s v%d, #%+d", opcode, VRegA_31i(), VRegB_31i()); break;
    311     case k31c:
    312       if (Opcode() == CONST_STRING_JUMBO) {
    313         uint32_t string_idx = VRegB_31c();
    314         if (file != nullptr) {
    315           os << StringPrintf("%s v%d, %s // string@%d", opcode, VRegA_31c(),
    316                              PrintableString(file->StringDataByIdx(string_idx)).c_str(),
    317                              string_idx);
    318         } else {
    319           os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx);
    320         }
    321       } else {
    322         os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break;
    323       }
    324       break;
    325     case k35c: {
    326       uint32_t arg[5];
    327       GetVarArgs(arg);
    328       switch (Opcode()) {
    329         case FILLED_NEW_ARRAY:
    330         {
    331           const int32_t a = VRegA_35c();
    332           os << opcode << " {";
    333           for (int i = 0; i < a; ++i) {
    334             if (i > 0) {
    335               os << ", ";
    336             }
    337             os << "v" << arg[i];
    338           }
    339           os << "}, type@" << VRegB_35c();
    340         }
    341         break;
    342 
    343         case INVOKE_VIRTUAL:
    344         case INVOKE_SUPER:
    345         case INVOKE_DIRECT:
    346         case INVOKE_STATIC:
    347         case INVOKE_INTERFACE:
    348           if (file != nullptr) {
    349             os << opcode << " {";
    350             uint32_t method_idx = VRegB_35c();
    351             for (size_t i = 0; i < VRegA_35c(); ++i) {
    352               if (i != 0) {
    353                 os << ", ";
    354               }
    355               os << "v" << arg[i];
    356             }
    357             os << "}, " << PrettyMethod(method_idx, *file) << " // method@" << method_idx;
    358             break;
    359           }
    360           FALLTHROUGH_INTENDED;
    361         case INVOKE_VIRTUAL_QUICK:
    362           if (file != nullptr) {
    363             os << opcode << " {";
    364             uint32_t method_idx = VRegB_35c();
    365             for (size_t i = 0; i < VRegA_35c(); ++i) {
    366               if (i != 0) {
    367                 os << ", ";
    368               }
    369               os << "v" << arg[i];
    370             }
    371             os << "},  // vtable@" << method_idx;
    372             break;
    373           }
    374           FALLTHROUGH_INTENDED;
    375         default:
    376           os << opcode << " {v" << arg[0] << ", v" << arg[1] << ", v" << arg[2]
    377                        << ", v" << arg[3] << ", v" << arg[4] << "}, thing@" << VRegB_35c();
    378           break;
    379       }
    380       break;
    381     }
    382     case k3rc: {
    383       switch (Opcode()) {
    384         case INVOKE_VIRTUAL_RANGE:
    385         case INVOKE_SUPER_RANGE:
    386         case INVOKE_DIRECT_RANGE:
    387         case INVOKE_STATIC_RANGE:
    388         case INVOKE_INTERFACE_RANGE:
    389           if (file != nullptr) {
    390             uint32_t method_idx = VRegB_3rc();
    391             os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1))
    392                << PrettyMethod(method_idx, *file) << " // method@" << method_idx;
    393             break;
    394           }
    395           FALLTHROUGH_INTENDED;
    396         case INVOKE_VIRTUAL_RANGE_QUICK:
    397           if (file != nullptr) {
    398             uint32_t method_idx = VRegB_3rc();
    399             os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1))
    400                << "// vtable@" << method_idx;
    401             break;
    402           }
    403           FALLTHROUGH_INTENDED;
    404         default:
    405           os << StringPrintf("%s, {v%d .. v%d}, thing@%d", opcode, VRegC_3rc(),
    406                              (VRegC_3rc() + VRegA_3rc() - 1), VRegB_3rc());
    407           break;
    408       }
    409       break;
    410     }
    411     case k51l: os << StringPrintf("%s v%d, #%+" PRId64, opcode, VRegA_51l(), VRegB_51l()); break;
    412     default: os << " unknown format (" << DumpHex(5) << ")"; break;
    413   }
    414   return os.str();
    415 }
    416 
    417 std::ostream& operator<<(std::ostream& os, const Instruction::Code& code) {
    418   return os << Instruction::Name(code);
    419 }
    420 
    421 }  // namespace art
    422