blob: e6db7bccc35df3d200a22c2a6b5acd96db256438 [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 Geoffray818f2102014-02-18 16:43:35 +000032
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000033 // To avoid splitting blocks, we compute ahead of time the instructions that
34 // start a new block, and create these blocks.
35 ComputeBranchTargets(code_ptr, code_end);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000036
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000037 size_t dex_offset = 0;
Nicolas Geoffray818f2102014-02-18 16:43:35 +000038 while (code_ptr < code_end) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000039 // Update the current block if dex_offset starts a new block.
40 MaybeUpdateCurrentBlock(dex_offset);
Nicolas Geoffray818f2102014-02-18 16:43:35 +000041 const Instruction& instruction = *Instruction::At(code_ptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000042 if (!AnalyzeDexInstruction(instruction, dex_offset)) return nullptr;
43 dex_offset += instruction.SizeInCodeUnits();
Nicolas Geoffray818f2102014-02-18 16:43:35 +000044 code_ptr += instruction.SizeInCodeUnits();
45 }
46
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000047 // Add the exit block at the end to give it the highest id.
Nicolas Geoffray818f2102014-02-18 16:43:35 +000048 graph_->AddBlock(exit_block_);
49 return graph_;
50}
51
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000052void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
53 HBasicBlock* block = FindBlockStartingAt(index);
54 if (block == nullptr) return;
55
56 if (current_block_ != nullptr) {
57 // Branching instructions clear current_block, so we know
58 // the last instruction of the current block is not a branching
59 // instruction. We add an unconditional goto to the found block.
60 current_block_->AddInstruction(new (arena_) HGoto());
61 current_block_->AddSuccessor(block);
62 }
63 graph_->AddBlock(block);
64 current_block_ = block;
65}
66
67void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end) {
68 // TODO: Support switch instructions.
69 branch_targets_.SetSize(code_end - code_ptr);
70
71 // Create the first block for the dex instructions, single successor of the entry block.
72 HBasicBlock* block = new (arena_) HBasicBlock(graph_);
73 branch_targets_.Put(0, block);
74 entry_block_->AddSuccessor(block);
75
76 // Iterate over all instructions and find branching instructions. Create blocks for
77 // the locations these instructions branch to.
78 size_t dex_offset = 0;
79 while (code_ptr < code_end) {
80 const Instruction& instruction = *Instruction::At(code_ptr);
81 if (instruction.IsBranch()) {
82 int32_t target = instruction.GetTargetOffset() + dex_offset;
83 // Create a block for the target instruction.
84 if (FindBlockStartingAt(target) == nullptr) {
85 block = new (arena_) HBasicBlock(graph_);
86 branch_targets_.Put(target, block);
87 }
88 dex_offset += instruction.SizeInCodeUnits();
89 code_ptr += instruction.SizeInCodeUnits();
90 if ((code_ptr < code_end) && (FindBlockStartingAt(dex_offset) == nullptr)) {
91 block = new (arena_) HBasicBlock(graph_);
92 branch_targets_.Put(dex_offset, block);
93 }
94 } else {
95 code_ptr += instruction.SizeInCodeUnits();
96 dex_offset += instruction.SizeInCodeUnits();
97 }
98 }
99}
100
101HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
102 DCHECK_GE(index, 0);
103 return branch_targets_.Get(index);
104}
105
106bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
107 if (current_block_ == nullptr) return true; // Dead code
108
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000109 switch (instruction.Opcode()) {
110 case Instruction::RETURN_VOID:
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000111 current_block_->AddInstruction(new (arena_) HReturnVoid());
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000112 current_block_->AddSuccessor(exit_block_);
113 current_block_ = nullptr;
114 break;
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000115 case Instruction::IF_EQ: {
116 // TODO: Read the dex register.
117 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
118 DCHECK(target != nullptr);
119 current_block_->AddInstruction(new (arena_) HIf());
120 current_block_->AddSuccessor(target);
121 target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
122 DCHECK(target != nullptr);
123 current_block_->AddSuccessor(target);
124 current_block_ = nullptr;
125 break;
126 }
127 case Instruction::GOTO:
128 case Instruction::GOTO_16:
129 case Instruction::GOTO_32: {
130 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
131 DCHECK(target != nullptr);
132 current_block_->AddInstruction(new (arena_) HGoto());
133 current_block_->AddSuccessor(target);
134 current_block_ = nullptr;
135 break;
136 }
137 case Instruction::NOP:
138 break;
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000139 default:
140 return false;
141 }
142 return true;
143}
144
145} // namespace art