1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "block_builder.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "base/logging.h" // FOR VLOG.
20*795d594fSAndroid Build Coastguard Worker #include "dex/bytecode_utils.h"
21*795d594fSAndroid Build Coastguard Worker #include "dex/code_item_accessors-inl.h"
22*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_exception_helpers.h"
23*795d594fSAndroid Build Coastguard Worker
24*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
25*795d594fSAndroid Build Coastguard Worker
HBasicBlockBuilder(HGraph * graph,const DexFile * const dex_file,const CodeItemDebugInfoAccessor & accessor,ScopedArenaAllocator * local_allocator)26*795d594fSAndroid Build Coastguard Worker HBasicBlockBuilder::HBasicBlockBuilder(HGraph* graph,
27*795d594fSAndroid Build Coastguard Worker const DexFile* const dex_file,
28*795d594fSAndroid Build Coastguard Worker const CodeItemDebugInfoAccessor& accessor,
29*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator* local_allocator)
30*795d594fSAndroid Build Coastguard Worker : allocator_(graph->GetAllocator()),
31*795d594fSAndroid Build Coastguard Worker graph_(graph),
32*795d594fSAndroid Build Coastguard Worker dex_file_(dex_file),
33*795d594fSAndroid Build Coastguard Worker code_item_accessor_(accessor),
34*795d594fSAndroid Build Coastguard Worker local_allocator_(local_allocator),
35*795d594fSAndroid Build Coastguard Worker branch_targets_(code_item_accessor_.HasCodeItem()
36*795d594fSAndroid Build Coastguard Worker ? code_item_accessor_.InsnsSizeInCodeUnits()
37*795d594fSAndroid Build Coastguard Worker : /* fake dex_pc=0 for intrinsic graph */ 1u,
38*795d594fSAndroid Build Coastguard Worker nullptr,
39*795d594fSAndroid Build Coastguard Worker local_allocator->Adapter(kArenaAllocGraphBuilder)),
40*795d594fSAndroid Build Coastguard Worker throwing_blocks_(kDefaultNumberOfThrowingBlocks,
41*795d594fSAndroid Build Coastguard Worker local_allocator->Adapter(kArenaAllocGraphBuilder)) {}
42*795d594fSAndroid Build Coastguard Worker
MaybeCreateBlockAt(uint32_t dex_pc)43*795d594fSAndroid Build Coastguard Worker HBasicBlock* HBasicBlockBuilder::MaybeCreateBlockAt(uint32_t dex_pc) {
44*795d594fSAndroid Build Coastguard Worker return MaybeCreateBlockAt(dex_pc, dex_pc);
45*795d594fSAndroid Build Coastguard Worker }
46*795d594fSAndroid Build Coastguard Worker
MaybeCreateBlockAt(uint32_t semantic_dex_pc,uint32_t store_dex_pc)47*795d594fSAndroid Build Coastguard Worker HBasicBlock* HBasicBlockBuilder::MaybeCreateBlockAt(uint32_t semantic_dex_pc,
48*795d594fSAndroid Build Coastguard Worker uint32_t store_dex_pc) {
49*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = branch_targets_[store_dex_pc];
50*795d594fSAndroid Build Coastguard Worker if (block == nullptr) {
51*795d594fSAndroid Build Coastguard Worker block = new (allocator_) HBasicBlock(graph_, semantic_dex_pc);
52*795d594fSAndroid Build Coastguard Worker branch_targets_[store_dex_pc] = block;
53*795d594fSAndroid Build Coastguard Worker }
54*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(block->GetDexPc(), semantic_dex_pc);
55*795d594fSAndroid Build Coastguard Worker return block;
56*795d594fSAndroid Build Coastguard Worker }
57*795d594fSAndroid Build Coastguard Worker
CreateBranchTargets()58*795d594fSAndroid Build Coastguard Worker bool HBasicBlockBuilder::CreateBranchTargets() {
59*795d594fSAndroid Build Coastguard Worker // Create the first block for the dex instructions, single successor of the entry block.
60*795d594fSAndroid Build Coastguard Worker MaybeCreateBlockAt(0u);
61*795d594fSAndroid Build Coastguard Worker
62*795d594fSAndroid Build Coastguard Worker if (code_item_accessor_.TriesSize() != 0) {
63*795d594fSAndroid Build Coastguard Worker // Create branch targets at the start/end of the TryItem range. These are
64*795d594fSAndroid Build Coastguard Worker // places where the program might fall through into/out of the a block and
65*795d594fSAndroid Build Coastguard Worker // where TryBoundary instructions will be inserted later. Other edges which
66*795d594fSAndroid Build Coastguard Worker // enter/exit the try blocks are a result of branches/switches.
67*795d594fSAndroid Build Coastguard Worker for (const dex::TryItem& try_item : code_item_accessor_.TryItems()) {
68*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc_start = try_item.start_addr_;
69*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc_end = dex_pc_start + try_item.insn_count_;
70*795d594fSAndroid Build Coastguard Worker MaybeCreateBlockAt(dex_pc_start);
71*795d594fSAndroid Build Coastguard Worker if (dex_pc_end < code_item_accessor_.InsnsSizeInCodeUnits()) {
72*795d594fSAndroid Build Coastguard Worker // TODO: Do not create block if the last instruction cannot fall through.
73*795d594fSAndroid Build Coastguard Worker MaybeCreateBlockAt(dex_pc_end);
74*795d594fSAndroid Build Coastguard Worker } else if (dex_pc_end == code_item_accessor_.InsnsSizeInCodeUnits()) {
75*795d594fSAndroid Build Coastguard Worker // The TryItem spans until the very end of the CodeItem and therefore
76*795d594fSAndroid Build Coastguard Worker // cannot have any code afterwards.
77*795d594fSAndroid Build Coastguard Worker } else {
78*795d594fSAndroid Build Coastguard Worker // The TryItem spans beyond the end of the CodeItem. This is invalid code.
79*795d594fSAndroid Build Coastguard Worker VLOG(compiler) << "Not compiled: TryItem spans beyond the end of the CodeItem";
80*795d594fSAndroid Build Coastguard Worker return false;
81*795d594fSAndroid Build Coastguard Worker }
82*795d594fSAndroid Build Coastguard Worker }
83*795d594fSAndroid Build Coastguard Worker
84*795d594fSAndroid Build Coastguard Worker // Create branch targets for exception handlers.
85*795d594fSAndroid Build Coastguard Worker const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData();
86*795d594fSAndroid Build Coastguard Worker uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
87*795d594fSAndroid Build Coastguard Worker for (uint32_t idx = 0; idx < handlers_size; ++idx) {
88*795d594fSAndroid Build Coastguard Worker CatchHandlerIterator iterator(handlers_ptr);
89*795d594fSAndroid Build Coastguard Worker for (; iterator.HasNext(); iterator.Next()) {
90*795d594fSAndroid Build Coastguard Worker MaybeCreateBlockAt(iterator.GetHandlerAddress());
91*795d594fSAndroid Build Coastguard Worker }
92*795d594fSAndroid Build Coastguard Worker handlers_ptr = iterator.EndDataPointer();
93*795d594fSAndroid Build Coastguard Worker }
94*795d594fSAndroid Build Coastguard Worker }
95*795d594fSAndroid Build Coastguard Worker
96*795d594fSAndroid Build Coastguard Worker // Iterate over all instructions and find branching instructions. Create blocks for
97*795d594fSAndroid Build Coastguard Worker // the locations these instructions branch to.
98*795d594fSAndroid Build Coastguard Worker for (const DexInstructionPcPair& pair : code_item_accessor_) {
99*795d594fSAndroid Build Coastguard Worker const uint32_t dex_pc = pair.DexPc();
100*795d594fSAndroid Build Coastguard Worker const Instruction& instruction = pair.Inst();
101*795d594fSAndroid Build Coastguard Worker
102*795d594fSAndroid Build Coastguard Worker if (instruction.IsBranch()) {
103*795d594fSAndroid Build Coastguard Worker MaybeCreateBlockAt(dex_pc + instruction.GetTargetOffset());
104*795d594fSAndroid Build Coastguard Worker } else if (instruction.IsSwitch()) {
105*795d594fSAndroid Build Coastguard Worker DexSwitchTable table(instruction, dex_pc);
106*795d594fSAndroid Build Coastguard Worker for (DexSwitchTableIterator s_it(table); !s_it.Done(); s_it.Advance()) {
107*795d594fSAndroid Build Coastguard Worker MaybeCreateBlockAt(dex_pc + s_it.CurrentTargetOffset());
108*795d594fSAndroid Build Coastguard Worker
109*795d594fSAndroid Build Coastguard Worker // Create N-1 blocks where we will insert comparisons of the input value
110*795d594fSAndroid Build Coastguard Worker // against the Switch's case keys.
111*795d594fSAndroid Build Coastguard Worker if (table.ShouldBuildDecisionTree() && !s_it.IsLast()) {
112*795d594fSAndroid Build Coastguard Worker // Store the block under dex_pc of the current key at the switch data
113*795d594fSAndroid Build Coastguard Worker // instruction for uniqueness but give it the dex_pc of the SWITCH
114*795d594fSAndroid Build Coastguard Worker // instruction which it semantically belongs to.
115*795d594fSAndroid Build Coastguard Worker MaybeCreateBlockAt(dex_pc, s_it.GetDexPcForCurrentIndex());
116*795d594fSAndroid Build Coastguard Worker }
117*795d594fSAndroid Build Coastguard Worker }
118*795d594fSAndroid Build Coastguard Worker } else if (instruction.Opcode() == Instruction::MOVE_EXCEPTION) {
119*795d594fSAndroid Build Coastguard Worker // End the basic block after MOVE_EXCEPTION. This simplifies the later
120*795d594fSAndroid Build Coastguard Worker // stage of TryBoundary-block insertion.
121*795d594fSAndroid Build Coastguard Worker } else {
122*795d594fSAndroid Build Coastguard Worker continue;
123*795d594fSAndroid Build Coastguard Worker }
124*795d594fSAndroid Build Coastguard Worker
125*795d594fSAndroid Build Coastguard Worker if (instruction.CanFlowThrough()) {
126*795d594fSAndroid Build Coastguard Worker DexInstructionIterator next(std::next(DexInstructionIterator(pair)));
127*795d594fSAndroid Build Coastguard Worker if (next == code_item_accessor_.end()) {
128*795d594fSAndroid Build Coastguard Worker // In the normal case we should never hit this but someone can artificially forge a dex
129*795d594fSAndroid Build Coastguard Worker // file to fall-through out the method code. In this case we bail out compilation.
130*795d594fSAndroid Build Coastguard Worker VLOG(compiler) << "Not compiled: Fall-through beyond the CodeItem";
131*795d594fSAndroid Build Coastguard Worker return false;
132*795d594fSAndroid Build Coastguard Worker }
133*795d594fSAndroid Build Coastguard Worker MaybeCreateBlockAt(next.DexPc());
134*795d594fSAndroid Build Coastguard Worker }
135*795d594fSAndroid Build Coastguard Worker }
136*795d594fSAndroid Build Coastguard Worker
137*795d594fSAndroid Build Coastguard Worker return true;
138*795d594fSAndroid Build Coastguard Worker }
139*795d594fSAndroid Build Coastguard Worker
ConnectBasicBlocks()140*795d594fSAndroid Build Coastguard Worker void HBasicBlockBuilder::ConnectBasicBlocks() {
141*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = graph_->GetEntryBlock();
142*795d594fSAndroid Build Coastguard Worker graph_->AddBlock(block);
143*795d594fSAndroid Build Coastguard Worker
144*795d594fSAndroid Build Coastguard Worker bool is_throwing_block = false;
145*795d594fSAndroid Build Coastguard Worker // Calculate the qucikening index here instead of CreateBranchTargets since it's easier to
146*795d594fSAndroid Build Coastguard Worker // calculate in dex_pc order.
147*795d594fSAndroid Build Coastguard Worker for (const DexInstructionPcPair& pair : code_item_accessor_) {
148*795d594fSAndroid Build Coastguard Worker const uint32_t dex_pc = pair.DexPc();
149*795d594fSAndroid Build Coastguard Worker const Instruction& instruction = pair.Inst();
150*795d594fSAndroid Build Coastguard Worker
151*795d594fSAndroid Build Coastguard Worker // Check if this dex_pc address starts a new basic block.
152*795d594fSAndroid Build Coastguard Worker HBasicBlock* next_block = GetBlockAt(dex_pc);
153*795d594fSAndroid Build Coastguard Worker if (next_block != nullptr) {
154*795d594fSAndroid Build Coastguard Worker if (block != nullptr) {
155*795d594fSAndroid Build Coastguard Worker // Last instruction did not end its basic block but a new one starts here.
156*795d594fSAndroid Build Coastguard Worker // It must have been a block falling through into the next one.
157*795d594fSAndroid Build Coastguard Worker block->AddSuccessor(next_block);
158*795d594fSAndroid Build Coastguard Worker }
159*795d594fSAndroid Build Coastguard Worker block = next_block;
160*795d594fSAndroid Build Coastguard Worker is_throwing_block = false;
161*795d594fSAndroid Build Coastguard Worker graph_->AddBlock(block);
162*795d594fSAndroid Build Coastguard Worker }
163*795d594fSAndroid Build Coastguard Worker
164*795d594fSAndroid Build Coastguard Worker if (block == nullptr) {
165*795d594fSAndroid Build Coastguard Worker // Ignore dead code.
166*795d594fSAndroid Build Coastguard Worker continue;
167*795d594fSAndroid Build Coastguard Worker }
168*795d594fSAndroid Build Coastguard Worker
169*795d594fSAndroid Build Coastguard Worker if (!is_throwing_block && IsThrowingDexInstruction(instruction)) {
170*795d594fSAndroid Build Coastguard Worker DCHECK(!ContainsElement(throwing_blocks_, block));
171*795d594fSAndroid Build Coastguard Worker is_throwing_block = true;
172*795d594fSAndroid Build Coastguard Worker throwing_blocks_.push_back(block);
173*795d594fSAndroid Build Coastguard Worker }
174*795d594fSAndroid Build Coastguard Worker
175*795d594fSAndroid Build Coastguard Worker if (instruction.IsBranch()) {
176*795d594fSAndroid Build Coastguard Worker uint32_t target_dex_pc = dex_pc + instruction.GetTargetOffset();
177*795d594fSAndroid Build Coastguard Worker block->AddSuccessor(GetBlockAt(target_dex_pc));
178*795d594fSAndroid Build Coastguard Worker } else if (instruction.IsReturn() || (instruction.Opcode() == Instruction::THROW)) {
179*795d594fSAndroid Build Coastguard Worker block->AddSuccessor(graph_->GetExitBlock());
180*795d594fSAndroid Build Coastguard Worker } else if (instruction.IsSwitch()) {
181*795d594fSAndroid Build Coastguard Worker DexSwitchTable table(instruction, dex_pc);
182*795d594fSAndroid Build Coastguard Worker for (DexSwitchTableIterator s_it(table); !s_it.Done(); s_it.Advance()) {
183*795d594fSAndroid Build Coastguard Worker uint32_t target_dex_pc = dex_pc + s_it.CurrentTargetOffset();
184*795d594fSAndroid Build Coastguard Worker block->AddSuccessor(GetBlockAt(target_dex_pc));
185*795d594fSAndroid Build Coastguard Worker
186*795d594fSAndroid Build Coastguard Worker if (table.ShouldBuildDecisionTree() && !s_it.IsLast()) {
187*795d594fSAndroid Build Coastguard Worker uint32_t next_case_dex_pc = s_it.GetDexPcForCurrentIndex();
188*795d594fSAndroid Build Coastguard Worker HBasicBlock* next_case_block = GetBlockAt(next_case_dex_pc);
189*795d594fSAndroid Build Coastguard Worker block->AddSuccessor(next_case_block);
190*795d594fSAndroid Build Coastguard Worker block = next_case_block;
191*795d594fSAndroid Build Coastguard Worker graph_->AddBlock(block);
192*795d594fSAndroid Build Coastguard Worker }
193*795d594fSAndroid Build Coastguard Worker }
194*795d594fSAndroid Build Coastguard Worker } else {
195*795d594fSAndroid Build Coastguard Worker // Remaining code only applies to instructions which end their basic block.
196*795d594fSAndroid Build Coastguard Worker continue;
197*795d594fSAndroid Build Coastguard Worker }
198*795d594fSAndroid Build Coastguard Worker
199*795d594fSAndroid Build Coastguard Worker // Go to the next instruction in case we read dex PC below.
200*795d594fSAndroid Build Coastguard Worker if (instruction.CanFlowThrough()) {
201*795d594fSAndroid Build Coastguard Worker block->AddSuccessor(GetBlockAt(std::next(DexInstructionIterator(pair)).DexPc()));
202*795d594fSAndroid Build Coastguard Worker }
203*795d594fSAndroid Build Coastguard Worker
204*795d594fSAndroid Build Coastguard Worker // The basic block ends here. Do not add any more instructions.
205*795d594fSAndroid Build Coastguard Worker block = nullptr;
206*795d594fSAndroid Build Coastguard Worker }
207*795d594fSAndroid Build Coastguard Worker
208*795d594fSAndroid Build Coastguard Worker graph_->AddBlock(graph_->GetExitBlock());
209*795d594fSAndroid Build Coastguard Worker }
210*795d594fSAndroid Build Coastguard Worker
211*795d594fSAndroid Build Coastguard Worker // Returns the TryItem stored for `block` or nullptr if there is no info for it.
GetTryItem(HBasicBlock * block,const ScopedArenaSafeMap<uint32_t,const dex::TryItem * > & try_block_info)212*795d594fSAndroid Build Coastguard Worker static const dex::TryItem* GetTryItem(
213*795d594fSAndroid Build Coastguard Worker HBasicBlock* block,
214*795d594fSAndroid Build Coastguard Worker const ScopedArenaSafeMap<uint32_t, const dex::TryItem*>& try_block_info) {
215*795d594fSAndroid Build Coastguard Worker auto iterator = try_block_info.find(block->GetBlockId());
216*795d594fSAndroid Build Coastguard Worker return (iterator == try_block_info.end()) ? nullptr : iterator->second;
217*795d594fSAndroid Build Coastguard Worker }
218*795d594fSAndroid Build Coastguard Worker
219*795d594fSAndroid Build Coastguard Worker // Iterates over the exception handlers of `try_item`, finds the corresponding
220*795d594fSAndroid Build Coastguard Worker // catch blocks and makes them successors of `try_boundary`. The order of
221*795d594fSAndroid Build Coastguard Worker // successors matches the order in which runtime exception delivery searches
222*795d594fSAndroid Build Coastguard Worker // for a handler.
LinkToCatchBlocks(HTryBoundary * try_boundary,const CodeItemDataAccessor & accessor,const dex::TryItem * try_item,const ScopedArenaSafeMap<uint32_t,HBasicBlock * > & catch_blocks)223*795d594fSAndroid Build Coastguard Worker static void LinkToCatchBlocks(HTryBoundary* try_boundary,
224*795d594fSAndroid Build Coastguard Worker const CodeItemDataAccessor& accessor,
225*795d594fSAndroid Build Coastguard Worker const dex::TryItem* try_item,
226*795d594fSAndroid Build Coastguard Worker const ScopedArenaSafeMap<uint32_t, HBasicBlock*>& catch_blocks) {
227*795d594fSAndroid Build Coastguard Worker for (CatchHandlerIterator it(accessor.GetCatchHandlerData(try_item->handler_off_));
228*795d594fSAndroid Build Coastguard Worker it.HasNext();
229*795d594fSAndroid Build Coastguard Worker it.Next()) {
230*795d594fSAndroid Build Coastguard Worker try_boundary->AddExceptionHandler(catch_blocks.Get(it.GetHandlerAddress()));
231*795d594fSAndroid Build Coastguard Worker }
232*795d594fSAndroid Build Coastguard Worker }
233*795d594fSAndroid Build Coastguard Worker
MightHaveLiveNormalPredecessors(HBasicBlock * catch_block)234*795d594fSAndroid Build Coastguard Worker bool HBasicBlockBuilder::MightHaveLiveNormalPredecessors(HBasicBlock* catch_block) {
235*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
236*795d594fSAndroid Build Coastguard Worker DCHECK_NE(catch_block->GetDexPc(), kNoDexPc) << "Should not be called on synthetic blocks";
237*795d594fSAndroid Build Coastguard Worker DCHECK(!graph_->GetEntryBlock()->GetSuccessors().empty())
238*795d594fSAndroid Build Coastguard Worker << "Basic blocks must have been created and connected";
239*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* predecessor : catch_block->GetPredecessors()) {
240*795d594fSAndroid Build Coastguard Worker DCHECK(!predecessor->IsSingleTryBoundary())
241*795d594fSAndroid Build Coastguard Worker << "TryBoundary blocks must not have not been created yet";
242*795d594fSAndroid Build Coastguard Worker }
243*795d594fSAndroid Build Coastguard Worker }
244*795d594fSAndroid Build Coastguard Worker
245*795d594fSAndroid Build Coastguard Worker const Instruction& first = code_item_accessor_.InstructionAt(catch_block->GetDexPc());
246*795d594fSAndroid Build Coastguard Worker if (first.Opcode() == Instruction::MOVE_EXCEPTION) {
247*795d594fSAndroid Build Coastguard Worker // Verifier guarantees that if a catch block begins with MOVE_EXCEPTION then
248*795d594fSAndroid Build Coastguard Worker // it has no live normal predecessors.
249*795d594fSAndroid Build Coastguard Worker return false;
250*795d594fSAndroid Build Coastguard Worker } else if (catch_block->GetPredecessors().empty()) {
251*795d594fSAndroid Build Coastguard Worker // Normal control-flow edges have already been created. Since block's list of
252*795d594fSAndroid Build Coastguard Worker // predecessors is empty, it cannot have any live or dead normal predecessors.
253*795d594fSAndroid Build Coastguard Worker return false;
254*795d594fSAndroid Build Coastguard Worker }
255*795d594fSAndroid Build Coastguard Worker
256*795d594fSAndroid Build Coastguard Worker // The catch block has normal predecessors but we do not know which are live
257*795d594fSAndroid Build Coastguard Worker // and which will be removed during the initial DCE. Return `true` to signal
258*795d594fSAndroid Build Coastguard Worker // that it may have live normal predecessors.
259*795d594fSAndroid Build Coastguard Worker return true;
260*795d594fSAndroid Build Coastguard Worker }
261*795d594fSAndroid Build Coastguard Worker
InsertTryBoundaryBlocks()262*795d594fSAndroid Build Coastguard Worker void HBasicBlockBuilder::InsertTryBoundaryBlocks() {
263*795d594fSAndroid Build Coastguard Worker if (code_item_accessor_.TriesSize() == 0) {
264*795d594fSAndroid Build Coastguard Worker return;
265*795d594fSAndroid Build Coastguard Worker }
266*795d594fSAndroid Build Coastguard Worker
267*795d594fSAndroid Build Coastguard Worker // Keep a map of all try blocks and their respective TryItems. We do not use
268*795d594fSAndroid Build Coastguard Worker // the block's pointer but rather its id to ensure deterministic iteration.
269*795d594fSAndroid Build Coastguard Worker ScopedArenaSafeMap<uint32_t, const dex::TryItem*> try_block_info(
270*795d594fSAndroid Build Coastguard Worker std::less<uint32_t>(), local_allocator_->Adapter(kArenaAllocGraphBuilder));
271*795d594fSAndroid Build Coastguard Worker
272*795d594fSAndroid Build Coastguard Worker // Obtain TryItem information for blocks with throwing instructions, and split
273*795d594fSAndroid Build Coastguard Worker // blocks which are both try & catch to simplify the graph.
274*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : graph_->GetBlocks()) {
275*795d594fSAndroid Build Coastguard Worker if (block->GetDexPc() == kNoDexPc) {
276*795d594fSAndroid Build Coastguard Worker continue;
277*795d594fSAndroid Build Coastguard Worker }
278*795d594fSAndroid Build Coastguard Worker
279*795d594fSAndroid Build Coastguard Worker // Do not bother creating exceptional edges for try blocks which have no
280*795d594fSAndroid Build Coastguard Worker // throwing instructions. In that case we simply assume that the block is
281*795d594fSAndroid Build Coastguard Worker // not covered by a TryItem. This prevents us from creating a throw-catch
282*795d594fSAndroid Build Coastguard Worker // loop for synchronized blocks.
283*795d594fSAndroid Build Coastguard Worker if (ContainsElement(throwing_blocks_, block)) {
284*795d594fSAndroid Build Coastguard Worker // Try to find a TryItem covering the block.
285*795d594fSAndroid Build Coastguard Worker const dex::TryItem* try_item = code_item_accessor_.FindTryItem(block->GetDexPc());
286*795d594fSAndroid Build Coastguard Worker if (try_item != nullptr) {
287*795d594fSAndroid Build Coastguard Worker // Block throwing and in a TryItem. Store the try block information.
288*795d594fSAndroid Build Coastguard Worker try_block_info.Put(block->GetBlockId(), try_item);
289*795d594fSAndroid Build Coastguard Worker }
290*795d594fSAndroid Build Coastguard Worker }
291*795d594fSAndroid Build Coastguard Worker }
292*795d594fSAndroid Build Coastguard Worker
293*795d594fSAndroid Build Coastguard Worker // Map from a handler dex_pc to the corresponding catch block.
294*795d594fSAndroid Build Coastguard Worker ScopedArenaSafeMap<uint32_t, HBasicBlock*> catch_blocks(
295*795d594fSAndroid Build Coastguard Worker std::less<uint32_t>(), local_allocator_->Adapter(kArenaAllocGraphBuilder));
296*795d594fSAndroid Build Coastguard Worker
297*795d594fSAndroid Build Coastguard Worker // Iterate over catch blocks, create artifical landing pads if necessary to
298*795d594fSAndroid Build Coastguard Worker // simplify the CFG, and set metadata.
299*795d594fSAndroid Build Coastguard Worker const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData();
300*795d594fSAndroid Build Coastguard Worker uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
301*795d594fSAndroid Build Coastguard Worker for (uint32_t idx = 0; idx < handlers_size; ++idx) {
302*795d594fSAndroid Build Coastguard Worker CatchHandlerIterator iterator(handlers_ptr);
303*795d594fSAndroid Build Coastguard Worker for (; iterator.HasNext(); iterator.Next()) {
304*795d594fSAndroid Build Coastguard Worker uint32_t address = iterator.GetHandlerAddress();
305*795d594fSAndroid Build Coastguard Worker auto existing = catch_blocks.find(address);
306*795d594fSAndroid Build Coastguard Worker if (existing != catch_blocks.end()) {
307*795d594fSAndroid Build Coastguard Worker // Catch block already processed.
308*795d594fSAndroid Build Coastguard Worker TryCatchInformation* info = existing->second->GetTryCatchInformation();
309*795d594fSAndroid Build Coastguard Worker if (iterator.GetHandlerTypeIndex() != info->GetCatchTypeIndex()) {
310*795d594fSAndroid Build Coastguard Worker // The handler is for multiple types. We could record all the types, but
311*795d594fSAndroid Build Coastguard Worker // doing class resolution here isn't ideal, and it's unclear whether wasting
312*795d594fSAndroid Build Coastguard Worker // the space in TryCatchInformation is worth it.
313*795d594fSAndroid Build Coastguard Worker info->SetInvalidTypeIndex();
314*795d594fSAndroid Build Coastguard Worker }
315*795d594fSAndroid Build Coastguard Worker continue;
316*795d594fSAndroid Build Coastguard Worker }
317*795d594fSAndroid Build Coastguard Worker
318*795d594fSAndroid Build Coastguard Worker // Check if we should create an artifical landing pad for the catch block.
319*795d594fSAndroid Build Coastguard Worker // We create one if the catch block is also a try block because we do not
320*795d594fSAndroid Build Coastguard Worker // have a strategy for inserting TryBoundaries on exceptional edges.
321*795d594fSAndroid Build Coastguard Worker // We also create one if the block might have normal predecessors so as to
322*795d594fSAndroid Build Coastguard Worker // simplify register allocation.
323*795d594fSAndroid Build Coastguard Worker HBasicBlock* catch_block = GetBlockAt(address);
324*795d594fSAndroid Build Coastguard Worker bool is_try_block = (try_block_info.find(catch_block->GetBlockId()) != try_block_info.end());
325*795d594fSAndroid Build Coastguard Worker if (is_try_block || MightHaveLiveNormalPredecessors(catch_block)) {
326*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_catch_block = new (allocator_) HBasicBlock(graph_, address);
327*795d594fSAndroid Build Coastguard Worker new_catch_block->AddInstruction(new (allocator_) HGoto(address));
328*795d594fSAndroid Build Coastguard Worker new_catch_block->AddSuccessor(catch_block);
329*795d594fSAndroid Build Coastguard Worker graph_->AddBlock(new_catch_block);
330*795d594fSAndroid Build Coastguard Worker catch_block = new_catch_block;
331*795d594fSAndroid Build Coastguard Worker }
332*795d594fSAndroid Build Coastguard Worker
333*795d594fSAndroid Build Coastguard Worker catch_blocks.Put(address, catch_block);
334*795d594fSAndroid Build Coastguard Worker catch_block->SetTryCatchInformation(
335*795d594fSAndroid Build Coastguard Worker new (allocator_) TryCatchInformation(iterator.GetHandlerTypeIndex(), *dex_file_));
336*795d594fSAndroid Build Coastguard Worker }
337*795d594fSAndroid Build Coastguard Worker handlers_ptr = iterator.EndDataPointer();
338*795d594fSAndroid Build Coastguard Worker }
339*795d594fSAndroid Build Coastguard Worker
340*795d594fSAndroid Build Coastguard Worker // Do a pass over the try blocks and insert entering TryBoundaries where at
341*795d594fSAndroid Build Coastguard Worker // least one predecessor is not covered by the same TryItem as the try block.
342*795d594fSAndroid Build Coastguard Worker // We do not split each edge separately, but rather create one boundary block
343*795d594fSAndroid Build Coastguard Worker // that all predecessors are relinked to. This preserves loop headers (b/23895756).
344*795d594fSAndroid Build Coastguard Worker for (const auto& entry : try_block_info) {
345*795d594fSAndroid Build Coastguard Worker uint32_t block_id = entry.first;
346*795d594fSAndroid Build Coastguard Worker const dex::TryItem* try_item = entry.second;
347*795d594fSAndroid Build Coastguard Worker HBasicBlock* try_block = graph_->GetBlocks()[block_id];
348*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* predecessor : try_block->GetPredecessors()) {
349*795d594fSAndroid Build Coastguard Worker if (GetTryItem(predecessor, try_block_info) != try_item) {
350*795d594fSAndroid Build Coastguard Worker // Found a predecessor not covered by the same TryItem. Insert entering
351*795d594fSAndroid Build Coastguard Worker // boundary block.
352*795d594fSAndroid Build Coastguard Worker HTryBoundary* try_entry = new (allocator_) HTryBoundary(
353*795d594fSAndroid Build Coastguard Worker HTryBoundary::BoundaryKind::kEntry, try_block->GetDexPc());
354*795d594fSAndroid Build Coastguard Worker try_block->CreateImmediateDominator()->AddInstruction(try_entry);
355*795d594fSAndroid Build Coastguard Worker LinkToCatchBlocks(try_entry, code_item_accessor_, try_item, catch_blocks);
356*795d594fSAndroid Build Coastguard Worker break;
357*795d594fSAndroid Build Coastguard Worker }
358*795d594fSAndroid Build Coastguard Worker }
359*795d594fSAndroid Build Coastguard Worker }
360*795d594fSAndroid Build Coastguard Worker
361*795d594fSAndroid Build Coastguard Worker // Do a second pass over the try blocks and insert exit TryBoundaries where
362*795d594fSAndroid Build Coastguard Worker // the successor is not in the same TryItem.
363*795d594fSAndroid Build Coastguard Worker for (const auto& entry : try_block_info) {
364*795d594fSAndroid Build Coastguard Worker uint32_t block_id = entry.first;
365*795d594fSAndroid Build Coastguard Worker const dex::TryItem* try_item = entry.second;
366*795d594fSAndroid Build Coastguard Worker HBasicBlock* try_block = graph_->GetBlocks()[block_id];
367*795d594fSAndroid Build Coastguard Worker // NOTE: Do not use iterators because SplitEdge would invalidate them.
368*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = try_block->GetSuccessors().size(); i < e; ++i) {
369*795d594fSAndroid Build Coastguard Worker HBasicBlock* successor = try_block->GetSuccessors()[i];
370*795d594fSAndroid Build Coastguard Worker
371*795d594fSAndroid Build Coastguard Worker // If the successor is a try block, all of its predecessors must be
372*795d594fSAndroid Build Coastguard Worker // covered by the same TryItem. Otherwise the previous pass would have
373*795d594fSAndroid Build Coastguard Worker // created a non-throwing boundary block.
374*795d594fSAndroid Build Coastguard Worker if (GetTryItem(successor, try_block_info) != nullptr) {
375*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(try_item, GetTryItem(successor, try_block_info));
376*795d594fSAndroid Build Coastguard Worker continue;
377*795d594fSAndroid Build Coastguard Worker }
378*795d594fSAndroid Build Coastguard Worker
379*795d594fSAndroid Build Coastguard Worker // Insert TryBoundary and link to catch blocks.
380*795d594fSAndroid Build Coastguard Worker HTryBoundary* try_exit =
381*795d594fSAndroid Build Coastguard Worker new (allocator_) HTryBoundary(HTryBoundary::BoundaryKind::kExit, successor->GetDexPc());
382*795d594fSAndroid Build Coastguard Worker graph_->SplitEdge(try_block, successor)->AddInstruction(try_exit);
383*795d594fSAndroid Build Coastguard Worker LinkToCatchBlocks(try_exit, code_item_accessor_, try_item, catch_blocks);
384*795d594fSAndroid Build Coastguard Worker }
385*795d594fSAndroid Build Coastguard Worker }
386*795d594fSAndroid Build Coastguard Worker }
387*795d594fSAndroid Build Coastguard Worker
InsertSynthesizedLoopsForOsr()388*795d594fSAndroid Build Coastguard Worker void HBasicBlockBuilder::InsertSynthesizedLoopsForOsr() {
389*795d594fSAndroid Build Coastguard Worker ArenaSet<uint32_t> targets(allocator_->Adapter(kArenaAllocGraphBuilder));
390*795d594fSAndroid Build Coastguard Worker // Collect basic blocks that are targets of a negative branch.
391*795d594fSAndroid Build Coastguard Worker for (const DexInstructionPcPair& pair : code_item_accessor_) {
392*795d594fSAndroid Build Coastguard Worker const uint32_t dex_pc = pair.DexPc();
393*795d594fSAndroid Build Coastguard Worker const Instruction& instruction = pair.Inst();
394*795d594fSAndroid Build Coastguard Worker if (instruction.IsBranch()) {
395*795d594fSAndroid Build Coastguard Worker uint32_t target_dex_pc = dex_pc + instruction.GetTargetOffset();
396*795d594fSAndroid Build Coastguard Worker if (target_dex_pc < dex_pc) {
397*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = GetBlockAt(target_dex_pc);
398*795d594fSAndroid Build Coastguard Worker CHECK_NE(kNoDexPc, block->GetDexPc());
399*795d594fSAndroid Build Coastguard Worker targets.insert(block->GetBlockId());
400*795d594fSAndroid Build Coastguard Worker }
401*795d594fSAndroid Build Coastguard Worker } else if (instruction.IsSwitch()) {
402*795d594fSAndroid Build Coastguard Worker DexSwitchTable table(instruction, dex_pc);
403*795d594fSAndroid Build Coastguard Worker for (DexSwitchTableIterator s_it(table); !s_it.Done(); s_it.Advance()) {
404*795d594fSAndroid Build Coastguard Worker uint32_t target_dex_pc = dex_pc + s_it.CurrentTargetOffset();
405*795d594fSAndroid Build Coastguard Worker if (target_dex_pc < dex_pc) {
406*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = GetBlockAt(target_dex_pc);
407*795d594fSAndroid Build Coastguard Worker CHECK_NE(kNoDexPc, block->GetDexPc());
408*795d594fSAndroid Build Coastguard Worker targets.insert(block->GetBlockId());
409*795d594fSAndroid Build Coastguard Worker }
410*795d594fSAndroid Build Coastguard Worker }
411*795d594fSAndroid Build Coastguard Worker }
412*795d594fSAndroid Build Coastguard Worker }
413*795d594fSAndroid Build Coastguard Worker
414*795d594fSAndroid Build Coastguard Worker // Insert synthesized loops before the collected blocks.
415*795d594fSAndroid Build Coastguard Worker for (uint32_t block_id : targets) {
416*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = graph_->GetBlocks()[block_id];
417*795d594fSAndroid Build Coastguard Worker HBasicBlock* loop_block = new (allocator_) HBasicBlock(graph_, block->GetDexPc());
418*795d594fSAndroid Build Coastguard Worker graph_->AddBlock(loop_block);
419*795d594fSAndroid Build Coastguard Worker while (!block->GetPredecessors().empty()) {
420*795d594fSAndroid Build Coastguard Worker block->GetPredecessors()[0]->ReplaceSuccessor(block, loop_block);
421*795d594fSAndroid Build Coastguard Worker }
422*795d594fSAndroid Build Coastguard Worker loop_block->AddSuccessor(loop_block);
423*795d594fSAndroid Build Coastguard Worker loop_block->AddSuccessor(block);
424*795d594fSAndroid Build Coastguard Worker // We loop on false - we know this won't be optimized later on as the loop
425*795d594fSAndroid Build Coastguard Worker // is marked irreducible, which disables loop optimizations.
426*795d594fSAndroid Build Coastguard Worker loop_block->AddInstruction(new (allocator_) HIf(graph_->GetIntConstant(0), kNoDexPc));
427*795d594fSAndroid Build Coastguard Worker }
428*795d594fSAndroid Build Coastguard Worker }
429*795d594fSAndroid Build Coastguard Worker
Build()430*795d594fSAndroid Build Coastguard Worker bool HBasicBlockBuilder::Build() {
431*795d594fSAndroid Build Coastguard Worker DCHECK(code_item_accessor_.HasCodeItem());
432*795d594fSAndroid Build Coastguard Worker DCHECK(graph_->GetBlocks().empty());
433*795d594fSAndroid Build Coastguard Worker
434*795d594fSAndroid Build Coastguard Worker graph_->SetEntryBlock(new (allocator_) HBasicBlock(graph_, kNoDexPc));
435*795d594fSAndroid Build Coastguard Worker graph_->SetExitBlock(new (allocator_) HBasicBlock(graph_, kNoDexPc));
436*795d594fSAndroid Build Coastguard Worker
437*795d594fSAndroid Build Coastguard Worker // TODO(dbrazdil): Do CreateBranchTargets and ConnectBasicBlocks in one pass.
438*795d594fSAndroid Build Coastguard Worker if (!CreateBranchTargets()) {
439*795d594fSAndroid Build Coastguard Worker return false;
440*795d594fSAndroid Build Coastguard Worker }
441*795d594fSAndroid Build Coastguard Worker
442*795d594fSAndroid Build Coastguard Worker ConnectBasicBlocks();
443*795d594fSAndroid Build Coastguard Worker InsertTryBoundaryBlocks();
444*795d594fSAndroid Build Coastguard Worker
445*795d594fSAndroid Build Coastguard Worker if (graph_->IsCompilingOsr()) {
446*795d594fSAndroid Build Coastguard Worker InsertSynthesizedLoopsForOsr();
447*795d594fSAndroid Build Coastguard Worker }
448*795d594fSAndroid Build Coastguard Worker
449*795d594fSAndroid Build Coastguard Worker return true;
450*795d594fSAndroid Build Coastguard Worker }
451*795d594fSAndroid Build Coastguard Worker
BuildIntrinsic()452*795d594fSAndroid Build Coastguard Worker void HBasicBlockBuilder::BuildIntrinsic() {
453*795d594fSAndroid Build Coastguard Worker DCHECK(!code_item_accessor_.HasCodeItem());
454*795d594fSAndroid Build Coastguard Worker DCHECK(graph_->GetBlocks().empty());
455*795d594fSAndroid Build Coastguard Worker
456*795d594fSAndroid Build Coastguard Worker // Create blocks.
457*795d594fSAndroid Build Coastguard Worker HBasicBlock* entry_block = new (allocator_) HBasicBlock(graph_, kNoDexPc);
458*795d594fSAndroid Build Coastguard Worker HBasicBlock* exit_block = new (allocator_) HBasicBlock(graph_, kNoDexPc);
459*795d594fSAndroid Build Coastguard Worker HBasicBlock* body = MaybeCreateBlockAt(/* semantic_dex_pc= */ kNoDexPc, /* store_dex_pc= */ 0u);
460*795d594fSAndroid Build Coastguard Worker
461*795d594fSAndroid Build Coastguard Worker // Add blocks to the graph.
462*795d594fSAndroid Build Coastguard Worker graph_->AddBlock(entry_block);
463*795d594fSAndroid Build Coastguard Worker graph_->AddBlock(body);
464*795d594fSAndroid Build Coastguard Worker graph_->AddBlock(exit_block);
465*795d594fSAndroid Build Coastguard Worker graph_->SetEntryBlock(entry_block);
466*795d594fSAndroid Build Coastguard Worker graph_->SetExitBlock(exit_block);
467*795d594fSAndroid Build Coastguard Worker
468*795d594fSAndroid Build Coastguard Worker // Connect blocks.
469*795d594fSAndroid Build Coastguard Worker entry_block->AddSuccessor(body);
470*795d594fSAndroid Build Coastguard Worker body->AddSuccessor(exit_block);
471*795d594fSAndroid Build Coastguard Worker }
472*795d594fSAndroid Build Coastguard Worker
473*795d594fSAndroid Build Coastguard Worker } // namespace art
474