blob: 8c6a8cb19fb13a09b3f62b080f0b235325df7cc4 [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 Geoffray818f2102014-02-18 16:43:35 +000019#include "dex_instruction.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000020#include "dex_instruction-inl.h"
Nicolas Geoffray818f2102014-02-18 16:43:35 +000021#include "builder.h"
22#include "nodes.h"
23
24namespace art {
25
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000026void HGraphBuilder::InitializeLocals(int count) {
27 locals_.SetSize(count);
28 for (int i = 0; i < count; i++) {
29 HLocal* local = new (arena_) HLocal(i);
30 entry_block_->AddInstruction(local);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000031 locals_.Put(i, local);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000032 }
33}
34
35static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000036 if (code_item.tries_size_ > 0) {
37 return false;
38 } else if (code_item.outs_size_ > 0) {
39 return false;
40 } 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 Geoffrayd4dd2552014-02-28 10:23:58 +000059 graph_->set_entry_block(entry_block_);
60 graph_->set_exit_block(exit_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000061
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000062 InitializeLocals(code_item.registers_size_);
63
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000064 // To avoid splitting blocks, we compute ahead of time the instructions that
65 // start a new block, and create these blocks.
66 ComputeBranchTargets(code_ptr, code_end);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000067
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000068 size_t dex_offset = 0;
Nicolas Geoffray818f2102014-02-18 16:43:35 +000069 while (code_ptr < code_end) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000070 // Update the current block if dex_offset starts a new block.
71 MaybeUpdateCurrentBlock(dex_offset);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000072 const Instruction& instruction = *Instruction::At(code_ptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000073 if (!AnalyzeDexInstruction(instruction, dex_offset)) return nullptr;
74 dex_offset += instruction.SizeInCodeUnits();
Nicolas Geoffray818f2102014-02-18 16:43:35 +000075 code_ptr += instruction.SizeInCodeUnits();
76 }
77
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000078 // Add the exit block at the end to give it the highest id.
Nicolas Geoffray818f2102014-02-18 16:43:35 +000079 graph_->AddBlock(exit_block_);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000080 exit_block_->AddInstruction(new (arena_) HExit());
81 entry_block_->AddInstruction(new (arena_) HGoto());
Nicolas Geoffray818f2102014-02-18 16:43:35 +000082 return graph_;
83}
84
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000085void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
86 HBasicBlock* block = FindBlockStartingAt(index);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000087 if (block == nullptr) {
88 return;
89 }
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000090
91 if (current_block_ != nullptr) {
92 // Branching instructions clear current_block, so we know
93 // the last instruction of the current block is not a branching
94 // instruction. We add an unconditional goto to the found block.
95 current_block_->AddInstruction(new (arena_) HGoto());
96 current_block_->AddSuccessor(block);
97 }
98 graph_->AddBlock(block);
99 current_block_ = block;
100}
101
102void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end) {
103 // TODO: Support switch instructions.
104 branch_targets_.SetSize(code_end - code_ptr);
105
106 // Create the first block for the dex instructions, single successor of the entry block.
107 HBasicBlock* block = new (arena_) HBasicBlock(graph_);
108 branch_targets_.Put(0, block);
109 entry_block_->AddSuccessor(block);
110
111 // Iterate over all instructions and find branching instructions. Create blocks for
112 // the locations these instructions branch to.
113 size_t dex_offset = 0;
114 while (code_ptr < code_end) {
115 const Instruction& instruction = *Instruction::At(code_ptr);
116 if (instruction.IsBranch()) {
117 int32_t target = instruction.GetTargetOffset() + dex_offset;
118 // Create a block for the target instruction.
119 if (FindBlockStartingAt(target) == nullptr) {
120 block = new (arena_) HBasicBlock(graph_);
121 branch_targets_.Put(target, block);
122 }
123 dex_offset += instruction.SizeInCodeUnits();
124 code_ptr += instruction.SizeInCodeUnits();
125 if ((code_ptr < code_end) && (FindBlockStartingAt(dex_offset) == nullptr)) {
126 block = new (arena_) HBasicBlock(graph_);
127 branch_targets_.Put(dex_offset, block);
128 }
129 } else {
130 code_ptr += instruction.SizeInCodeUnits();
131 dex_offset += instruction.SizeInCodeUnits();
132 }
133 }
134}
135
136HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
137 DCHECK_GE(index, 0);
138 return branch_targets_.Get(index);
139}
140
141bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000142 if (current_block_ == nullptr) {
143 return true; // Dead code
144 }
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000145
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000146 switch (instruction.Opcode()) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000147 case Instruction::CONST_4: {
148 int32_t register_index = instruction.VRegA();
149 HIntConstant* constant = GetConstant(instruction.VRegB_11n());
150 UpdateLocal(register_index, constant);
151 break;
152 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000153
154 case Instruction::RETURN_VOID: {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000155 current_block_->AddInstruction(new (arena_) HReturnVoid());
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000156 current_block_->AddSuccessor(exit_block_);
157 current_block_ = nullptr;
158 break;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000159 }
160
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000161 case Instruction::IF_EQ: {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000162 HInstruction* first = LoadLocal(instruction.VRegA());
163 HInstruction* second = LoadLocal(instruction.VRegB());
164 current_block_->AddInstruction(new (arena_) HEqual(first, second));
165 current_block_->AddInstruction(new (arena_) HIf(current_block_->last_instruction()));
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000166 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
167 DCHECK(target != nullptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000168 current_block_->AddSuccessor(target);
169 target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
170 DCHECK(target != nullptr);
171 current_block_->AddSuccessor(target);
172 current_block_ = nullptr;
173 break;
174 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000175
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000176 case Instruction::GOTO:
177 case Instruction::GOTO_16:
178 case Instruction::GOTO_32: {
179 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
180 DCHECK(target != nullptr);
181 current_block_->AddInstruction(new (arena_) HGoto());
182 current_block_->AddSuccessor(target);
183 current_block_ = nullptr;
184 break;
185 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000186
187 case Instruction::RETURN: {
188 HInstruction* value = LoadLocal(instruction.VRegA());
189 current_block_->AddInstruction(new (arena_) HReturn(value));
190 current_block_->AddSuccessor(exit_block_);
191 current_block_ = nullptr;
192 break;
193 }
194
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000195 case Instruction::NOP:
196 break;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000197
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000198 default:
199 return false;
200 }
201 return true;
202}
203
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000204HIntConstant* HGraphBuilder::GetConstant0() {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000205 if (constant0_ != nullptr) {
206 return constant0_;
207 }
208 constant0_ = new(arena_) HIntConstant(0);
209 entry_block_->AddInstruction(constant0_);
210 return constant0_;
211}
212
213HIntConstant* HGraphBuilder::GetConstant1() {
214 if (constant1_ != nullptr) {
215 return constant1_;
216 }
217 constant1_ = new(arena_) HIntConstant(1);
218 entry_block_->AddInstruction(constant1_);
219 return constant1_;
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000220}
221
222HIntConstant* HGraphBuilder::GetConstant(int constant) {
223 switch (constant) {
224 case 0: return GetConstant0();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000225 case 1: return GetConstant1();
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000226 default: {
227 HIntConstant* instruction = new (arena_) HIntConstant(constant);
228 entry_block_->AddInstruction(instruction);
229 return instruction;
230 }
231 }
232}
233
234HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
235 return locals_.Get(register_index);
236}
237
238void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) const {
239 HLocal* local = GetLocalAt(register_index);
240 current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction));
241}
242
243HInstruction* HGraphBuilder::LoadLocal(int register_index) const {
244 HLocal* local = GetLocalAt(register_index);
245 current_block_->AddInstruction(new (arena_) HLoadLocal(local));
246 return current_block_->last_instruction();
247}
248
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000249} // namespace art