blob: 190c92562f2a333d742a53ee3ae5307475d2994b [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);
31 locals_.Put(0, local);
32 }
33}
34
35static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) {
36 if (code_item.tries_size_ > 0) return false;
37 if (code_item.outs_size_ > 0) return false;
38 if (code_item.ins_size_ > 0) return false;
39 return true;
40}
41
42HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
43 if (!CanHandleCodeItem(code_item)) return nullptr;
44
45 const uint16_t* code_ptr = code_item.insns_;
46 const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
47
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000048 // Setup the graph with the entry block and exit block.
Nicolas Geoffray818f2102014-02-18 16:43:35 +000049 graph_ = new (arena_) HGraph(arena_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000050 entry_block_ = new (arena_) HBasicBlock(graph_);
51 graph_->AddBlock(entry_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000052 exit_block_ = new (arena_) HBasicBlock(graph_);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000053 graph_->set_entry_block(entry_block_);
54 graph_->set_exit_block(exit_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000055
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000056 InitializeLocals(code_item.registers_size_);
57
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000058 // To avoid splitting blocks, we compute ahead of time the instructions that
59 // start a new block, and create these blocks.
60 ComputeBranchTargets(code_ptr, code_end);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000061
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000062 size_t dex_offset = 0;
Nicolas Geoffray818f2102014-02-18 16:43:35 +000063 while (code_ptr < code_end) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000064 // Update the current block if dex_offset starts a new block.
65 MaybeUpdateCurrentBlock(dex_offset);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000066 const Instruction& instruction = *Instruction::At(code_ptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000067 if (!AnalyzeDexInstruction(instruction, dex_offset)) return nullptr;
68 dex_offset += instruction.SizeInCodeUnits();
Nicolas Geoffray818f2102014-02-18 16:43:35 +000069 code_ptr += instruction.SizeInCodeUnits();
70 }
71
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000072 // Add the exit block at the end to give it the highest id.
Nicolas Geoffray818f2102014-02-18 16:43:35 +000073 graph_->AddBlock(exit_block_);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000074 exit_block_->AddInstruction(new (arena_) HExit());
75 entry_block_->AddInstruction(new (arena_) HGoto());
Nicolas Geoffray818f2102014-02-18 16:43:35 +000076 return graph_;
77}
78
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000079void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
80 HBasicBlock* block = FindBlockStartingAt(index);
81 if (block == nullptr) return;
82
83 if (current_block_ != nullptr) {
84 // Branching instructions clear current_block, so we know
85 // the last instruction of the current block is not a branching
86 // instruction. We add an unconditional goto to the found block.
87 current_block_->AddInstruction(new (arena_) HGoto());
88 current_block_->AddSuccessor(block);
89 }
90 graph_->AddBlock(block);
91 current_block_ = block;
92}
93
94void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end) {
95 // TODO: Support switch instructions.
96 branch_targets_.SetSize(code_end - code_ptr);
97
98 // Create the first block for the dex instructions, single successor of the entry block.
99 HBasicBlock* block = new (arena_) HBasicBlock(graph_);
100 branch_targets_.Put(0, block);
101 entry_block_->AddSuccessor(block);
102
103 // Iterate over all instructions and find branching instructions. Create blocks for
104 // the locations these instructions branch to.
105 size_t dex_offset = 0;
106 while (code_ptr < code_end) {
107 const Instruction& instruction = *Instruction::At(code_ptr);
108 if (instruction.IsBranch()) {
109 int32_t target = instruction.GetTargetOffset() + dex_offset;
110 // Create a block for the target instruction.
111 if (FindBlockStartingAt(target) == nullptr) {
112 block = new (arena_) HBasicBlock(graph_);
113 branch_targets_.Put(target, block);
114 }
115 dex_offset += instruction.SizeInCodeUnits();
116 code_ptr += instruction.SizeInCodeUnits();
117 if ((code_ptr < code_end) && (FindBlockStartingAt(dex_offset) == nullptr)) {
118 block = new (arena_) HBasicBlock(graph_);
119 branch_targets_.Put(dex_offset, block);
120 }
121 } else {
122 code_ptr += instruction.SizeInCodeUnits();
123 dex_offset += instruction.SizeInCodeUnits();
124 }
125 }
126}
127
128HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
129 DCHECK_GE(index, 0);
130 return branch_targets_.Get(index);
131}
132
133bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
134 if (current_block_ == nullptr) return true; // Dead code
135
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000136 switch (instruction.Opcode()) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000137 case Instruction::CONST_4: {
138 int32_t register_index = instruction.VRegA();
139 HIntConstant* constant = GetConstant(instruction.VRegB_11n());
140 UpdateLocal(register_index, constant);
141 break;
142 }
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000143 case Instruction::RETURN_VOID:
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000144 current_block_->AddInstruction(new (arena_) HReturnVoid());
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000145 current_block_->AddSuccessor(exit_block_);
146 current_block_ = nullptr;
147 break;
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000148 case Instruction::IF_EQ: {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000149 HInstruction* first = LoadLocal(instruction.VRegA());
150 HInstruction* second = LoadLocal(instruction.VRegB());
151 current_block_->AddInstruction(new (arena_) HEqual(first, second));
152 current_block_->AddInstruction(new (arena_) HIf(current_block_->last_instruction()));
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000153 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
154 DCHECK(target != nullptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000155 current_block_->AddSuccessor(target);
156 target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
157 DCHECK(target != nullptr);
158 current_block_->AddSuccessor(target);
159 current_block_ = nullptr;
160 break;
161 }
162 case Instruction::GOTO:
163 case Instruction::GOTO_16:
164 case Instruction::GOTO_32: {
165 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
166 DCHECK(target != nullptr);
167 current_block_->AddInstruction(new (arena_) HGoto());
168 current_block_->AddSuccessor(target);
169 current_block_ = nullptr;
170 break;
171 }
172 case Instruction::NOP:
173 break;
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000174 default:
175 return false;
176 }
177 return true;
178}
179
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000180HIntConstant* HGraphBuilder::GetConstant0() {
181 if (constant0_ != nullptr) return constant0_;
182 HIntConstant* constant = new(arena_) HIntConstant(0);
183 entry_block_->AddInstruction(constant);
184 return constant;
185}
186
187HIntConstant* HGraphBuilder::GetConstant(int constant) {
188 switch (constant) {
189 case 0: return GetConstant0();
190 default: {
191 HIntConstant* instruction = new (arena_) HIntConstant(constant);
192 entry_block_->AddInstruction(instruction);
193 return instruction;
194 }
195 }
196}
197
198HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
199 return locals_.Get(register_index);
200}
201
202void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) const {
203 HLocal* local = GetLocalAt(register_index);
204 current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction));
205}
206
207HInstruction* HGraphBuilder::LoadLocal(int register_index) const {
208 HLocal* local = GetLocalAt(register_index);
209 current_block_->AddInstruction(new (arena_) HLoadLocal(local));
210 return current_block_->last_instruction();
211}
212
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000213} // namespace art