Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2016 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_to_dex_decompiler.h"
     18 
     19 #include <android-base/logging.h>
     20 
     21 #include "base/macros.h"
     22 #include "base/mutex.h"
     23 #include "dex/bytecode_utils.h"
     24 #include "dex/code_item_accessors-inl.h"
     25 #include "dex/dex_file-inl.h"
     26 #include "dex/dex_instruction-inl.h"
     27 #include "quicken_info.h"
     28 
     29 namespace art {
     30 namespace optimizer {
     31 
     32 class DexDecompiler {
     33  public:
     34   DexDecompiler(const DexFile& dex_file,
     35                 const DexFile::CodeItem& code_item,
     36                 const ArrayRef<const uint8_t>& quickened_info,
     37                 bool decompile_return_instruction)
     38     : code_item_accessor_(dex_file, &code_item),
     39       quicken_info_(quickened_info),
     40       decompile_return_instruction_(decompile_return_instruction) {}
     41 
     42   bool Decompile();
     43 
     44  private:
     45   void DecompileInstanceFieldAccess(Instruction* inst, Instruction::Code new_opcode) {
     46     uint16_t index = NextIndex();
     47     inst->SetOpcode(new_opcode);
     48     inst->SetVRegC_22c(index);
     49   }
     50 
     51   void DecompileInvokeVirtual(Instruction* inst, Instruction::Code new_opcode, bool is_range) {
     52     const uint16_t index = NextIndex();
     53     inst->SetOpcode(new_opcode);
     54     if (is_range) {
     55       inst->SetVRegB_3rc(index);
     56     } else {
     57       inst->SetVRegB_35c(index);
     58     }
     59   }
     60 
     61   void DecompileNop(Instruction* inst) {
     62     const uint16_t reference_index = NextIndex();
     63     if (reference_index == DexFile::kDexNoIndex16) {
     64       // This means it was a normal nop and not a check-cast.
     65       return;
     66     }
     67     const uint16_t type_index = NextIndex();
     68     inst->SetOpcode(Instruction::CHECK_CAST);
     69     inst->SetVRegA_21c(reference_index);
     70     inst->SetVRegB_21c(type_index);
     71   }
     72 
     73   uint16_t NextIndex() {
     74     DCHECK_LT(quicken_index_, quicken_info_.NumIndices());
     75     const uint16_t ret = quicken_info_.GetData(quicken_index_);
     76     quicken_index_++;
     77     return ret;
     78   }
     79 
     80   const CodeItemInstructionAccessor code_item_accessor_;
     81   const QuickenInfoTable quicken_info_;
     82   const bool decompile_return_instruction_;
     83 
     84   size_t quicken_index_ = 0u;
     85 
     86   DISALLOW_COPY_AND_ASSIGN(DexDecompiler);
     87 };
     88 
     89 bool DexDecompiler::Decompile() {
     90   // We need to iterate over the code item, and not over the quickening data,
     91   // because the RETURN_VOID quickening is not encoded in the quickening data. Because
     92   // unquickening is a rare need and not performance sensitive, it is not worth the
     93   // added storage to also add the RETURN_VOID quickening in the quickened data.
     94   for (const DexInstructionPcPair& pair : code_item_accessor_) {
     95     Instruction* inst = const_cast<Instruction*>(&pair.Inst());
     96 
     97     switch (inst->Opcode()) {
     98       case Instruction::RETURN_VOID_NO_BARRIER:
     99         if (decompile_return_instruction_) {
    100           inst->SetOpcode(Instruction::RETURN_VOID);
    101         }
    102         break;
    103 
    104       case Instruction::NOP:
    105         if (quicken_info_.NumIndices() > 0) {
    106           // Only try to decompile NOP if there are more than 0 indices. Not having
    107           // any index happens when we unquicken a code item that only has
    108           // RETURN_VOID_NO_BARRIER as quickened instruction.
    109           DecompileNop(inst);
    110         }
    111         break;
    112 
    113       case Instruction::IGET_QUICK:
    114         DecompileInstanceFieldAccess(inst, Instruction::IGET);
    115         break;
    116 
    117       case Instruction::IGET_WIDE_QUICK:
    118         DecompileInstanceFieldAccess(inst, Instruction::IGET_WIDE);
    119         break;
    120 
    121       case Instruction::IGET_OBJECT_QUICK:
    122         DecompileInstanceFieldAccess(inst, Instruction::IGET_OBJECT);
    123         break;
    124 
    125       case Instruction::IGET_BOOLEAN_QUICK:
    126         DecompileInstanceFieldAccess(inst, Instruction::IGET_BOOLEAN);
    127         break;
    128 
    129       case Instruction::IGET_BYTE_QUICK:
    130         DecompileInstanceFieldAccess(inst, Instruction::IGET_BYTE);
    131         break;
    132 
    133       case Instruction::IGET_CHAR_QUICK:
    134         DecompileInstanceFieldAccess(inst, Instruction::IGET_CHAR);
    135         break;
    136 
    137       case Instruction::IGET_SHORT_QUICK:
    138         DecompileInstanceFieldAccess(inst, Instruction::IGET_SHORT);
    139         break;
    140 
    141       case Instruction::IPUT_QUICK:
    142         DecompileInstanceFieldAccess(inst, Instruction::IPUT);
    143         break;
    144 
    145       case Instruction::IPUT_BOOLEAN_QUICK:
    146         DecompileInstanceFieldAccess(inst, Instruction::IPUT_BOOLEAN);
    147         break;
    148 
    149       case Instruction::IPUT_BYTE_QUICK:
    150         DecompileInstanceFieldAccess(inst, Instruction::IPUT_BYTE);
    151         break;
    152 
    153       case Instruction::IPUT_CHAR_QUICK:
    154         DecompileInstanceFieldAccess(inst, Instruction::IPUT_CHAR);
    155         break;
    156 
    157       case Instruction::IPUT_SHORT_QUICK:
    158         DecompileInstanceFieldAccess(inst, Instruction::IPUT_SHORT);
    159         break;
    160 
    161       case Instruction::IPUT_WIDE_QUICK:
    162         DecompileInstanceFieldAccess(inst, Instruction::IPUT_WIDE);
    163         break;
    164 
    165       case Instruction::IPUT_OBJECT_QUICK:
    166         DecompileInstanceFieldAccess(inst, Instruction::IPUT_OBJECT);
    167         break;
    168 
    169       case Instruction::INVOKE_VIRTUAL_QUICK:
    170         DecompileInvokeVirtual(inst, Instruction::INVOKE_VIRTUAL, false);
    171         break;
    172 
    173       case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
    174         DecompileInvokeVirtual(inst, Instruction::INVOKE_VIRTUAL_RANGE, true);
    175         break;
    176 
    177       default:
    178         break;
    179     }
    180   }
    181 
    182   if (quicken_index_ != quicken_info_.NumIndices()) {
    183     if (quicken_index_ == 0) {
    184       LOG(WARNING) << "Failed to use any value in quickening info,"
    185                    << " potentially due to duplicate methods.";
    186     } else {
    187       LOG(FATAL) << "Failed to use all values in quickening info."
    188                  << " Actual: " << std::hex << quicken_index_
    189                  << " Expected: " << quicken_info_.NumIndices();
    190       return false;
    191     }
    192   }
    193 
    194   return true;
    195 }
    196 
    197 bool ArtDecompileDEX(const DexFile& dex_file,
    198                      const DexFile::CodeItem& code_item,
    199                      const ArrayRef<const uint8_t>& quickened_info,
    200                      bool decompile_return_instruction) {
    201   if (quickened_info.size() == 0 && !decompile_return_instruction) {
    202     return true;
    203   }
    204   DexDecompiler decompiler(dex_file, code_item, quickened_info, decompile_return_instruction);
    205   return decompiler.Decompile();
    206 }
    207 
    208 }  // namespace optimizer
    209 }  // namespace art
    210