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