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 "android-base/stringprintf.h"
     25 
     26 #include "dex_file-inl.h"
     27 #include "utils.h"
     28 
     29 namespace art {
     30 
     31 using android::base::StringPrintf;
     32 
     33 const char* const Instruction::kInstructionNames[] = {
     34 #define INSTRUCTION_NAME(o, c, pname, f, i, a, e, v) pname,
     35 #include "dex_instruction_list.h"
     36   DEX_INSTRUCTION_LIST(INSTRUCTION_NAME)
     37 #undef DEX_INSTRUCTION_LIST
     38 #undef INSTRUCTION_NAME
     39 };
     40 
     41 static_assert(sizeof(Instruction::InstructionDescriptor) == 8u, "Unexpected descriptor size");
     42 
     43 static constexpr int8_t InstructionSizeInCodeUnitsByOpcode(Instruction::Code opcode,
     44                                                            Instruction::Format format) {
     45   if (opcode == Instruction::Code::NOP) {
     46     return -1;
     47   } else if ((format >= Instruction::Format::k10x) && (format <= Instruction::Format::k10t)) {
     48     return 1;
     49   } else if ((format >= Instruction::Format::k20t) && (format <= Instruction::Format::k22c)) {
     50     return 2;
     51   } else if ((format >= Instruction::Format::k32x) && (format <= Instruction::Format::k3rc)) {
     52     return 3;
     53   } else if ((format >= Instruction::Format::k45cc) && (format <= Instruction::Format::k4rcc)) {
     54     return 4;
     55   } else if (format == Instruction::Format::k51l) {
     56     return 5;
     57   } else {
     58     return -1;
     59   }
     60 }
     61 
     62 Instruction::InstructionDescriptor const Instruction::kInstructionDescriptors[] = {
     63 #define INSTRUCTION_DESCR(opcode, c, p, format, index, flags, eflags, vflags) \
     64     { vflags, \
     65       format, \
     66       index, \
     67       flags, \
     68       InstructionSizeInCodeUnitsByOpcode((c), (format)), \
     69     },
     70 #include "dex_instruction_list.h"
     71   DEX_INSTRUCTION_LIST(INSTRUCTION_DESCR)
     72 #undef DEX_INSTRUCTION_LIST
     73 #undef INSTRUCTION_DESCR
     74 };
     75 
     76 int32_t Instruction::GetTargetOffset() const {
     77   switch (FormatOf(Opcode())) {
     78     // Cases for conditional branches follow.
     79     case k22t: return VRegC_22t();
     80     case k21t: return VRegB_21t();
     81     // Cases for unconditional branches follow.
     82     case k10t: return VRegA_10t();
     83     case k20t: return VRegA_20t();
     84     case k30t: return VRegA_30t();
     85     default: LOG(FATAL) << "Tried to access the branch offset of an instruction " << Name() <<
     86         " which does not have a target operand.";
     87   }
     88   return 0;
     89 }
     90 
     91 bool Instruction::CanFlowThrough() const {
     92   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
     93   uint16_t insn = *insns;
     94   Code opcode = static_cast<Code>(insn & 0xFF);
     95   return  FlagsOf(opcode) & Instruction::kContinue;
     96 }
     97 
     98 size_t Instruction::SizeInCodeUnitsComplexOpcode() const {
     99   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
    100   // Handle special NOP encoded variable length sequences.
    101   switch (*insns) {
    102     case kPackedSwitchSignature:
    103       return (4 + insns[1] * 2);
    104     case kSparseSwitchSignature:
    105       return (2 + insns[1] * 4);
    106     case kArrayDataSignature: {
    107       uint16_t element_size = insns[1];
    108       uint32_t length = insns[2] | (((uint32_t)insns[3]) << 16);
    109       // The plus 1 is to round up for odd size and width.
    110       return (4 + (element_size * length + 1) / 2);
    111     }
    112     default:
    113       if ((*insns & 0xFF) == 0) {
    114         return 1;  // NOP.
    115       } else {
    116         LOG(FATAL) << "Unreachable: " << DumpString(nullptr);
    117         UNREACHABLE();
    118       }
    119   }
    120 }
    121 
    122 std::string Instruction::DumpHex(size_t code_units) const {
    123   size_t inst_length = SizeInCodeUnits();
    124   if (inst_length > code_units) {
    125     inst_length = code_units;
    126   }
    127   std::ostringstream os;
    128   const uint16_t* insn = reinterpret_cast<const uint16_t*>(this);
    129   for (size_t i = 0; i < inst_length; i++) {
    130     os << StringPrintf("0x%04x", insn[i]) << " ";
    131   }
    132   for (size_t i = inst_length; i < code_units; i++) {
    133     os << "       ";
    134   }
    135   return os.str();
    136 }
    137 
    138 std::string Instruction::DumpHexLE(size_t instr_code_units) const {
    139   size_t inst_length = SizeInCodeUnits();
    140   if (inst_length > instr_code_units) {
    141     inst_length = instr_code_units;
    142   }
    143   std::ostringstream os;
    144   const uint16_t* insn = reinterpret_cast<const uint16_t*>(this);
    145   for (size_t i = 0; i < inst_length; i++) {
    146     os << StringPrintf("%02x%02x", static_cast<uint8_t>(insn[i] & 0x00FF),
    147                        static_cast<uint8_t>((insn[i] & 0xFF00) >> 8)) << " ";
    148   }
    149   for (size_t i = inst_length; i < instr_code_units; i++) {
    150     os << "     ";
    151   }
    152   return os.str();
    153 }
    154 
    155 std::string Instruction::DumpString(const DexFile* file) const {
    156   std::ostringstream os;
    157   const char* opcode = kInstructionNames[Opcode()];
    158   switch (FormatOf(Opcode())) {
    159     case k10x:  os << opcode; break;
    160     case k12x:  os << StringPrintf("%s v%d, v%d", opcode, VRegA_12x(), VRegB_12x()); break;
    161     case k11n:  os << StringPrintf("%s v%d, #%+d", opcode, VRegA_11n(), VRegB_11n()); break;
    162     case k11x:  os << StringPrintf("%s v%d", opcode, VRegA_11x()); break;
    163     case k10t:  os << StringPrintf("%s %+d", opcode, VRegA_10t()); break;
    164     case k20t:  os << StringPrintf("%s %+d", opcode, VRegA_20t()); break;
    165     case k22x:  os << StringPrintf("%s v%d, v%d", opcode, VRegA_22x(), VRegB_22x()); break;
    166     case k21t:  os << StringPrintf("%s v%d, %+d", opcode, VRegA_21t(), VRegB_21t()); break;
    167     case k21s:  os << StringPrintf("%s v%d, #%+d", opcode, VRegA_21s(), VRegB_21s()); break;
    168     case k21h: {
    169         // op vAA, #+BBBB0000[00000000]
    170         if (Opcode() == CONST_HIGH16) {
    171           uint32_t value = VRegB_21h() << 16;
    172           os << StringPrintf("%s v%d, #int %+d // 0x%x", opcode, VRegA_21h(), value, value);
    173         } else {
    174           uint64_t value = static_cast<uint64_t>(VRegB_21h()) << 48;
    175           os << StringPrintf("%s v%d, #long %+" PRId64 " // 0x%" PRIx64, opcode, VRegA_21h(),
    176                              value, value);
    177         }
    178       }
    179       break;
    180     case k21c: {
    181       switch (Opcode()) {
    182         case CONST_STRING:
    183           if (file != nullptr) {
    184             uint32_t string_idx = VRegB_21c();
    185             if (string_idx < file->NumStringIds()) {
    186               os << StringPrintf(
    187                   "const-string v%d, %s // string@%d",
    188                   VRegA_21c(),
    189                   PrintableString(file->StringDataByIdx(dex::StringIndex(string_idx))).c_str(),
    190                   string_idx);
    191             } else {
    192               os << StringPrintf("const-string v%d, <<invalid-string-idx-%d>> // string@%d",
    193                                  VRegA_21c(),
    194                                  string_idx,
    195                                  string_idx);
    196             }
    197             break;
    198           }
    199           FALLTHROUGH_INTENDED;
    200         case CHECK_CAST:
    201         case CONST_CLASS:
    202         case NEW_INSTANCE:
    203           if (file != nullptr) {
    204             dex::TypeIndex type_idx(VRegB_21c());
    205             os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", "
    206                << file->PrettyType(type_idx) << " // type@" << type_idx;
    207             break;
    208           }
    209           FALLTHROUGH_INTENDED;
    210         case SGET:
    211         case SGET_WIDE:
    212         case SGET_OBJECT:
    213         case SGET_BOOLEAN:
    214         case SGET_BYTE:
    215         case SGET_CHAR:
    216         case SGET_SHORT:
    217           if (file != nullptr) {
    218             uint32_t field_idx = VRegB_21c();
    219             os << opcode << "  v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyField(field_idx, true)
    220                << " // field@" << field_idx;
    221             break;
    222           }
    223           FALLTHROUGH_INTENDED;
    224         case SPUT:
    225         case SPUT_WIDE:
    226         case SPUT_OBJECT:
    227         case SPUT_BOOLEAN:
    228         case SPUT_BYTE:
    229         case SPUT_CHAR:
    230         case SPUT_SHORT:
    231           if (file != nullptr) {
    232             uint32_t field_idx = VRegB_21c();
    233             os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyField(field_idx, true)
    234                << " // field@" << field_idx;
    235             break;
    236           }
    237           FALLTHROUGH_INTENDED;
    238         default:
    239           os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c());
    240           break;
    241       }
    242       break;
    243     }
    244     case k23x:  os << StringPrintf("%s v%d, v%d, v%d", opcode, VRegA_23x(), VRegB_23x(), VRegC_23x()); break;
    245     case k22b:  os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22b(), VRegB_22b(), VRegC_22b()); break;
    246     case k22t:  os << StringPrintf("%s v%d, v%d, %+d", opcode, VRegA_22t(), VRegB_22t(), VRegC_22t()); break;
    247     case k22s:  os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22s(), VRegB_22s(), VRegC_22s()); break;
    248     case k22c: {
    249       switch (Opcode()) {
    250         case IGET:
    251         case IGET_WIDE:
    252         case IGET_OBJECT:
    253         case IGET_BOOLEAN:
    254         case IGET_BYTE:
    255         case IGET_CHAR:
    256         case IGET_SHORT:
    257           if (file != nullptr) {
    258             uint32_t field_idx = VRegC_22c();
    259             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
    260                << file->PrettyField(field_idx, true) << " // field@" << field_idx;
    261             break;
    262           }
    263           FALLTHROUGH_INTENDED;
    264         case IGET_QUICK:
    265         case IGET_OBJECT_QUICK:
    266           if (file != nullptr) {
    267             uint32_t field_idx = VRegC_22c();
    268             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
    269                << "// offset@" << field_idx;
    270             break;
    271           }
    272           FALLTHROUGH_INTENDED;
    273         case IPUT:
    274         case IPUT_WIDE:
    275         case IPUT_OBJECT:
    276         case IPUT_BOOLEAN:
    277         case IPUT_BYTE:
    278         case IPUT_CHAR:
    279         case IPUT_SHORT:
    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                << file->PrettyField(field_idx, true) << " // field@" << field_idx;
    284             break;
    285           }
    286           FALLTHROUGH_INTENDED;
    287         case IPUT_QUICK:
    288         case IPUT_OBJECT_QUICK:
    289           if (file != nullptr) {
    290             uint32_t field_idx = VRegC_22c();
    291             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
    292                << "// offset@" << field_idx;
    293             break;
    294           }
    295           FALLTHROUGH_INTENDED;
    296         case INSTANCE_OF:
    297           if (file != nullptr) {
    298             dex::TypeIndex type_idx(VRegC_22c());
    299             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
    300                << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
    301                << " // type@" << type_idx.index_;
    302             break;
    303           }
    304           FALLTHROUGH_INTENDED;
    305         case NEW_ARRAY:
    306           if (file != nullptr) {
    307             dex::TypeIndex type_idx(VRegC_22c());
    308             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
    309                << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
    310                << " // type@" << type_idx.index_;
    311             break;
    312           }
    313           FALLTHROUGH_INTENDED;
    314         default:
    315           os << StringPrintf("%s v%d, v%d, thing@%d", opcode, VRegA_22c(), VRegB_22c(), VRegC_22c());
    316           break;
    317       }
    318       break;
    319     }
    320     case k32x:  os << StringPrintf("%s v%d, v%d", opcode, VRegA_32x(), VRegB_32x()); break;
    321     case k30t:  os << StringPrintf("%s %+d", opcode, VRegA_30t()); break;
    322     case k31t:  os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break;
    323     case k31i:  os << StringPrintf("%s v%d, #%+d", opcode, VRegA_31i(), VRegB_31i()); break;
    324     case k31c:
    325       if (Opcode() == CONST_STRING_JUMBO) {
    326         uint32_t string_idx = VRegB_31c();
    327         if (file != nullptr) {
    328           if (string_idx < file->NumStringIds()) {
    329             os << StringPrintf(
    330                 "%s v%d, %s // string@%d",
    331                 opcode,
    332                 VRegA_31c(),
    333                 PrintableString(file->StringDataByIdx(dex::StringIndex(string_idx))).c_str(),
    334                 string_idx);
    335           } else {
    336             os << StringPrintf("%s v%d, <<invalid-string-idx-%d>> // string@%d",
    337                                opcode,
    338                                VRegA_31c(),
    339                                string_idx,
    340                                string_idx);
    341           }
    342         } else {
    343           os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx);
    344         }
    345       } else {
    346         os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break;
    347       }
    348       break;
    349     case k35c: {
    350       uint32_t arg[kMaxVarArgRegs];
    351       GetVarArgs(arg);
    352       switch (Opcode()) {
    353         case FILLED_NEW_ARRAY:
    354         {
    355           const int32_t a = VRegA_35c();
    356           os << opcode << " {";
    357           for (int i = 0; i < a; ++i) {
    358             if (i > 0) {
    359               os << ", ";
    360             }
    361             os << "v" << arg[i];
    362           }
    363           os << "}, type@" << VRegB_35c();
    364         }
    365         break;
    366 
    367         case INVOKE_VIRTUAL:
    368         case INVOKE_SUPER:
    369         case INVOKE_DIRECT:
    370         case INVOKE_STATIC:
    371         case INVOKE_INTERFACE:
    372           if (file != nullptr) {
    373             os << opcode << " {";
    374             uint32_t method_idx = VRegB_35c();
    375             for (size_t i = 0; i < VRegA_35c(); ++i) {
    376               if (i != 0) {
    377                 os << ", ";
    378               }
    379               os << "v" << arg[i];
    380             }
    381             os << "}, " << file->PrettyMethod(method_idx) << " // method@" << method_idx;
    382             break;
    383           }
    384           FALLTHROUGH_INTENDED;
    385         case INVOKE_VIRTUAL_QUICK:
    386           if (file != nullptr) {
    387             os << opcode << " {";
    388             uint32_t method_idx = VRegB_35c();
    389             for (size_t i = 0; i < VRegA_35c(); ++i) {
    390               if (i != 0) {
    391                 os << ", ";
    392               }
    393               os << "v" << arg[i];
    394             }
    395             os << "},  // vtable@" << method_idx;
    396             break;
    397           }
    398           FALLTHROUGH_INTENDED;
    399         case INVOKE_CUSTOM:
    400           if (file != nullptr) {
    401             os << opcode << " {";
    402             uint32_t call_site_idx = VRegB_35c();
    403             for (size_t i = 0; i < VRegA_35c(); ++i) {
    404               if (i != 0) {
    405                 os << ", ";
    406               }
    407               os << "v" << arg[i];
    408             }
    409             os << "},  // call_site@" << call_site_idx;
    410             break;
    411           }
    412           FALLTHROUGH_INTENDED;
    413         default:
    414           os << opcode << " {v" << arg[0] << ", v" << arg[1] << ", v" << arg[2]
    415                        << ", v" << arg[3] << ", v" << arg[4] << "}, thing@" << VRegB_35c();
    416           break;
    417       }
    418       break;
    419     }
    420     case k3rc: {
    421       uint16_t first_reg = VRegC_3rc();
    422       uint16_t last_reg =  VRegC_3rc() + VRegA_3rc() - 1;
    423       switch (Opcode()) {
    424         case INVOKE_VIRTUAL_RANGE:
    425         case INVOKE_SUPER_RANGE:
    426         case INVOKE_DIRECT_RANGE:
    427         case INVOKE_STATIC_RANGE:
    428         case INVOKE_INTERFACE_RANGE:
    429           if (file != nullptr) {
    430             uint32_t method_idx = VRegB_3rc();
    431             os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
    432                << file->PrettyMethod(method_idx) << " // method@" << method_idx;
    433             break;
    434           }
    435           FALLTHROUGH_INTENDED;
    436         case INVOKE_VIRTUAL_RANGE_QUICK:
    437           if (file != nullptr) {
    438             uint32_t method_idx = VRegB_3rc();
    439             os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
    440                << "// vtable@" << method_idx;
    441             break;
    442           }
    443           FALLTHROUGH_INTENDED;
    444         case INVOKE_CUSTOM_RANGE:
    445           if (file != nullptr) {
    446             uint32_t call_site_idx = VRegB_3rc();
    447             os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
    448                << "// call_site@" << call_site_idx;
    449             break;
    450           }
    451           FALLTHROUGH_INTENDED;
    452         default:
    453           os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
    454              << "thing@" << VRegB_3rc();
    455           break;
    456       }
    457       break;
    458     }
    459     case k45cc: {
    460       uint32_t arg[kMaxVarArgRegs];
    461       GetVarArgs(arg);
    462       uint32_t method_idx = VRegB_45cc();
    463       uint32_t proto_idx = VRegH_45cc();
    464       os << opcode << " {";
    465       for (int i = 0; i < VRegA_45cc(); ++i) {
    466         if (i != 0) {
    467           os << ", ";
    468         }
    469         os << "v" << arg[i];
    470       }
    471       os << "}";
    472       if (file != nullptr) {
    473         os << ", " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx)
    474            << " // ";
    475       } else {
    476         os << ", ";
    477       }
    478       os << "method@" << method_idx << ", proto@" << proto_idx;
    479       break;
    480     }
    481     case k4rcc:
    482       switch (Opcode()) {
    483         case INVOKE_POLYMORPHIC_RANGE: {
    484           if (file != nullptr) {
    485             uint32_t method_idx = VRegB_4rcc();
    486             uint32_t proto_idx = VRegH_4rcc();
    487             os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc())
    488                << "}, " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx)
    489                << " // method@" << method_idx << ", proto@" << proto_idx;
    490             break;
    491           }
    492         }
    493         FALLTHROUGH_INTENDED;
    494         default: {
    495           uint32_t method_idx = VRegB_4rcc();
    496           uint32_t proto_idx = VRegH_4rcc();
    497           os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc())
    498              << "}, method@" << method_idx << ", proto@" << proto_idx;
    499         }
    500       }
    501       break;
    502     case k51l: os << StringPrintf("%s v%d, #%+" PRId64, opcode, VRegA_51l(), VRegB_51l()); break;
    503   }
    504   return os.str();
    505 }
    506 
    507 // Add some checks that ensure the flags make sense. We need a subclass to be in the context of
    508 // Instruction. Otherwise the flags from the instruction list don't work.
    509 struct InstructionStaticAsserts : private Instruction {
    510   #define IMPLIES(a, b) (!(a) || (b))
    511 
    512   #define VAR_ARGS_CHECK(o, c, pname, f, i, a, e, v) \
    513     static_assert(IMPLIES((f) == k35c || (f) == k45cc, \
    514                           ((v) & (kVerifyVarArg | kVerifyVarArgNonZero)) != 0), \
    515                   "Missing var-arg verification");
    516   #include "dex_instruction_list.h"
    517     DEX_INSTRUCTION_LIST(VAR_ARGS_CHECK)
    518   #undef DEX_INSTRUCTION_LIST
    519   #undef VAR_ARGS_CHECK
    520 
    521   #define VAR_ARGS_RANGE_CHECK(o, c, pname, f, i, a, e, v) \
    522     static_assert(IMPLIES((f) == k3rc || (f) == k4rcc, \
    523                           ((v) & (kVerifyVarArgRange | kVerifyVarArgRangeNonZero)) != 0), \
    524                   "Missing var-arg verification");
    525   #include "dex_instruction_list.h"
    526     DEX_INSTRUCTION_LIST(VAR_ARGS_RANGE_CHECK)
    527   #undef DEX_INSTRUCTION_LIST
    528   #undef VAR_ARGS_RANGE_CHECK
    529 
    530   #define EXPERIMENTAL_CHECK(o, c, pname, f, i, a, e, v) \
    531     static_assert(kHaveExperimentalInstructions || (((a) & kExperimental) == 0), \
    532                   "Unexpected experimental instruction.");
    533     #include "dex_instruction_list.h"
    534   DEX_INSTRUCTION_LIST(EXPERIMENTAL_CHECK)
    535   #undef DEX_INSTRUCTION_LIST
    536   #undef EXPERIMENTAL_CHECK
    537 };
    538 
    539 std::ostream& operator<<(std::ostream& os, const Instruction::Code& code) {
    540   return os << Instruction::Name(code);
    541 }
    542 
    543 }  // namespace art
    544