1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "block_builder.h"
18 
19 #include "bytecode_utils.h"
20 
21 namespace art {
22 
MaybeCreateBlockAt(uint32_t dex_pc)23 HBasicBlock* HBasicBlockBuilder::MaybeCreateBlockAt(uint32_t dex_pc) {
24   return MaybeCreateBlockAt(dex_pc, dex_pc);
25 }
26 
MaybeCreateBlockAt(uint32_t semantic_dex_pc,uint32_t store_dex_pc)27 HBasicBlock* HBasicBlockBuilder::MaybeCreateBlockAt(uint32_t semantic_dex_pc,
28                                                     uint32_t store_dex_pc) {
29   HBasicBlock* block = branch_targets_[store_dex_pc];
30   if (block == nullptr) {
31     block = new (arena_) HBasicBlock(graph_, semantic_dex_pc);
32     branch_targets_[store_dex_pc] = block;
33   }
34   DCHECK_EQ(block->GetDexPc(), semantic_dex_pc);
35   return block;
36 }
37 
CreateBranchTargets()38 bool HBasicBlockBuilder::CreateBranchTargets() {
39   // Create the first block for the dex instructions, single successor of the entry block.
40   MaybeCreateBlockAt(0u);
41 
42   if (code_item_.tries_size_ != 0) {
43     // Create branch targets at the start/end of the TryItem range. These are
44     // places where the program might fall through into/out of the a block and
45     // where TryBoundary instructions will be inserted later. Other edges which
46     // enter/exit the try blocks are a result of branches/switches.
47     for (size_t idx = 0; idx < code_item_.tries_size_; ++idx) {
48       const DexFile::TryItem* try_item = DexFile::GetTryItems(code_item_, idx);
49       uint32_t dex_pc_start = try_item->start_addr_;
50       uint32_t dex_pc_end = dex_pc_start + try_item->insn_count_;
51       MaybeCreateBlockAt(dex_pc_start);
52       if (dex_pc_end < code_item_.insns_size_in_code_units_) {
53         // TODO: Do not create block if the last instruction cannot fall through.
54         MaybeCreateBlockAt(dex_pc_end);
55       } else if (dex_pc_end == code_item_.insns_size_in_code_units_) {
56         // The TryItem spans until the very end of the CodeItem and therefore
57         // cannot have any code afterwards.
58       } else {
59         // The TryItem spans beyond the end of the CodeItem. This is invalid code.
60         return false;
61       }
62     }
63 
64     // Create branch targets for exception handlers.
65     const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(code_item_, 0);
66     uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
67     for (uint32_t idx = 0; idx < handlers_size; ++idx) {
68       CatchHandlerIterator iterator(handlers_ptr);
69       for (; iterator.HasNext(); iterator.Next()) {
70         MaybeCreateBlockAt(iterator.GetHandlerAddress());
71       }
72       handlers_ptr = iterator.EndDataPointer();
73     }
74   }
75 
76   // Iterate over all instructions and find branching instructions. Create blocks for
77   // the locations these instructions branch to.
78   for (CodeItemIterator it(code_item_); !it.Done(); it.Advance()) {
79     uint32_t dex_pc = it.CurrentDexPc();
80     const Instruction& instruction = it.CurrentInstruction();
81 
82     if (instruction.IsBranch()) {
83       number_of_branches_++;
84       MaybeCreateBlockAt(dex_pc + instruction.GetTargetOffset());
85     } else if (instruction.IsSwitch()) {
86       DexSwitchTable table(instruction, dex_pc);
87       for (DexSwitchTableIterator s_it(table); !s_it.Done(); s_it.Advance()) {
88         MaybeCreateBlockAt(dex_pc + s_it.CurrentTargetOffset());
89 
90         // Create N-1 blocks where we will insert comparisons of the input value
91         // against the Switch's case keys.
92         if (table.ShouldBuildDecisionTree() && !s_it.IsLast()) {
93           // Store the block under dex_pc of the current key at the switch data
94           // instruction for uniqueness but give it the dex_pc of the SWITCH
95           // instruction which it semantically belongs to.
96           MaybeCreateBlockAt(dex_pc, s_it.GetDexPcForCurrentIndex());
97         }
98       }
99     } else if (instruction.Opcode() == Instruction::MOVE_EXCEPTION) {
100       // End the basic block after MOVE_EXCEPTION. This simplifies the later
101       // stage of TryBoundary-block insertion.
102     } else {
103       continue;
104     }
105 
106     if (instruction.CanFlowThrough()) {
107       if (it.IsLast()) {
108         // In the normal case we should never hit this but someone can artificially forge a dex
109         // file to fall-through out the method code. In this case we bail out compilation.
110         return false;
111       } else {
112         MaybeCreateBlockAt(dex_pc + it.CurrentInstruction().SizeInCodeUnits());
113       }
114     }
115   }
116 
117   return true;
118 }
119 
ConnectBasicBlocks()120 void HBasicBlockBuilder::ConnectBasicBlocks() {
121   HBasicBlock* block = graph_->GetEntryBlock();
122   graph_->AddBlock(block);
123 
124   bool is_throwing_block = false;
125   for (CodeItemIterator it(code_item_); !it.Done(); it.Advance()) {
126     uint32_t dex_pc = it.CurrentDexPc();
127 
128     // Check if this dex_pc address starts a new basic block.
129     HBasicBlock* next_block = GetBlockAt(dex_pc);
130     if (next_block != nullptr) {
131       if (block != nullptr) {
132         // Last instruction did not end its basic block but a new one starts here.
133         // It must have been a block falling through into the next one.
134         block->AddSuccessor(next_block);
135       }
136       block = next_block;
137       is_throwing_block = false;
138       graph_->AddBlock(block);
139     }
140 
141     if (block == nullptr) {
142       // Ignore dead code.
143       continue;
144     }
145 
146     const Instruction& instruction = it.CurrentInstruction();
147 
148     if (!is_throwing_block && IsThrowingDexInstruction(instruction)) {
149       DCHECK(!ContainsElement(throwing_blocks_, block));
150       is_throwing_block = true;
151       throwing_blocks_.push_back(block);
152     }
153 
154     if (instruction.IsBranch()) {
155       uint32_t target_dex_pc = dex_pc + instruction.GetTargetOffset();
156       block->AddSuccessor(GetBlockAt(target_dex_pc));
157     } else if (instruction.IsReturn() || (instruction.Opcode() == Instruction::THROW)) {
158       block->AddSuccessor(graph_->GetExitBlock());
159     } else if (instruction.IsSwitch()) {
160       DexSwitchTable table(instruction, dex_pc);
161       for (DexSwitchTableIterator s_it(table); !s_it.Done(); s_it.Advance()) {
162         uint32_t target_dex_pc = dex_pc + s_it.CurrentTargetOffset();
163         block->AddSuccessor(GetBlockAt(target_dex_pc));
164 
165         if (table.ShouldBuildDecisionTree() && !s_it.IsLast()) {
166           uint32_t next_case_dex_pc = s_it.GetDexPcForCurrentIndex();
167           HBasicBlock* next_case_block = GetBlockAt(next_case_dex_pc);
168           block->AddSuccessor(next_case_block);
169           block = next_case_block;
170           graph_->AddBlock(block);
171         }
172       }
173     } else {
174       // Remaining code only applies to instructions which end their basic block.
175       continue;
176     }
177 
178     if (instruction.CanFlowThrough()) {
179       uint32_t next_dex_pc = dex_pc + instruction.SizeInCodeUnits();
180       block->AddSuccessor(GetBlockAt(next_dex_pc));
181     }
182 
183     // The basic block ends here. Do not add any more instructions.
184     block = nullptr;
185   }
186 
187   graph_->AddBlock(graph_->GetExitBlock());
188 }
189 
190 // Returns the TryItem stored for `block` or nullptr if there is no info for it.
GetTryItem(HBasicBlock * block,const ArenaSafeMap<uint32_t,const DexFile::TryItem * > & try_block_info)191 static const DexFile::TryItem* GetTryItem(
192     HBasicBlock* block,
193     const ArenaSafeMap<uint32_t, const DexFile::TryItem*>& try_block_info) {
194   auto iterator = try_block_info.find(block->GetBlockId());
195   return (iterator == try_block_info.end()) ? nullptr : iterator->second;
196 }
197 
198 // Iterates over the exception handlers of `try_item`, finds the corresponding
199 // catch blocks and makes them successors of `try_boundary`. The order of
200 // successors matches the order in which runtime exception delivery searches
201 // for a handler.
LinkToCatchBlocks(HTryBoundary * try_boundary,const DexFile::CodeItem & code_item,const DexFile::TryItem * try_item,const ArenaSafeMap<uint32_t,HBasicBlock * > & catch_blocks)202 static void LinkToCatchBlocks(HTryBoundary* try_boundary,
203                               const DexFile::CodeItem& code_item,
204                               const DexFile::TryItem* try_item,
205                               const ArenaSafeMap<uint32_t, HBasicBlock*>& catch_blocks) {
206   for (CatchHandlerIterator it(code_item, *try_item); it.HasNext(); it.Next()) {
207     try_boundary->AddExceptionHandler(catch_blocks.Get(it.GetHandlerAddress()));
208   }
209 }
210 
MightHaveLiveNormalPredecessors(HBasicBlock * catch_block)211 bool HBasicBlockBuilder::MightHaveLiveNormalPredecessors(HBasicBlock* catch_block) {
212   if (kIsDebugBuild) {
213     DCHECK_NE(catch_block->GetDexPc(), kNoDexPc) << "Should not be called on synthetic blocks";
214     DCHECK(!graph_->GetEntryBlock()->GetSuccessors().empty())
215         << "Basic blocks must have been created and connected";
216     for (HBasicBlock* predecessor : catch_block->GetPredecessors()) {
217       DCHECK(!predecessor->IsSingleTryBoundary())
218           << "TryBoundary blocks must not have not been created yet";
219     }
220   }
221 
222   const Instruction& first = GetDexInstructionAt(code_item_, catch_block->GetDexPc());
223   if (first.Opcode() == Instruction::MOVE_EXCEPTION) {
224     // Verifier guarantees that if a catch block begins with MOVE_EXCEPTION then
225     // it has no live normal predecessors.
226     return false;
227   } else if (catch_block->GetPredecessors().empty()) {
228     // Normal control-flow edges have already been created. Since block's list of
229     // predecessors is empty, it cannot have any live or dead normal predecessors.
230     return false;
231   }
232 
233   // The catch block has normal predecessors but we do not know which are live
234   // and which will be removed during the initial DCE. Return `true` to signal
235   // that it may have live normal predecessors.
236   return true;
237 }
238 
InsertTryBoundaryBlocks()239 void HBasicBlockBuilder::InsertTryBoundaryBlocks() {
240   if (code_item_.tries_size_ == 0) {
241     return;
242   }
243 
244   // Keep a map of all try blocks and their respective TryItems. We do not use
245   // the block's pointer but rather its id to ensure deterministic iteration.
246   ArenaSafeMap<uint32_t, const DexFile::TryItem*> try_block_info(
247       std::less<uint32_t>(), arena_->Adapter(kArenaAllocGraphBuilder));
248 
249   // Obtain TryItem information for blocks with throwing instructions, and split
250   // blocks which are both try & catch to simplify the graph.
251   for (HBasicBlock* block : graph_->GetBlocks()) {
252     if (block->GetDexPc() == kNoDexPc) {
253       continue;
254     }
255 
256     // Do not bother creating exceptional edges for try blocks which have no
257     // throwing instructions. In that case we simply assume that the block is
258     // not covered by a TryItem. This prevents us from creating a throw-catch
259     // loop for synchronized blocks.
260     if (ContainsElement(throwing_blocks_, block)) {
261       // Try to find a TryItem covering the block.
262       const int32_t try_item_idx = DexFile::FindTryItem(code_item_, block->GetDexPc());
263       if (try_item_idx != -1) {
264         // Block throwing and in a TryItem. Store the try block information.
265         try_block_info.Put(block->GetBlockId(), DexFile::GetTryItems(code_item_, try_item_idx));
266       }
267     }
268   }
269 
270   // Map from a handler dex_pc to the corresponding catch block.
271   ArenaSafeMap<uint32_t, HBasicBlock*> catch_blocks(
272       std::less<uint32_t>(), arena_->Adapter(kArenaAllocGraphBuilder));
273 
274   // Iterate over catch blocks, create artifical landing pads if necessary to
275   // simplify the CFG, and set metadata.
276   const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(code_item_, 0);
277   uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
278   for (uint32_t idx = 0; idx < handlers_size; ++idx) {
279     CatchHandlerIterator iterator(handlers_ptr);
280     for (; iterator.HasNext(); iterator.Next()) {
281       uint32_t address = iterator.GetHandlerAddress();
282       if (catch_blocks.find(address) != catch_blocks.end()) {
283         // Catch block already processed.
284         continue;
285       }
286 
287       // Check if we should create an artifical landing pad for the catch block.
288       // We create one if the catch block is also a try block because we do not
289       // have a strategy for inserting TryBoundaries on exceptional edges.
290       // We also create one if the block might have normal predecessors so as to
291       // simplify register allocation.
292       HBasicBlock* catch_block = GetBlockAt(address);
293       bool is_try_block = (try_block_info.find(catch_block->GetBlockId()) != try_block_info.end());
294       if (is_try_block || MightHaveLiveNormalPredecessors(catch_block)) {
295         HBasicBlock* new_catch_block = new (arena_) HBasicBlock(graph_, address);
296         new_catch_block->AddInstruction(new (arena_) HGoto(address));
297         new_catch_block->AddSuccessor(catch_block);
298         graph_->AddBlock(new_catch_block);
299         catch_block = new_catch_block;
300       }
301 
302       catch_blocks.Put(address, catch_block);
303       catch_block->SetTryCatchInformation(
304         new (arena_) TryCatchInformation(iterator.GetHandlerTypeIndex(), *dex_file_));
305     }
306     handlers_ptr = iterator.EndDataPointer();
307   }
308 
309   // Do a pass over the try blocks and insert entering TryBoundaries where at
310   // least one predecessor is not covered by the same TryItem as the try block.
311   // We do not split each edge separately, but rather create one boundary block
312   // that all predecessors are relinked to. This preserves loop headers (b/23895756).
313   for (auto entry : try_block_info) {
314     HBasicBlock* try_block = graph_->GetBlocks()[entry.first];
315     for (HBasicBlock* predecessor : try_block->GetPredecessors()) {
316       if (GetTryItem(predecessor, try_block_info) != entry.second) {
317         // Found a predecessor not covered by the same TryItem. Insert entering
318         // boundary block.
319         HTryBoundary* try_entry =
320             new (arena_) HTryBoundary(HTryBoundary::BoundaryKind::kEntry, try_block->GetDexPc());
321         try_block->CreateImmediateDominator()->AddInstruction(try_entry);
322         LinkToCatchBlocks(try_entry, code_item_, entry.second, catch_blocks);
323         break;
324       }
325     }
326   }
327 
328   // Do a second pass over the try blocks and insert exit TryBoundaries where
329   // the successor is not in the same TryItem.
330   for (auto entry : try_block_info) {
331     HBasicBlock* try_block = graph_->GetBlocks()[entry.first];
332     // NOTE: Do not use iterators because SplitEdge would invalidate them.
333     for (size_t i = 0, e = try_block->GetSuccessors().size(); i < e; ++i) {
334       HBasicBlock* successor = try_block->GetSuccessors()[i];
335 
336       // If the successor is a try block, all of its predecessors must be
337       // covered by the same TryItem. Otherwise the previous pass would have
338       // created a non-throwing boundary block.
339       if (GetTryItem(successor, try_block_info) != nullptr) {
340         DCHECK_EQ(entry.second, GetTryItem(successor, try_block_info));
341         continue;
342       }
343 
344       // Insert TryBoundary and link to catch blocks.
345       HTryBoundary* try_exit =
346           new (arena_) HTryBoundary(HTryBoundary::BoundaryKind::kExit, successor->GetDexPc());
347       graph_->SplitEdge(try_block, successor)->AddInstruction(try_exit);
348       LinkToCatchBlocks(try_exit, code_item_, entry.second, catch_blocks);
349     }
350   }
351 }
352 
Build()353 bool HBasicBlockBuilder::Build() {
354   DCHECK(graph_->GetBlocks().empty());
355 
356   graph_->SetEntryBlock(new (arena_) HBasicBlock(graph_, kNoDexPc));
357   graph_->SetExitBlock(new (arena_) HBasicBlock(graph_, kNoDexPc));
358 
359   // TODO(dbrazdil): Do CreateBranchTargets and ConnectBasicBlocks in one pass.
360   if (!CreateBranchTargets()) {
361     return false;
362   }
363 
364   ConnectBasicBlocks();
365   InsertTryBoundaryBlocks();
366 
367   return true;
368 }
369 
370 }  // namespace art
371