xref: /aosp_15_r20/art/compiler/optimizing/block_builder.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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