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