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