blob: f78e56bf5f6c17e540df537a88f59686874a55dc [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
18#include "dex_instruction.h"
19#include "builder.h"
20#include "nodes.h"
21
22namespace art {
23
24HGraph* HGraphBuilder::BuildGraph(const uint16_t* code_ptr, const uint16_t* code_end) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000025 // Setup the graph with the entry block and exit block.
Nicolas Geoffray818f2102014-02-18 16:43:35 +000026 graph_ = new (arena_) HGraph(arena_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000027 entry_block_ = new (arena_) HBasicBlock(graph_);
28 graph_->AddBlock(entry_block_);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000029 entry_block_->AddInstruction(new (arena_) HGoto());
Nicolas Geoffray818f2102014-02-18 16:43:35 +000030 exit_block_ = new (arena_) HBasicBlock(graph_);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000031 exit_block_->AddInstruction(new (arena_) HExit());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000032 graph_->set_entry_block(entry_block_);
33 graph_->set_exit_block(exit_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000034
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000035 // To avoid splitting blocks, we compute ahead of time the instructions that
36 // start a new block, and create these blocks.
37 ComputeBranchTargets(code_ptr, code_end);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000038
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000039 size_t dex_offset = 0;
Nicolas Geoffray818f2102014-02-18 16:43:35 +000040 while (code_ptr < code_end) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000041 // Update the current block if dex_offset starts a new block.
42 MaybeUpdateCurrentBlock(dex_offset);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000043 const Instruction& instruction = *Instruction::At(code_ptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000044 if (!AnalyzeDexInstruction(instruction, dex_offset)) return nullptr;
45 dex_offset += instruction.SizeInCodeUnits();
Nicolas Geoffray818f2102014-02-18 16:43:35 +000046 code_ptr += instruction.SizeInCodeUnits();
47 }
48
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000049 // Add the exit block at the end to give it the highest id.
Nicolas Geoffray818f2102014-02-18 16:43:35 +000050 graph_->AddBlock(exit_block_);
51 return graph_;
52}
53
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000054void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
55 HBasicBlock* block = FindBlockStartingAt(index);
56 if (block == nullptr) return;
57
58 if (current_block_ != nullptr) {
59 // Branching instructions clear current_block, so we know
60 // the last instruction of the current block is not a branching
61 // instruction. We add an unconditional goto to the found block.
62 current_block_->AddInstruction(new (arena_) HGoto());
63 current_block_->AddSuccessor(block);
64 }
65 graph_->AddBlock(block);
66 current_block_ = block;
67}
68
69void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end) {
70 // TODO: Support switch instructions.
71 branch_targets_.SetSize(code_end - code_ptr);
72
73 // Create the first block for the dex instructions, single successor of the entry block.
74 HBasicBlock* block = new (arena_) HBasicBlock(graph_);
75 branch_targets_.Put(0, block);
76 entry_block_->AddSuccessor(block);
77
78 // Iterate over all instructions and find branching instructions. Create blocks for
79 // the locations these instructions branch to.
80 size_t dex_offset = 0;
81 while (code_ptr < code_end) {
82 const Instruction& instruction = *Instruction::At(code_ptr);
83 if (instruction.IsBranch()) {
84 int32_t target = instruction.GetTargetOffset() + dex_offset;
85 // Create a block for the target instruction.
86 if (FindBlockStartingAt(target) == nullptr) {
87 block = new (arena_) HBasicBlock(graph_);
88 branch_targets_.Put(target, block);
89 }
90 dex_offset += instruction.SizeInCodeUnits();
91 code_ptr += instruction.SizeInCodeUnits();
92 if ((code_ptr < code_end) && (FindBlockStartingAt(dex_offset) == nullptr)) {
93 block = new (arena_) HBasicBlock(graph_);
94 branch_targets_.Put(dex_offset, block);
95 }
96 } else {
97 code_ptr += instruction.SizeInCodeUnits();
98 dex_offset += instruction.SizeInCodeUnits();
99 }
100 }
101}
102
103HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
104 DCHECK_GE(index, 0);
105 return branch_targets_.Get(index);
106}
107
108bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
109 if (current_block_ == nullptr) return true; // Dead code
110
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000111 switch (instruction.Opcode()) {
112 case Instruction::RETURN_VOID:
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000113 current_block_->AddInstruction(new (arena_) HReturnVoid());
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000114 current_block_->AddSuccessor(exit_block_);
115 current_block_ = nullptr;
116 break;
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000117 case Instruction::IF_EQ: {
118 // TODO: Read the dex register.
119 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
120 DCHECK(target != nullptr);
121 current_block_->AddInstruction(new (arena_) HIf());
122 current_block_->AddSuccessor(target);
123 target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
124 DCHECK(target != nullptr);
125 current_block_->AddSuccessor(target);
126 current_block_ = nullptr;
127 break;
128 }
129 case Instruction::GOTO:
130 case Instruction::GOTO_16:
131 case Instruction::GOTO_32: {
132 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
133 DCHECK(target != nullptr);
134 current_block_->AddInstruction(new (arena_) HGoto());
135 current_block_->AddSuccessor(target);
136 current_block_ = nullptr;
137 break;
138 }
139 case Instruction::NOP:
140 break;
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000141 default:
142 return false;
143 }
144 return true;
145}
146
147} // namespace art