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