blob: c15c9ec448c2f1fdf59bb6882792fe4401b6a7bd [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"
21#include "dex_file-inl.h"
22#include "dex_instruction-inl.h"
Calin Juravlee0ac1152017-02-13 19:03:47 -080023#include "bytecode_utils.h"
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000024
25namespace art {
26namespace optimizer {
27
28class DexDecompiler {
29 public:
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +000030 DexDecompiler(const DexFile::CodeItem& code_item,
31 const ArrayRef<const uint8_t>& quickened_info,
32 bool decompile_return_instruction)
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000033 : code_item_(code_item),
34 quickened_info_ptr_(quickened_info.data()),
Nicolas Geoffray095d6a62017-04-27 16:08:50 +010035 quickened_info_start_(quickened_info.data()),
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +000036 quickened_info_end_(quickened_info.data() + quickened_info.size()),
37 decompile_return_instruction_(decompile_return_instruction) {}
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000038
39 bool Decompile();
40
41 private:
42 void DecompileInstanceFieldAccess(Instruction* inst,
43 uint32_t dex_pc,
44 Instruction::Code new_opcode) {
45 uint16_t index = GetIndexAt(dex_pc);
46 inst->SetOpcode(new_opcode);
47 inst->SetVRegC_22c(index);
48 }
49
50 void DecompileInvokeVirtual(Instruction* inst,
51 uint32_t dex_pc,
52 Instruction::Code new_opcode,
53 bool is_range) {
54 uint16_t index = GetIndexAt(dex_pc);
55 inst->SetOpcode(new_opcode);
56 if (is_range) {
57 inst->SetVRegB_3rc(index);
58 } else {
59 inst->SetVRegB_35c(index);
60 }
61 }
62
63 void DecompileNop(Instruction* inst, uint32_t dex_pc) {
64 if (quickened_info_ptr_ == quickened_info_end_) {
65 return;
66 }
67 const uint8_t* temporary_pointer = quickened_info_ptr_;
68 uint32_t quickened_pc = DecodeUnsignedLeb128(&temporary_pointer);
69 if (quickened_pc != dex_pc) {
70 return;
71 }
72 uint16_t reference_index = GetIndexAt(dex_pc);
73 uint16_t type_index = GetIndexAt(dex_pc);
74 inst->SetOpcode(Instruction::CHECK_CAST);
75 inst->SetVRegA_21c(reference_index);
76 inst->SetVRegB_21c(type_index);
77 }
78
79 uint16_t GetIndexAt(uint32_t dex_pc) {
80 // Note that as a side effect, DecodeUnsignedLeb128 update the given pointer
81 // to the new position in the buffer.
82 DCHECK_LT(quickened_info_ptr_, quickened_info_end_);
83 uint32_t quickened_pc = DecodeUnsignedLeb128(&quickened_info_ptr_);
84 DCHECK_LT(quickened_info_ptr_, quickened_info_end_);
85 uint16_t index = DecodeUnsignedLeb128(&quickened_info_ptr_);
86 DCHECK_LE(quickened_info_ptr_, quickened_info_end_);
87 DCHECK_EQ(quickened_pc, dex_pc);
88 return index;
89 }
90
91 const DexFile::CodeItem& code_item_;
92 const uint8_t* quickened_info_ptr_;
Nicolas Geoffray095d6a62017-04-27 16:08:50 +010093 const uint8_t* const quickened_info_start_;
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000094 const uint8_t* const quickened_info_end_;
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +000095 const bool decompile_return_instruction_;
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000096
97 DISALLOW_COPY_AND_ASSIGN(DexDecompiler);
98};
99
100bool DexDecompiler::Decompile() {
101 // We need to iterate over the code item, and not over the quickening data,
102 // because the RETURN_VOID quickening is not encoded in the quickening data. Because
103 // unquickening is a rare need and not performance sensitive, it is not worth the
104 // added storage to also add the RETURN_VOID quickening in the quickened data.
105 for (CodeItemIterator it(code_item_); !it.Done(); it.Advance()) {
106 uint32_t dex_pc = it.CurrentDexPc();
107 Instruction* inst = const_cast<Instruction*>(&it.CurrentInstruction());
108
109 switch (inst->Opcode()) {
110 case Instruction::RETURN_VOID_NO_BARRIER:
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +0000111 if (decompile_return_instruction_) {
112 inst->SetOpcode(Instruction::RETURN_VOID);
113 }
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000114 break;
115
116 case Instruction::NOP:
117 DecompileNop(inst, dex_pc);
118 break;
119
120 case Instruction::IGET_QUICK:
121 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET);
122 break;
123
124 case Instruction::IGET_WIDE_QUICK:
125 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_WIDE);
126 break;
127
128 case Instruction::IGET_OBJECT_QUICK:
129 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_OBJECT);
130 break;
131
132 case Instruction::IGET_BOOLEAN_QUICK:
133 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BOOLEAN);
134 break;
135
136 case Instruction::IGET_BYTE_QUICK:
137 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BYTE);
138 break;
139
140 case Instruction::IGET_CHAR_QUICK:
141 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_CHAR);
142 break;
143
144 case Instruction::IGET_SHORT_QUICK:
145 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_SHORT);
146 break;
147
148 case Instruction::IPUT_QUICK:
149 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT);
150 break;
151
152 case Instruction::IPUT_BOOLEAN_QUICK:
153 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BOOLEAN);
154 break;
155
156 case Instruction::IPUT_BYTE_QUICK:
157 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BYTE);
158 break;
159
160 case Instruction::IPUT_CHAR_QUICK:
161 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_CHAR);
162 break;
163
164 case Instruction::IPUT_SHORT_QUICK:
165 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_SHORT);
166 break;
167
168 case Instruction::IPUT_WIDE_QUICK:
169 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_WIDE);
170 break;
171
172 case Instruction::IPUT_OBJECT_QUICK:
173 DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_OBJECT);
174 break;
175
176 case Instruction::INVOKE_VIRTUAL_QUICK:
177 DecompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL, false);
178 break;
179
180 case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
181 DecompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_RANGE, true);
182 break;
183
184 default:
185 break;
186 }
187 }
188
189 if (quickened_info_ptr_ != quickened_info_end_) {
Nicolas Geoffray095d6a62017-04-27 16:08:50 +0100190 if (quickened_info_start_ == quickened_info_ptr_) {
191 LOG(WARNING) << "Failed to use any value in quickening info,"
192 << " potentially due to duplicate methods.";
193 } else {
194 LOG(FATAL) << "Failed to use all values in quickening info."
195 << " Actual: " << std::hex << reinterpret_cast<uintptr_t>(quickened_info_ptr_)
196 << " Expected: " << reinterpret_cast<uintptr_t>(quickened_info_end_);
197 return false;
198 }
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000199 }
200
201 return true;
202}
203
204bool ArtDecompileDEX(const DexFile::CodeItem& code_item,
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +0000205 const ArrayRef<const uint8_t>& quickened_info,
206 bool decompile_return_instruction) {
207 if (quickened_info.size() == 0 && !decompile_return_instruction) {
208 return true;
209 }
210 DexDecompiler decompiler(code_item, quickened_info, decompile_return_instruction);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000211 return decompiler.Decompile();
212}
213
214} // namespace optimizer
215} // namespace art