blob: 908405b7caebea37c86463980ce038951ed79e3b [file] [log] [blame]
Nicolas Geoffray01b70e82016-11-17 10:58:36 +00001/*
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"
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070021#include "bytecode_utils.h"
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000022#include "dex_file-inl.h"
23#include "dex_instruction-inl.h"
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070024#include "quicken_info.h"
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000025
26namespace art {
27namespace optimizer {
28
29class DexDecompiler {
30 public:
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +000031 DexDecompiler(const DexFile::CodeItem& code_item,
32 const ArrayRef<const uint8_t>& quickened_info,
33 bool decompile_return_instruction)
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000034 : code_item_(code_item),
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070035 quicken_info_(quickened_info.data()),
36 quicken_info_number_of_indices_(QuickenInfoTable::NumberOfIndices(quickened_info.size())),
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +000037 decompile_return_instruction_(decompile_return_instruction) {}
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000038
39 bool Decompile();
40
41 private:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070042 void DecompileInstanceFieldAccess(Instruction* inst, Instruction::Code new_opcode) {
43 uint16_t index = NextIndex();
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000044 inst->SetOpcode(new_opcode);
45 inst->SetVRegC_22c(index);
46 }
47
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070048 void DecompileInvokeVirtual(Instruction* inst, Instruction::Code new_opcode, bool is_range) {
49 const uint16_t index = NextIndex();
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000050 inst->SetOpcode(new_opcode);
51 if (is_range) {
52 inst->SetVRegB_3rc(index);
53 } else {
54 inst->SetVRegB_35c(index);
55 }
56 }
57
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070058 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.
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000062 return;
63 }
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070064 const uint16_t type_index = NextIndex();
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000065 inst->SetOpcode(Instruction::CHECK_CAST);
66 inst->SetVRegA_21c(reference_index);
67 inst->SetVRegB_21c(type_index);
68 }
69
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070070 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;
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000075 }
76
77 const DexFile::CodeItem& code_item_;
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070078 const QuickenInfoTable quicken_info_;
79 const size_t quicken_info_number_of_indices_;
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +000080 const bool decompile_return_instruction_;
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000081
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070082 size_t quicken_index_ = 0u;
83
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000084 DISALLOW_COPY_AND_ASSIGN(DexDecompiler);
85};
86
87bool 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()) {
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000093 Instruction* inst = const_cast<Instruction*>(&it.CurrentInstruction());
94
95 switch (inst->Opcode()) {
96 case Instruction::RETURN_VOID_NO_BARRIER:
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +000097 if (decompile_return_instruction_) {
98 inst->SetOpcode(Instruction::RETURN_VOID);
99 }
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000100 break;
101
102 case Instruction::NOP:
Mathieu Chartier36f549e2017-07-12 21:43:37 -0700103 if (quicken_info_number_of_indices_ > 0) {
Nicolas Geoffraya55e2682017-07-13 09:22:59 +0100104 // 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.
Mathieu Chartier36f549e2017-07-12 21:43:37 -0700107 DecompileNop(inst);
108 }
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000109 break;
110
111 case Instruction::IGET_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700112 DecompileInstanceFieldAccess(inst, Instruction::IGET);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000113 break;
114
115 case Instruction::IGET_WIDE_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700116 DecompileInstanceFieldAccess(inst, Instruction::IGET_WIDE);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000117 break;
118
119 case Instruction::IGET_OBJECT_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700120 DecompileInstanceFieldAccess(inst, Instruction::IGET_OBJECT);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000121 break;
122
123 case Instruction::IGET_BOOLEAN_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700124 DecompileInstanceFieldAccess(inst, Instruction::IGET_BOOLEAN);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000125 break;
126
127 case Instruction::IGET_BYTE_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700128 DecompileInstanceFieldAccess(inst, Instruction::IGET_BYTE);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000129 break;
130
131 case Instruction::IGET_CHAR_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700132 DecompileInstanceFieldAccess(inst, Instruction::IGET_CHAR);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000133 break;
134
135 case Instruction::IGET_SHORT_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700136 DecompileInstanceFieldAccess(inst, Instruction::IGET_SHORT);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000137 break;
138
139 case Instruction::IPUT_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700140 DecompileInstanceFieldAccess(inst, Instruction::IPUT);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000141 break;
142
143 case Instruction::IPUT_BOOLEAN_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700144 DecompileInstanceFieldAccess(inst, Instruction::IPUT_BOOLEAN);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000145 break;
146
147 case Instruction::IPUT_BYTE_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700148 DecompileInstanceFieldAccess(inst, Instruction::IPUT_BYTE);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000149 break;
150
151 case Instruction::IPUT_CHAR_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700152 DecompileInstanceFieldAccess(inst, Instruction::IPUT_CHAR);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000153 break;
154
155 case Instruction::IPUT_SHORT_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700156 DecompileInstanceFieldAccess(inst, Instruction::IPUT_SHORT);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000157 break;
158
159 case Instruction::IPUT_WIDE_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700160 DecompileInstanceFieldAccess(inst, Instruction::IPUT_WIDE);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000161 break;
162
163 case Instruction::IPUT_OBJECT_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700164 DecompileInstanceFieldAccess(inst, Instruction::IPUT_OBJECT);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000165 break;
166
167 case Instruction::INVOKE_VIRTUAL_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700168 DecompileInvokeVirtual(inst, Instruction::INVOKE_VIRTUAL, false);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000169 break;
170
171 case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700172 DecompileInvokeVirtual(inst, Instruction::INVOKE_VIRTUAL_RANGE, true);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000173 break;
174
175 default:
176 break;
177 }
178 }
179
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700180 if (quicken_index_ != quicken_info_number_of_indices_) {
181 if (quicken_index_ == 0) {
Nicolas Geoffray095d6a62017-04-27 16:08:50 +0100182 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."
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700186 << " Actual: " << std::hex << quicken_index_
187 << " Expected: " << quicken_info_number_of_indices_;
Nicolas Geoffray095d6a62017-04-27 16:08:50 +0100188 return false;
189 }
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000190 }
191
192 return true;
193}
194
195bool ArtDecompileDEX(const DexFile::CodeItem& code_item,
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +0000196 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);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000202 return decompiler.Decompile();
203}
204
205} // namespace optimizer
206} // namespace art