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