blob: d90405a1a483b17378c064fc3dd5222710113dd0 [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 Geoffray2e7038a2014-04-03 18:49:58 +0100196 case Instruction::INVOKE_STATIC:
197 case Instruction::INVOKE_DIRECT: {
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000198 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();
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100203
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000204 if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) {
205 return false;
206 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100207
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100208 // Treat invoke-direct like static calls for now.
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100209 HInvokeStatic* invoke = new (arena_) HInvokeStatic(
210 arena_, number_of_arguments, dex_offset, method_idx);
211
212 uint32_t args[5];
213 instruction.GetArgs(args);
214
215 for (size_t i = 0; i < number_of_arguments; i++) {
216 HInstruction* arg = LoadLocal(args[i]);
217 HInstruction* push = new (arena_) HPushArgument(arg, i);
218 current_block_->AddInstruction(push);
219 invoke->SetArgumentAt(i, push);
220 }
221
222 current_block_->AddInstruction(invoke);
223 break;
224 }
225
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100226 case Instruction::INVOKE_STATIC_RANGE:
227 case Instruction::INVOKE_DIRECT_RANGE: {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100228 uint32_t method_idx = instruction.VRegB_3rc();
229 const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
230 uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
231 const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
232 const size_t number_of_arguments = instruction.VRegA_3rc();
233
234 if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) {
235 return false;
236 }
237
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100238 // Treat invoke-direct like static calls for now.
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100239 HInvokeStatic* invoke = new (arena_) HInvokeStatic(
240 arena_, number_of_arguments, dex_offset, method_idx);
241 int32_t register_index = instruction.VRegC();
242 for (size_t i = 0; i < number_of_arguments; i++) {
243 HInstruction* arg = LoadLocal(register_index + i);
244 HInstruction* push = new (arena_) HPushArgument(arg, i);
245 current_block_->AddInstruction(push);
246 invoke->SetArgumentAt(i, push);
247 }
248 current_block_->AddInstruction(invoke);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000249 break;
250 }
251
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000252 case Instruction::ADD_INT: {
253 HInstruction* first = LoadLocal(instruction.VRegB());
254 HInstruction* second = LoadLocal(instruction.VRegC());
255 current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second));
256 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
257 break;
258 }
259
260 case Instruction::ADD_INT_2ADDR: {
261 HInstruction* first = LoadLocal(instruction.VRegA());
262 HInstruction* second = LoadLocal(instruction.VRegB());
263 current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second));
264 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
265 break;
266 }
267
268 case Instruction::ADD_INT_LIT16: {
269 HInstruction* first = LoadLocal(instruction.VRegB());
270 HInstruction* second = GetConstant(instruction.VRegC_22s());
271 current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second));
272 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
273 break;
274 }
275
276 case Instruction::ADD_INT_LIT8: {
277 HInstruction* first = LoadLocal(instruction.VRegB());
278 HInstruction* second = GetConstant(instruction.VRegC_22b());
279 current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second));
280 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
281 break;
282 }
283
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100284 case Instruction::NEW_INSTANCE: {
285 current_block_->AddInstruction(
286 new (arena_) HNewInstance(dex_offset, instruction.VRegB_21c()));
287 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
288 break;
289 }
290
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000291 case Instruction::NOP:
292 break;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000293
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000294 default:
295 return false;
296 }
297 return true;
298}
299
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000300HIntConstant* HGraphBuilder::GetConstant0() {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000301 if (constant0_ != nullptr) {
302 return constant0_;
303 }
304 constant0_ = new(arena_) HIntConstant(0);
305 entry_block_->AddInstruction(constant0_);
306 return constant0_;
307}
308
309HIntConstant* HGraphBuilder::GetConstant1() {
310 if (constant1_ != nullptr) {
311 return constant1_;
312 }
313 constant1_ = new(arena_) HIntConstant(1);
314 entry_block_->AddInstruction(constant1_);
315 return constant1_;
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000316}
317
318HIntConstant* HGraphBuilder::GetConstant(int constant) {
319 switch (constant) {
320 case 0: return GetConstant0();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000321 case 1: return GetConstant1();
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000322 default: {
323 HIntConstant* instruction = new (arena_) HIntConstant(constant);
324 entry_block_->AddInstruction(instruction);
325 return instruction;
326 }
327 }
328}
329
330HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
331 return locals_.Get(register_index);
332}
333
334void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) const {
335 HLocal* local = GetLocalAt(register_index);
336 current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction));
337}
338
339HInstruction* HGraphBuilder::LoadLocal(int register_index) const {
340 HLocal* local = GetLocalAt(register_index);
341 current_block_->AddInstruction(new (arena_) HLoadLocal(local));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000342 return current_block_->GetLastInstruction();
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000343}
344
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000345} // namespace art