blob: f89583d96f2d0a3052080d696479eafd1adc5421 [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 Geoffrayf583e592014-04-07 13:20:42 +010028void HGraphBuilder::InitializeLocals(uint16_t count) {
29 graph_->SetNumberOfVRegs(count);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000030 locals_.SetSize(count);
31 for (int i = 0; i < count; i++) {
32 HLocal* local = new (arena_) HLocal(i);
33 entry_block_->AddInstruction(local);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000034 locals_.Put(i, local);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000035 }
36}
37
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010038bool HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) {
39 // dex_compilation_unit_ is null only when unit testing.
40 if (dex_compilation_unit_ == nullptr) {
41 return true;
42 }
43
44 graph_->SetNumberOfInVRegs(number_of_parameters);
45 const char* shorty = dex_compilation_unit_->GetShorty();
46 int locals_index = locals_.Size() - number_of_parameters;
47 HBasicBlock* first_block = entry_block_->GetSuccessors()->Get(0);
48 int parameter_index = 0;
49
50 if (!dex_compilation_unit_->IsStatic()) {
51 // Add the implicit 'this' argument, not expressed in the signature.
52 HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++);
53 first_block->AddInstruction(parameter);
54 HLocal* local = GetLocalAt(locals_index++);
55 first_block->AddInstruction(new (arena_) HStoreLocal(local, parameter));
56 number_of_parameters--;
57 }
58
59 uint32_t pos = 1;
60 for (int i = 0; i < number_of_parameters; i++) {
61 switch (shorty[pos++]) {
62 case 'F':
63 case 'D':
64 case 'J': {
65 return false;
66 }
67
68 default: {
69 // integer and reference parameters.
70 HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++);
71 first_block->AddInstruction(parameter);
72 HLocal* local = GetLocalAt(locals_index++);
73 // Store the parameter value in the local that the dex code will use
74 // to reference that parameter.
75 first_block->AddInstruction(new (arena_) HStoreLocal(local, parameter));
76 break;
77 }
78 }
79 }
80 return true;
81}
82
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000083static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000084 if (code_item.tries_size_ > 0) {
85 return false;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000086 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000087 return true;
88}
89
90HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000091 if (!CanHandleCodeItem(code_item)) {
92 return nullptr;
93 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000094
95 const uint16_t* code_ptr = code_item.insns_;
96 const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
97
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000098 // Setup the graph with the entry block and exit block.
Nicolas Geoffray818f2102014-02-18 16:43:35 +000099 graph_ = new (arena_) HGraph(arena_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000100 entry_block_ = new (arena_) HBasicBlock(graph_);
101 graph_->AddBlock(entry_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000102 exit_block_ = new (arena_) HBasicBlock(graph_);
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000103 graph_->SetEntryBlock(entry_block_);
104 graph_->SetExitBlock(exit_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000105
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000106 InitializeLocals(code_item.registers_size_);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100107 graph_->UpdateMaximumNumberOfOutVRegs(code_item.outs_size_);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000108
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000109 // To avoid splitting blocks, we compute ahead of time the instructions that
110 // start a new block, and create these blocks.
111 ComputeBranchTargets(code_ptr, code_end);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000112
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100113 if (!InitializeParameters(code_item.ins_size_)) {
114 return nullptr;
115 }
116
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000117 size_t dex_offset = 0;
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000118 while (code_ptr < code_end) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000119 // Update the current block if dex_offset starts a new block.
120 MaybeUpdateCurrentBlock(dex_offset);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000121 const Instruction& instruction = *Instruction::At(code_ptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000122 if (!AnalyzeDexInstruction(instruction, dex_offset)) return nullptr;
123 dex_offset += instruction.SizeInCodeUnits();
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000124 code_ptr += instruction.SizeInCodeUnits();
125 }
126
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000127 // Add the exit block at the end to give it the highest id.
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000128 graph_->AddBlock(exit_block_);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000129 exit_block_->AddInstruction(new (arena_) HExit());
130 entry_block_->AddInstruction(new (arena_) HGoto());
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000131 return graph_;
132}
133
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000134void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
135 HBasicBlock* block = FindBlockStartingAt(index);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000136 if (block == nullptr) {
137 return;
138 }
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000139
140 if (current_block_ != nullptr) {
141 // Branching instructions clear current_block, so we know
142 // the last instruction of the current block is not a branching
143 // instruction. We add an unconditional goto to the found block.
144 current_block_->AddInstruction(new (arena_) HGoto());
145 current_block_->AddSuccessor(block);
146 }
147 graph_->AddBlock(block);
148 current_block_ = block;
149}
150
151void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end) {
152 // TODO: Support switch instructions.
153 branch_targets_.SetSize(code_end - code_ptr);
154
155 // Create the first block for the dex instructions, single successor of the entry block.
156 HBasicBlock* block = new (arena_) HBasicBlock(graph_);
157 branch_targets_.Put(0, block);
158 entry_block_->AddSuccessor(block);
159
160 // Iterate over all instructions and find branching instructions. Create blocks for
161 // the locations these instructions branch to.
162 size_t dex_offset = 0;
163 while (code_ptr < code_end) {
164 const Instruction& instruction = *Instruction::At(code_ptr);
165 if (instruction.IsBranch()) {
166 int32_t target = instruction.GetTargetOffset() + dex_offset;
167 // Create a block for the target instruction.
168 if (FindBlockStartingAt(target) == nullptr) {
169 block = new (arena_) HBasicBlock(graph_);
170 branch_targets_.Put(target, block);
171 }
172 dex_offset += instruction.SizeInCodeUnits();
173 code_ptr += instruction.SizeInCodeUnits();
174 if ((code_ptr < code_end) && (FindBlockStartingAt(dex_offset) == nullptr)) {
175 block = new (arena_) HBasicBlock(graph_);
176 branch_targets_.Put(dex_offset, block);
177 }
178 } else {
179 code_ptr += instruction.SizeInCodeUnits();
180 dex_offset += instruction.SizeInCodeUnits();
181 }
182 }
183}
184
185HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
186 DCHECK_GE(index, 0);
187 return branch_targets_.Get(index);
188}
189
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100190template<typename T>
191void HGraphBuilder::Binop_32x(const Instruction& instruction) {
192 HInstruction* first = LoadLocal(instruction.VRegB());
193 HInstruction* second = LoadLocal(instruction.VRegC());
194 current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
195 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
196}
197
198template<typename T>
199void HGraphBuilder::Binop_12x(const Instruction& instruction) {
200 HInstruction* first = LoadLocal(instruction.VRegA());
201 HInstruction* second = LoadLocal(instruction.VRegB());
202 current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
203 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
204}
205
206template<typename T>
207void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) {
208 HInstruction* first = LoadLocal(instruction.VRegB());
209 HInstruction* second = GetConstant(instruction.VRegC_22s());
210 if (reverse) {
211 std::swap(first, second);
212 }
213 current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
214 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
215}
216
217template<typename T>
218void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) {
219 HInstruction* first = LoadLocal(instruction.VRegB());
220 HInstruction* second = GetConstant(instruction.VRegC_22b());
221 if (reverse) {
222 std::swap(first, second);
223 }
224 current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
225 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
226}
227
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000228bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000229 if (current_block_ == nullptr) {
230 return true; // Dead code
231 }
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000232
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000233 switch (instruction.Opcode()) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000234 case Instruction::CONST_4: {
235 int32_t register_index = instruction.VRegA();
236 HIntConstant* constant = GetConstant(instruction.VRegB_11n());
237 UpdateLocal(register_index, constant);
238 break;
239 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000240
241 case Instruction::RETURN_VOID: {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000242 current_block_->AddInstruction(new (arena_) HReturnVoid());
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000243 current_block_->AddSuccessor(exit_block_);
244 current_block_ = nullptr;
245 break;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000246 }
247
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000248 case Instruction::IF_EQ: {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000249 HInstruction* first = LoadLocal(instruction.VRegA());
250 HInstruction* second = LoadLocal(instruction.VRegB());
251 current_block_->AddInstruction(new (arena_) HEqual(first, second));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000252 current_block_->AddInstruction(new (arena_) HIf(current_block_->GetLastInstruction()));
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000253 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
254 DCHECK(target != nullptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000255 current_block_->AddSuccessor(target);
256 target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
257 DCHECK(target != nullptr);
258 current_block_->AddSuccessor(target);
259 current_block_ = nullptr;
260 break;
261 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000262
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000263 case Instruction::GOTO:
264 case Instruction::GOTO_16:
265 case Instruction::GOTO_32: {
266 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
267 DCHECK(target != nullptr);
268 current_block_->AddInstruction(new (arena_) HGoto());
269 current_block_->AddSuccessor(target);
270 current_block_ = nullptr;
271 break;
272 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000273
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100274 case Instruction::RETURN:
275 case Instruction::RETURN_OBJECT: {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000276 HInstruction* value = LoadLocal(instruction.VRegA());
277 current_block_->AddInstruction(new (arena_) HReturn(value));
278 current_block_->AddSuccessor(exit_block_);
279 current_block_ = nullptr;
280 break;
281 }
282
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100283 case Instruction::INVOKE_STATIC:
284 case Instruction::INVOKE_DIRECT: {
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000285 uint32_t method_idx = instruction.VRegB_35c();
286 const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
287 uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
288 const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
289 const size_t number_of_arguments = instruction.VRegA_35c();
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100290
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000291 if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) {
292 return false;
293 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100294
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100295 // Treat invoke-direct like static calls for now.
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100296 HInvokeStatic* invoke = new (arena_) HInvokeStatic(
297 arena_, number_of_arguments, dex_offset, method_idx);
298
299 uint32_t args[5];
300 instruction.GetArgs(args);
301
302 for (size_t i = 0; i < number_of_arguments; i++) {
303 HInstruction* arg = LoadLocal(args[i]);
304 HInstruction* push = new (arena_) HPushArgument(arg, i);
305 current_block_->AddInstruction(push);
306 invoke->SetArgumentAt(i, push);
307 }
308
309 current_block_->AddInstruction(invoke);
310 break;
311 }
312
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100313 case Instruction::INVOKE_STATIC_RANGE:
314 case Instruction::INVOKE_DIRECT_RANGE: {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100315 uint32_t method_idx = instruction.VRegB_3rc();
316 const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
317 uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
318 const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
319 const size_t number_of_arguments = instruction.VRegA_3rc();
320
321 if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) {
322 return false;
323 }
324
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100325 // Treat invoke-direct like static calls for now.
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100326 HInvokeStatic* invoke = new (arena_) HInvokeStatic(
327 arena_, number_of_arguments, dex_offset, method_idx);
328 int32_t register_index = instruction.VRegC();
329 for (size_t i = 0; i < number_of_arguments; i++) {
330 HInstruction* arg = LoadLocal(register_index + i);
331 HInstruction* push = new (arena_) HPushArgument(arg, i);
332 current_block_->AddInstruction(push);
333 invoke->SetArgumentAt(i, push);
334 }
335 current_block_->AddInstruction(invoke);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000336 break;
337 }
338
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000339 case Instruction::ADD_INT: {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100340 Binop_32x<HAdd>(instruction);
341 break;
342 }
343
344 case Instruction::SUB_INT: {
345 Binop_32x<HSub>(instruction);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000346 break;
347 }
348
349 case Instruction::ADD_INT_2ADDR: {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100350 Binop_12x<HAdd>(instruction);
351 break;
352 }
353
354 case Instruction::SUB_INT_2ADDR: {
355 Binop_12x<HSub>(instruction);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000356 break;
357 }
358
359 case Instruction::ADD_INT_LIT16: {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100360 Binop_22s<HAdd>(instruction, false);
361 break;
362 }
363
364 case Instruction::RSUB_INT: {
365 Binop_22s<HSub>(instruction, true);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000366 break;
367 }
368
369 case Instruction::ADD_INT_LIT8: {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100370 Binop_22b<HAdd>(instruction, false);
371 break;
372 }
373
374 case Instruction::RSUB_INT_LIT8: {
375 Binop_22b<HSub>(instruction, true);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000376 break;
377 }
378
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100379 case Instruction::NEW_INSTANCE: {
380 current_block_->AddInstruction(
381 new (arena_) HNewInstance(dex_offset, instruction.VRegB_21c()));
382 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
383 break;
384 }
385
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000386 case Instruction::NOP:
387 break;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000388
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000389 default:
390 return false;
391 }
392 return true;
393}
394
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000395HIntConstant* HGraphBuilder::GetConstant0() {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000396 if (constant0_ != nullptr) {
397 return constant0_;
398 }
399 constant0_ = new(arena_) HIntConstant(0);
400 entry_block_->AddInstruction(constant0_);
401 return constant0_;
402}
403
404HIntConstant* HGraphBuilder::GetConstant1() {
405 if (constant1_ != nullptr) {
406 return constant1_;
407 }
408 constant1_ = new(arena_) HIntConstant(1);
409 entry_block_->AddInstruction(constant1_);
410 return constant1_;
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000411}
412
413HIntConstant* HGraphBuilder::GetConstant(int constant) {
414 switch (constant) {
415 case 0: return GetConstant0();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000416 case 1: return GetConstant1();
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000417 default: {
418 HIntConstant* instruction = new (arena_) HIntConstant(constant);
419 entry_block_->AddInstruction(instruction);
420 return instruction;
421 }
422 }
423}
424
425HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
426 return locals_.Get(register_index);
427}
428
429void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) const {
430 HLocal* local = GetLocalAt(register_index);
431 current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction));
432}
433
434HInstruction* HGraphBuilder::LoadLocal(int register_index) const {
435 HLocal* local = GetLocalAt(register_index);
436 current_block_->AddInstruction(new (arena_) HLoadLocal(local));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000437 return current_block_->GetLastInstruction();
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000438}
439
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000440} // namespace art