blob: 64ecdb5c246a75f6deb4b13b9ed31aab4914cee9 [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;
40 } else if (code_item.outs_size_ > 0) {
41 return false;
42 } else if (code_item.ins_size_ > 0) {
43 return false;
44 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000045 return true;
46}
47
48HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000049 if (!CanHandleCodeItem(code_item)) {
50 return nullptr;
51 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000052
53 const uint16_t* code_ptr = code_item.insns_;
54 const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
55
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000056 // Setup the graph with the entry block and exit block.
Nicolas Geoffray818f2102014-02-18 16:43:35 +000057 graph_ = new (arena_) HGraph(arena_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000058 entry_block_ = new (arena_) HBasicBlock(graph_);
59 graph_->AddBlock(entry_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000060 exit_block_ = new (arena_) HBasicBlock(graph_);
Nicolas Geoffray787c3072014-03-17 10:20:19 +000061 graph_->SetEntryBlock(entry_block_);
62 graph_->SetExitBlock(exit_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000063
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000064 InitializeLocals(code_item.registers_size_);
65
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000066 // To avoid splitting blocks, we compute ahead of time the instructions that
67 // start a new block, and create these blocks.
68 ComputeBranchTargets(code_ptr, code_end);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000069
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000070 size_t dex_offset = 0;
Nicolas Geoffray818f2102014-02-18 16:43:35 +000071 while (code_ptr < code_end) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000072 // Update the current block if dex_offset starts a new block.
73 MaybeUpdateCurrentBlock(dex_offset);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000074 const Instruction& instruction = *Instruction::At(code_ptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000075 if (!AnalyzeDexInstruction(instruction, dex_offset)) return nullptr;
76 dex_offset += instruction.SizeInCodeUnits();
Nicolas Geoffray818f2102014-02-18 16:43:35 +000077 code_ptr += instruction.SizeInCodeUnits();
78 }
79
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000080 // Add the exit block at the end to give it the highest id.
Nicolas Geoffray818f2102014-02-18 16:43:35 +000081 graph_->AddBlock(exit_block_);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000082 exit_block_->AddInstruction(new (arena_) HExit());
83 entry_block_->AddInstruction(new (arena_) HGoto());
Nicolas Geoffray818f2102014-02-18 16:43:35 +000084 return graph_;
85}
86
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000087void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
88 HBasicBlock* block = FindBlockStartingAt(index);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000089 if (block == nullptr) {
90 return;
91 }
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000092
93 if (current_block_ != nullptr) {
94 // Branching instructions clear current_block, so we know
95 // the last instruction of the current block is not a branching
96 // instruction. We add an unconditional goto to the found block.
97 current_block_->AddInstruction(new (arena_) HGoto());
98 current_block_->AddSuccessor(block);
99 }
100 graph_->AddBlock(block);
101 current_block_ = block;
102}
103
104void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end) {
105 // TODO: Support switch instructions.
106 branch_targets_.SetSize(code_end - code_ptr);
107
108 // Create the first block for the dex instructions, single successor of the entry block.
109 HBasicBlock* block = new (arena_) HBasicBlock(graph_);
110 branch_targets_.Put(0, block);
111 entry_block_->AddSuccessor(block);
112
113 // Iterate over all instructions and find branching instructions. Create blocks for
114 // the locations these instructions branch to.
115 size_t dex_offset = 0;
116 while (code_ptr < code_end) {
117 const Instruction& instruction = *Instruction::At(code_ptr);
118 if (instruction.IsBranch()) {
119 int32_t target = instruction.GetTargetOffset() + dex_offset;
120 // Create a block for the target instruction.
121 if (FindBlockStartingAt(target) == nullptr) {
122 block = new (arena_) HBasicBlock(graph_);
123 branch_targets_.Put(target, block);
124 }
125 dex_offset += instruction.SizeInCodeUnits();
126 code_ptr += instruction.SizeInCodeUnits();
127 if ((code_ptr < code_end) && (FindBlockStartingAt(dex_offset) == nullptr)) {
128 block = new (arena_) HBasicBlock(graph_);
129 branch_targets_.Put(dex_offset, block);
130 }
131 } else {
132 code_ptr += instruction.SizeInCodeUnits();
133 dex_offset += instruction.SizeInCodeUnits();
134 }
135 }
136}
137
138HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
139 DCHECK_GE(index, 0);
140 return branch_targets_.Get(index);
141}
142
143bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000144 if (current_block_ == nullptr) {
145 return true; // Dead code
146 }
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000147
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000148 switch (instruction.Opcode()) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000149 case Instruction::CONST_4: {
150 int32_t register_index = instruction.VRegA();
151 HIntConstant* constant = GetConstant(instruction.VRegB_11n());
152 UpdateLocal(register_index, constant);
153 break;
154 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000155
156 case Instruction::RETURN_VOID: {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000157 current_block_->AddInstruction(new (arena_) HReturnVoid());
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000158 current_block_->AddSuccessor(exit_block_);
159 current_block_ = nullptr;
160 break;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000161 }
162
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000163 case Instruction::IF_EQ: {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000164 HInstruction* first = LoadLocal(instruction.VRegA());
165 HInstruction* second = LoadLocal(instruction.VRegB());
166 current_block_->AddInstruction(new (arena_) HEqual(first, second));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000167 current_block_->AddInstruction(new (arena_) HIf(current_block_->GetLastInstruction()));
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000168 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
169 DCHECK(target != nullptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000170 current_block_->AddSuccessor(target);
171 target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
172 DCHECK(target != nullptr);
173 current_block_->AddSuccessor(target);
174 current_block_ = nullptr;
175 break;
176 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000177
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000178 case Instruction::GOTO:
179 case Instruction::GOTO_16:
180 case Instruction::GOTO_32: {
181 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
182 DCHECK(target != nullptr);
183 current_block_->AddInstruction(new (arena_) HGoto());
184 current_block_->AddSuccessor(target);
185 current_block_ = nullptr;
186 break;
187 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000188
189 case Instruction::RETURN: {
190 HInstruction* value = LoadLocal(instruction.VRegA());
191 current_block_->AddInstruction(new (arena_) HReturn(value));
192 current_block_->AddSuccessor(exit_block_);
193 current_block_ = nullptr;
194 break;
195 }
196
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000197 case Instruction::INVOKE_STATIC: {
198 uint32_t method_idx = instruction.VRegB_35c();
199 const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
200 uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
201 const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
202 const size_t number_of_arguments = instruction.VRegA_35c();
203 if (number_of_arguments != 0) {
204 return false;
205 }
206 if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) {
207 return false;
208 }
209 current_block_->AddInstruction(new (arena_) HInvokeStatic(
210 arena_, number_of_arguments, dex_offset, method_idx));
211 break;
212 }
213
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000214 case Instruction::ADD_INT: {
215 HInstruction* first = LoadLocal(instruction.VRegB());
216 HInstruction* second = LoadLocal(instruction.VRegC());
217 current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second));
218 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
219 break;
220 }
221
222 case Instruction::ADD_INT_2ADDR: {
223 HInstruction* first = LoadLocal(instruction.VRegA());
224 HInstruction* second = LoadLocal(instruction.VRegB());
225 current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second));
226 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
227 break;
228 }
229
230 case Instruction::ADD_INT_LIT16: {
231 HInstruction* first = LoadLocal(instruction.VRegB());
232 HInstruction* second = GetConstant(instruction.VRegC_22s());
233 current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second));
234 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
235 break;
236 }
237
238 case Instruction::ADD_INT_LIT8: {
239 HInstruction* first = LoadLocal(instruction.VRegB());
240 HInstruction* second = GetConstant(instruction.VRegC_22b());
241 current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second));
242 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
243 break;
244 }
245
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000246 case Instruction::NOP:
247 break;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000248
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000249 default:
250 return false;
251 }
252 return true;
253}
254
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000255HIntConstant* HGraphBuilder::GetConstant0() {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000256 if (constant0_ != nullptr) {
257 return constant0_;
258 }
259 constant0_ = new(arena_) HIntConstant(0);
260 entry_block_->AddInstruction(constant0_);
261 return constant0_;
262}
263
264HIntConstant* HGraphBuilder::GetConstant1() {
265 if (constant1_ != nullptr) {
266 return constant1_;
267 }
268 constant1_ = new(arena_) HIntConstant(1);
269 entry_block_->AddInstruction(constant1_);
270 return constant1_;
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000271}
272
273HIntConstant* HGraphBuilder::GetConstant(int constant) {
274 switch (constant) {
275 case 0: return GetConstant0();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000276 case 1: return GetConstant1();
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000277 default: {
278 HIntConstant* instruction = new (arena_) HIntConstant(constant);
279 entry_block_->AddInstruction(instruction);
280 return instruction;
281 }
282 }
283}
284
285HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
286 return locals_.Get(register_index);
287}
288
289void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) const {
290 HLocal* local = GetLocalAt(register_index);
291 current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction));
292}
293
294HInstruction* HGraphBuilder::LoadLocal(int register_index) const {
295 HLocal* local = GetLocalAt(register_index);
296 current_block_->AddInstruction(new (arena_) HLoadLocal(local));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000297 return current_block_->GetLastInstruction();
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000298}
299
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000300} // namespace art