diff options
Diffstat (limited to 'compiler/optimizing/builder.cc')
-rw-r--r-- | compiler/optimizing/builder.cc | 172 |
1 files changed, 95 insertions, 77 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 732630d76b..fe52c44306 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -259,14 +259,20 @@ bool HGraphBuilder::SkipCompilation(const DexFile::CodeItem& code_item, return false; } -bool HGraphBuilder::IsBlockInPcRange(HBasicBlock* block, - uint32_t dex_pc_start, - uint32_t dex_pc_end) { - uint32_t dex_pc = block->GetDexPc(); - return block != entry_block_ - && block != exit_block_ - && dex_pc >= dex_pc_start - && dex_pc < dex_pc_end; +static const DexFile::TryItem* GetTryItem(HBasicBlock* block, + const DexFile::CodeItem& code_item, + const ArenaBitVector& can_block_throw) { + DCHECK(!block->IsSingleTryBoundary()); + + // Block does not contain throwing instructions. Even if it is covered by + // a TryItem, we will consider it not in a try block. + if (!can_block_throw.IsBitSet(block->GetBlockId())) { + return nullptr; + } + + // Instructions in the block may throw. Find a TryItem covering this block. + int32_t try_item_idx = DexFile::FindTryItem(code_item, block->GetDexPc()); + return (try_item_idx == -1) ? nullptr : DexFile::GetTryItems(code_item, try_item_idx); } void HGraphBuilder::CreateBlocksForTryCatch(const DexFile::CodeItem& code_item) { @@ -327,80 +333,90 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) return; } + // Bit vector stores information on which blocks contain throwing instructions. + // Must be expandable because catch blocks may be split into two. + ArenaBitVector can_block_throw(arena_, graph_->GetBlocks().Size(), /* expandable */ true); + + // Scan blocks and mark those which contain throwing instructions. + for (size_t block_id = 0, e = graph_->GetBlocks().Size(); block_id < e; ++block_id) { + HBasicBlock* block = graph_->GetBlocks().Get(block_id); + bool can_throw = false; + for (HInstructionIterator insn(block->GetInstructions()); !insn.Done(); insn.Advance()) { + if (insn.Current()->CanThrow()) { + can_throw = true; + break; + } + } + + if (can_throw) { + if (block->IsCatchBlock()) { + // Catch blocks are always considered an entry point into the TryItem in + // order to avoid splitting exceptional edges. We split the block after + // the move-exception (if present) and mark the first part non-throwing. + // Later on, a TryBoundary will be inserted between the two blocks. + HInstruction* first_insn = block->GetFirstInstruction(); + if (first_insn->IsLoadException()) { + // Catch block starts with a LoadException. Split the block after the + // StoreLocal that must come after the load. + DCHECK(first_insn->GetNext()->IsStoreLocal()); + block = block->SplitBefore(first_insn->GetNext()->GetNext()); + } else { + // Catch block does not load the exception. Split at the beginning to + // create an empty catch block. + block = block->SplitBefore(first_insn); + } + } + can_block_throw.SetBit(block->GetBlockId()); + } + } + // Iterate over all blocks, find those covered by some TryItem and: // (a) split edges which enter/exit the try range, // (b) create TryBoundary instructions in the new blocks, // (c) link the new blocks to corresponding exception handlers. // We cannot iterate only over blocks in `branch_targets_` because switch-case // blocks share the same dex_pc. - for (size_t block_id = 1, e = graph_->GetBlocks().Size(); block_id < e; ++block_id) { + for (size_t block_id = 0, e = graph_->GetBlocks().Size(); block_id < e; ++block_id) { HBasicBlock* try_block = graph_->GetBlocks().Get(block_id); - // Iteration starts from 1 to skip the entry block. - DCHECK_NE(try_block, entry_block_); - // Exit block has not yet been added to the graph at this point. - DCHECK_NE(try_block, exit_block_); // TryBoundary blocks are added at the end of the list and not iterated over. DCHECK(!try_block->IsSingleTryBoundary()); // Find the TryItem for this block. - int32_t try_item_idx = DexFile::FindTryItem(code_item, try_block->GetDexPc()); - if (try_item_idx == -1) { + const DexFile::TryItem* try_item = GetTryItem(try_block, code_item, can_block_throw); + if (try_item == nullptr) { continue; } - const DexFile::TryItem& try_item = *DexFile::GetTryItems(code_item, try_item_idx); - uint32_t try_start = try_item.start_addr_; - uint32_t try_end = try_start + try_item.insn_count_; - - if (try_block->IsCatchBlock()) { - // Catch blocks are always considered an entry point into the TryItem in - // order to avoid splitting exceptional edges (they might not have been - // created yet). We separate the move-exception (if present) from the - // rest of the block and insert a TryBoundary after it, creating a - // landing pad for the exceptional edges. - HInstruction* first_insn = try_block->GetFirstInstruction(); - HInstruction* split_position = nullptr; - if (first_insn->IsLoadException()) { - // Catch block starts with a LoadException. Split the block after the - // StoreLocal that must come after the load. - DCHECK(first_insn->GetNext()->IsStoreLocal()); - split_position = first_insn->GetNext()->GetNext(); - } else { - // Catch block does not obtain the exception. Split at the beginning - // to create an empty catch block. - split_position = first_insn; - } - DCHECK(split_position != nullptr); - HBasicBlock* catch_block = try_block; - try_block = catch_block->SplitBefore(split_position); - SplitTryBoundaryEdge(catch_block, try_block, HTryBoundary::kEntry, code_item, try_item); - } else { - // For non-catch blocks, find predecessors which are not covered by the - // same TryItem range. Such edges enter the try block and will have - // a TryBoundary inserted. - for (size_t i = 0; i < try_block->GetPredecessors().Size(); ++i) { - HBasicBlock* predecessor = try_block->GetPredecessors().Get(i); - if (predecessor->IsSingleTryBoundary()) { - // The edge was already split because of an exit from a neighbouring - // TryItem. We split it again and insert an entry point. - if (kIsDebugBuild) { - HTryBoundary* last_insn = predecessor->GetLastInstruction()->AsTryBoundary(); - DCHECK(!last_insn->IsEntry()); - DCHECK_EQ(last_insn->GetNormalFlowSuccessor(), try_block); - DCHECK(try_block->IsFirstIndexOfPredecessor(predecessor, i)); - DCHECK(!IsBlockInPcRange(predecessor->GetSinglePredecessor(), try_start, try_end)); - } - } else if (!IsBlockInPcRange(predecessor, try_start, try_end)) { - // This is an entry point into the TryItem and the edge has not been - // split yet. That means that `predecessor` is not in a TryItem, or - // it is in a different TryItem and we happened to iterate over this - // block first. We split the edge and insert an entry point. - } else { - // Not an edge on the boundary of the try block. - continue; + + // Catch blocks were split earlier and cannot throw. + DCHECK(!try_block->IsCatchBlock()); + + // Find predecessors which are not covered by the same TryItem range. Such + // edges enter the try block and will have a TryBoundary inserted. + for (size_t i = 0; i < try_block->GetPredecessors().Size(); ++i) { + HBasicBlock* predecessor = try_block->GetPredecessors().Get(i); + if (predecessor->IsSingleTryBoundary()) { + // The edge was already split because of an exit from a neighbouring + // TryItem. We split it again and insert an entry point. + if (kIsDebugBuild) { + HTryBoundary* last_insn = predecessor->GetLastInstruction()->AsTryBoundary(); + const DexFile::TryItem* predecessor_try_item = + GetTryItem(predecessor->GetSinglePredecessor(), code_item, can_block_throw); + DCHECK(!last_insn->IsEntry()); + DCHECK_EQ(last_insn->GetNormalFlowSuccessor(), try_block); + DCHECK(try_block->IsFirstIndexOfPredecessor(predecessor, i)); + DCHECK_NE(try_item, predecessor_try_item); } - SplitTryBoundaryEdge(predecessor, try_block, HTryBoundary::kEntry, code_item, try_item); + } else if (GetTryItem(predecessor, code_item, can_block_throw) != try_item) { + // This is an entry point into the TryItem and the edge has not been + // split yet. That means that `predecessor` is not in a TryItem, or + // it is in a different TryItem and we happened to iterate over this + // block first. We split the edge and insert an entry point. + } else { + // Not an edge on the boundary of the try block. + continue; } + SplitTryBoundaryEdge(predecessor, try_block, HTryBoundary::kEntry, code_item, *try_item); } // Find successors which are not covered by the same TryItem range. Such @@ -416,11 +432,13 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) // TryItem. We split it again and insert an exit. if (kIsDebugBuild) { HTryBoundary* last_insn = successor->GetLastInstruction()->AsTryBoundary(); + const DexFile::TryItem* successor_try_item = + GetTryItem(last_insn->GetNormalFlowSuccessor(), code_item, can_block_throw); DCHECK_EQ(try_block, successor->GetSinglePredecessor()); DCHECK(last_insn->IsEntry()); - DCHECK(!IsBlockInPcRange(last_insn->GetNormalFlowSuccessor(), try_start, try_end)); + DCHECK_NE(try_item, successor_try_item); } - } else if (!IsBlockInPcRange(successor, try_start, try_end)) { + } else if (GetTryItem(successor, code_item, can_block_throw) != try_item) { // This is an exit out of the TryItem and the edge has not been split // yet. That means that either `successor` is not in a TryItem, or it // is in a different TryItem and we happened to iterate over this @@ -437,7 +455,7 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) // Not an edge on the boundary of the try block. continue; } - SplitTryBoundaryEdge(try_block, successor, HTryBoundary::kExit, code_item, try_item); + SplitTryBoundaryEdge(try_block, successor, HTryBoundary::kExit, code_item, *try_item); } } } @@ -496,14 +514,14 @@ bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { // Add the suspend check to the entry block. entry_block_->AddInstruction(new (arena_) HSuspendCheck(0)); entry_block_->AddInstruction(new (arena_) HGoto()); + // Add the exit block at the end. + graph_->AddBlock(exit_block_); // Iterate over blocks covered by TryItems and insert TryBoundaries at entry // and exit points. This requires all control-flow instructions and // non-exceptional edges to have been created. InsertTryBoundaryBlocks(code_item); - // Add the exit block at the end to give it the highest id. - graph_->AddBlock(exit_block_); return true; } @@ -657,7 +675,7 @@ void HGraphBuilder::Binop_23x_shift(const Instruction& instruction, void HGraphBuilder::Binop_23x_cmp(const Instruction& instruction, Primitive::Type type, - HCompare::Bias bias, + ComparisonBias bias, uint32_t dex_pc) { HInstruction* first = LoadLocal(instruction.VRegB(), type); HInstruction* second = LoadLocal(instruction.VRegC(), type); @@ -2311,27 +2329,27 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::CMP_LONG: { - Binop_23x_cmp(instruction, Primitive::kPrimLong, HCompare::kNoBias, dex_pc); + Binop_23x_cmp(instruction, Primitive::kPrimLong, kNoBias, dex_pc); break; } case Instruction::CMPG_FLOAT: { - Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kGtBias, dex_pc); + Binop_23x_cmp(instruction, Primitive::kPrimFloat, kGtBias, dex_pc); break; } case Instruction::CMPG_DOUBLE: { - Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kGtBias, dex_pc); + Binop_23x_cmp(instruction, Primitive::kPrimDouble, kGtBias, dex_pc); break; } case Instruction::CMPL_FLOAT: { - Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kLtBias, dex_pc); + Binop_23x_cmp(instruction, Primitive::kPrimFloat, kLtBias, dex_pc); break; } case Instruction::CMPL_DOUBLE: { - Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kLtBias, dex_pc); + Binop_23x_cmp(instruction, Primitive::kPrimDouble, kLtBias, dex_pc); break; } |