blob: 05548761e03d500d68cb9c44dcbb9afa69136f8b [file] [log] [blame]
Nicolas Geoffray818f2102014-02-18 16:43:35 +00001/*
2 *
3 * Copyright (C) 2014 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000018#include "dex_file.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000019#include "dex_file-inl.h"
Nicolas Geoffray818f2102014-02-18 16:43:35 +000020#include "dex_instruction.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000021#include "dex_instruction-inl.h"
Nicolas Geoffray818f2102014-02-18 16:43:35 +000022#include "builder.h"
23#include "nodes.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000024#include "primitive.h"
Nicolas Geoffray818f2102014-02-18 16:43:35 +000025
26namespace art {
27
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000028void HGraphBuilder::InitializeLocals(int count) {
29 locals_.SetSize(count);
30 for (int i = 0; i < count; i++) {
31 HLocal* local = new (arena_) HLocal(i);
32 entry_block_->AddInstruction(local);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000033 locals_.Put(i, local);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000034 }
35}
36
37static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000038 if (code_item.tries_size_ > 0) {
39 return false;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000040 } else if (code_item.ins_size_ > 0) {
41 return false;
42 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000043 return true;
44}
45
46HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000047 if (!CanHandleCodeItem(code_item)) {
48 return nullptr;
49 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000050
51 const uint16_t* code_ptr = code_item.insns_;
52 const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
53
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000054 // Setup the graph with the entry block and exit block.
Nicolas Geoffray818f2102014-02-18 16:43:35 +000055 graph_ = new (arena_) HGraph(arena_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000056 entry_block_ = new (arena_) HBasicBlock(graph_);
57 graph_->AddBlock(entry_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000058 exit_block_ = new (arena_) HBasicBlock(graph_);
Nicolas Geoffray787c3072014-03-17 10:20:19 +000059 graph_->SetEntryBlock(entry_block_);
60 graph_->SetExitBlock(exit_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000061
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000062 InitializeLocals(code_item.registers_size_);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +010063 graph_->UpdateMaximumNumberOfOutVRegs(code_item.outs_size_);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000064
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000065 // To avoid splitting blocks, we compute ahead of time the instructions that
66 // start a new block, and create these blocks.
67 ComputeBranchTargets(code_ptr, code_end);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000068
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000069 size_t dex_offset = 0;
Nicolas Geoffray818f2102014-02-18 16:43:35 +000070 while (code_ptr < code_end) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000071 // Update the current block if dex_offset starts a new block.
72 MaybeUpdateCurrentBlock(dex_offset);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000073 const Instruction& instruction = *Instruction::At(code_ptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000074 if (!AnalyzeDexInstruction(instruction, dex_offset)) return nullptr;
75 dex_offset += instruction.SizeInCodeUnits();
Nicolas Geoffray818f2102014-02-18 16:43:35 +000076 code_ptr += instruction.SizeInCodeUnits();
77 }
78
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000079 // Add the exit block at the end to give it the highest id.
Nicolas Geoffray818f2102014-02-18 16:43:35 +000080 graph_->AddBlock(exit_block_);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000081 exit_block_->AddInstruction(new (arena_) HExit());
82 entry_block_->AddInstruction(new (arena_) HGoto());
Nicolas Geoffray818f2102014-02-18 16:43:35 +000083 return graph_;
84}
85
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000086void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
87 HBasicBlock* block = FindBlockStartingAt(index);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000088 if (block == nullptr) {
89 return;
90 }
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000091
92 if (current_block_ != nullptr) {
93 // Branching instructions clear current_block, so we know
94 // the last instruction of the current block is not a branching
95 // instruction. We add an unconditional goto to the found block.
96 current_block_->AddInstruction(new (arena_) HGoto());
97 current_block_->AddSuccessor(block);
98 }
99 graph_->AddBlock(block);
100 current_block_ = block;
101}
102
103void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end) {
104 // TODO: Support switch instructions.
105 branch_targets_.SetSize(code_end - code_ptr);
106
107 // Create the first block for the dex instructions, single successor of the entry block.
108 HBasicBlock* block = new (arena_) HBasicBlock(graph_);
109 branch_targets_.Put(0, block);
110 entry_block_->AddSuccessor(block);
111
112 // Iterate over all instructions and find branching instructions. Create blocks for
113 // the locations these instructions branch to.
114 size_t dex_offset = 0;
115 while (code_ptr < code_end) {
116 const Instruction& instruction = *Instruction::At(code_ptr);
117 if (instruction.IsBranch()) {
118 int32_t target = instruction.GetTargetOffset() + dex_offset;
119 // Create a block for the target instruction.
120 if (FindBlockStartingAt(target) == nullptr) {
121 block = new (arena_) HBasicBlock(graph_);
122 branch_targets_.Put(target, block);
123 }
124 dex_offset += instruction.SizeInCodeUnits();
125 code_ptr += instruction.SizeInCodeUnits();
126 if ((code_ptr < code_end) && (FindBlockStartingAt(dex_offset) == nullptr)) {
127 block = new (arena_) HBasicBlock(graph_);
128 branch_targets_.Put(dex_offset, block);
129 }
130 } else {
131 code_ptr += instruction.SizeInCodeUnits();
132 dex_offset += instruction.SizeInCodeUnits();
133 }
134 }
135}
136
137HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
138 DCHECK_GE(index, 0);
139 return branch_targets_.Get(index);
140}
141
142bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000143 if (current_block_ == nullptr) {
144 return true; // Dead code
145 }
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000146
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000147 switch (instruction.Opcode()) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000148 case Instruction::CONST_4: {
149 int32_t register_index = instruction.VRegA();
150 HIntConstant* constant = GetConstant(instruction.VRegB_11n());
151 UpdateLocal(register_index, constant);
152 break;
153 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000154
155 case Instruction::RETURN_VOID: {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000156 current_block_->AddInstruction(new (arena_) HReturnVoid());
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000157 current_block_->AddSuccessor(exit_block_);
158 current_block_ = nullptr;
159 break;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000160 }
161
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000162 case Instruction::IF_EQ: {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000163 HInstruction* first = LoadLocal(instruction.VRegA());
164 HInstruction* second = LoadLocal(instruction.VRegB());
165 current_block_->AddInstruction(new (arena_) HEqual(first, second));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000166 current_block_->AddInstruction(new (arena_) HIf(current_block_->GetLastInstruction()));
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000167 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
168 DCHECK(target != nullptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000169 current_block_->AddSuccessor(target);
170 target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
171 DCHECK(target != nullptr);
172 current_block_->AddSuccessor(target);
173 current_block_ = nullptr;
174 break;
175 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000176
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000177 case Instruction::GOTO:
178 case Instruction::GOTO_16:
179 case Instruction::GOTO_32: {
180 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
181 DCHECK(target != nullptr);
182 current_block_->AddInstruction(new (arena_) HGoto());
183 current_block_->AddSuccessor(target);
184 current_block_ = nullptr;
185 break;
186 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000187
188 case Instruction::RETURN: {
189 HInstruction* value = LoadLocal(instruction.VRegA());
190 current_block_->AddInstruction(new (arena_) HReturn(value));
191 current_block_->AddSuccessor(exit_block_);
192 current_block_ = nullptr;
193 break;
194 }
195
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000196 case Instruction::INVOKE_STATIC: {
197 uint32_t method_idx = instruction.VRegB_35c();
198 const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
199 uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
200 const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
201 const size_t number_of_arguments = instruction.VRegA_35c();
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100202
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000203 if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) {
204 return false;
205 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100206
207 HInvokeStatic* invoke = new (arena_) HInvokeStatic(
208 arena_, number_of_arguments, dex_offset, method_idx);
209
210 uint32_t args[5];
211 instruction.GetArgs(args);
212
213 for (size_t i = 0; i < number_of_arguments; i++) {
214 HInstruction* arg = LoadLocal(args[i]);
215 HInstruction* push = new (arena_) HPushArgument(arg, i);
216 current_block_->AddInstruction(push);
217 invoke->SetArgumentAt(i, push);
218 }
219
220 current_block_->AddInstruction(invoke);
221 break;
222 }
223
224 case Instruction::INVOKE_STATIC_RANGE: {
225 uint32_t method_idx = instruction.VRegB_3rc();
226 const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
227 uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
228 const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
229 const size_t number_of_arguments = instruction.VRegA_3rc();
230
231 if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) {
232 return false;
233 }
234
235 HInvokeStatic* invoke = new (arena_) HInvokeStatic(
236 arena_, number_of_arguments, dex_offset, method_idx);
237 int32_t register_index = instruction.VRegC();
238 for (size_t i = 0; i < number_of_arguments; i++) {
239 HInstruction* arg = LoadLocal(register_index + i);
240 HInstruction* push = new (arena_) HPushArgument(arg, i);
241 current_block_->AddInstruction(push);
242 invoke->SetArgumentAt(i, push);
243 }
244 current_block_->AddInstruction(invoke);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000245 break;
246 }
247
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000248 case Instruction::ADD_INT: {
249 HInstruction* first = LoadLocal(instruction.VRegB());
250 HInstruction* second = LoadLocal(instruction.VRegC());
251 current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second));
252 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
253 break;
254 }
255
256 case Instruction::ADD_INT_2ADDR: {
257 HInstruction* first = LoadLocal(instruction.VRegA());
258 HInstruction* second = LoadLocal(instruction.VRegB());
259 current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second));
260 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
261 break;
262 }
263
264 case Instruction::ADD_INT_LIT16: {
265 HInstruction* first = LoadLocal(instruction.VRegB());
266 HInstruction* second = GetConstant(instruction.VRegC_22s());
267 current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second));
268 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
269 break;
270 }
271
272 case Instruction::ADD_INT_LIT8: {
273 HInstruction* first = LoadLocal(instruction.VRegB());
274 HInstruction* second = GetConstant(instruction.VRegC_22b());
275 current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second));
276 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
277 break;
278 }
279
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000280 case Instruction::NOP:
281 break;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000282
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000283 default:
284 return false;
285 }
286 return true;
287}
288
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000289HIntConstant* HGraphBuilder::GetConstant0() {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000290 if (constant0_ != nullptr) {
291 return constant0_;
292 }
293 constant0_ = new(arena_) HIntConstant(0);
294 entry_block_->AddInstruction(constant0_);
295 return constant0_;
296}
297
298HIntConstant* HGraphBuilder::GetConstant1() {
299 if (constant1_ != nullptr) {
300 return constant1_;
301 }
302 constant1_ = new(arena_) HIntConstant(1);
303 entry_block_->AddInstruction(constant1_);
304 return constant1_;
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000305}
306
307HIntConstant* HGraphBuilder::GetConstant(int constant) {
308 switch (constant) {
309 case 0: return GetConstant0();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000310 case 1: return GetConstant1();
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000311 default: {
312 HIntConstant* instruction = new (arena_) HIntConstant(constant);
313 entry_block_->AddInstruction(instruction);
314 return instruction;
315 }
316 }
317}
318
319HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
320 return locals_.Get(register_index);
321}
322
323void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) const {
324 HLocal* local = GetLocalAt(register_index);
325 current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction));
326}
327
328HInstruction* HGraphBuilder::LoadLocal(int register_index) const {
329 HLocal* local = GetLocalAt(register_index);
330 current_block_->AddInstruction(new (arena_) HLoadLocal(local));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000331 return current_block_->GetLastInstruction();
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000332}
333
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000334} // namespace art