summaryrefslogtreecommitdiff
path: root/compiler/optimizing/builder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/builder.cc')
-rw-r--r--compiler/optimizing/builder.cc215
1 files changed, 119 insertions, 96 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index bde2c70fc6..8551382b07 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -306,114 +306,138 @@ void HGraphBuilder::CreateBlocksForTryCatch(const DexFile::CodeItem& code_item)
}
}
+void HGraphBuilder::SplitTryBoundaryEdge(HBasicBlock* predecessor,
+ HBasicBlock* successor,
+ HTryBoundary::BoundaryKind kind,
+ const DexFile::CodeItem& code_item,
+ const DexFile::TryItem& try_item) {
+ // Split the edge with a single TryBoundary instruction.
+ HTryBoundary* try_boundary = new (arena_) HTryBoundary(kind);
+ HBasicBlock* try_entry_block = graph_->SplitEdge(predecessor, successor);
+ try_entry_block->AddInstruction(try_boundary);
+
+ // Link the TryBoundary to the handlers of `try_item`.
+ for (CatchHandlerIterator it(code_item, try_item); it.HasNext(); it.Next()) {
+ try_boundary->AddExceptionHandler(FindBlockStartingAt(it.GetHandlerAddress()));
+ }
+}
+
void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) {
if (code_item.tries_size_ == 0) {
return;
}
- for (size_t idx = 0; idx < code_item.tries_size_; ++idx) {
- const DexFile::TryItem* try_item = DexFile::GetTryItems(code_item, idx);
- uint32_t try_start = try_item->start_addr_;
- uint32_t try_end = try_start + try_item->insn_count_;
-
- // Iterate over all blocks in the dex pc range of the 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.
- for (uint32_t inner_pc = try_start; inner_pc < try_end; ++inner_pc) {
- HBasicBlock* try_block = FindBlockStartingAt(inner_pc);
- if (try_block == nullptr) {
- continue;
+ // 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) {
+ 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) {
+ 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;
}
-
- // Find predecessors which are not covered by the same TryItem range. Such
- // edges enter the try block and will have a TryBoundary inserted.
+ 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);
- HTryBoundary* try_boundary = nullptr;
if (predecessor->IsSingleTryBoundary()) {
- try_boundary = predecessor->GetLastInstruction()->AsTryBoundary();
- if (try_boundary->GetNormalFlowSuccessor() == try_block
- && try_block->IsFirstIndexOfPredecessor(predecessor, i)) {
- // The edge was already split because of an exit from a neighbouring
- // TryItem and `predecessor` is the block with a TryBoundary created
- // between the two original blocks. We do not split the edge again.
+ // 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));
- DCHECK(try_boundary->IsTryExit());
- DCHECK(!try_boundary->IsTryEntry());
- try_boundary->SetIsTryEntry();
- } else {
- // This is an edge between a previously created TryBoundary and its
- // handler. We skip it because it is exceptional flow.
- DCHECK(try_block->IsCatchBlock());
- DCHECK(try_boundary->HasExceptionHandler(try_block));
- continue;
}
} 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 either `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 `predecessor` may add its
- // own exception handlers later.
- try_boundary = new (arena_) HTryBoundary(/* is_entry */ true, /* is_exit */ false);
- HBasicBlock* try_entry_block = graph_->SplitEdge(predecessor, try_block);
- try_entry_block->AddInstruction(try_boundary);
+ // 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;
}
- DCHECK(try_boundary != nullptr);
-
- // Link the TryBoundary block to the handlers of this TryItem.
- for (CatchHandlerIterator it(code_item, *try_item); it.HasNext(); it.Next()) {
- try_boundary->AddExceptionHandler(FindBlockStartingAt(it.GetHandlerAddress()));
- }
+ SplitTryBoundaryEdge(predecessor, try_block, HTryBoundary::kEntry, code_item, try_item);
}
+ }
- // Find successors which are not covered by the same TryItem range. Such
- // edges exit the try block and will have a TryBoundary inserted.
- for (size_t i = 0; i < try_block->GetSuccessors().Size(); ++i) {
- HBasicBlock* successor = try_block->GetSuccessors().Get(i);
- HTryBoundary* try_boundary = nullptr;
- if (successor->IsSingleTryBoundary()) {
- // The edge was already split because of an entry into a neighbouring
- // TryItem. We do not split the edge again.
- try_boundary = successor->GetLastInstruction()->AsTryBoundary();
+ // Find successors which are not covered by the same TryItem range. Such
+ // edges exit the try block and will have a TryBoundary inserted.
+ for (size_t i = 0; i < try_block->GetSuccessors().Size(); ++i) {
+ HBasicBlock* successor = try_block->GetSuccessors().Get(i);
+ if (successor->IsCatchBlock()) {
+ // A catch block is always considered an entry point into its TryItem.
+ // We therefore assume this is an exit point, regardless of whether
+ // the catch block is in a different TryItem or not.
+ } else if (successor->IsSingleTryBoundary()) {
+ // The edge was already split because of an entry into a neighbouring
+ // TryItem. We split it again and insert an exit.
+ if (kIsDebugBuild) {
+ HTryBoundary* last_insn = successor->GetLastInstruction()->AsTryBoundary();
DCHECK_EQ(try_block, successor->GetSinglePredecessor());
- DCHECK(try_boundary->IsTryEntry());
- DCHECK(!try_boundary->IsTryExit());
- DCHECK(!IsBlockInPcRange(try_boundary->GetNormalFlowSuccessor(), try_start, try_end));
- try_boundary->SetIsTryExit();
- } else if (!IsBlockInPcRange(successor, try_start, try_end)) {
- // 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
- // block first. We split the edge and `successor` may add its own
- // exception handlers later.
- HInstruction* last_instruction = try_block->GetLastInstruction();
- if (last_instruction->IsReturn() || last_instruction->IsReturnVoid()) {
- DCHECK_EQ(successor, exit_block_);
- // Control flow exits the try block with a Return(Void). Because
- // splitting the edge would invalidate the invariant that Return
- // always jumps to Exit, we move the Return outside the try block.
- HBasicBlock* return_block = try_block->SplitBefore(last_instruction);
- graph_->AddBlock(return_block);
- successor = return_block;
- }
- try_boundary = new (arena_) HTryBoundary(/* is_entry */ false, /* is_exit */ true);
- HBasicBlock* try_exit_block = graph_->SplitEdge(try_block, successor);
- try_exit_block->AddInstruction(try_boundary);
- } else {
- // Not an edge on the boundary of the try block.
- continue;
+ DCHECK(last_insn->IsEntry());
+ DCHECK(!IsBlockInPcRange(last_insn->GetNormalFlowSuccessor(), try_start, try_end));
}
- DCHECK(try_boundary != nullptr);
-
- // Link the TryBoundary block to the handlers of this TryItem.
- for (CatchHandlerIterator it(code_item, *try_item); it.HasNext(); it.Next()) {
- try_boundary->AddExceptionHandler(FindBlockStartingAt(it.GetHandlerAddress()));
+ } else if (!IsBlockInPcRange(successor, try_start, try_end)) {
+ // 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
+ // block first. We split the edge and insert an exit.
+ HInstruction* last_instruction = try_block->GetLastInstruction();
+ if (last_instruction->IsReturn() || last_instruction->IsReturnVoid()) {
+ DCHECK_EQ(successor, exit_block_);
+ // Control flow exits the try block with a Return(Void). Because
+ // splitting the edge would invalidate the invariant that Return
+ // always jumps to Exit, we move the Return outside the try block.
+ successor = try_block->SplitBefore(last_instruction);
}
+ } else {
+ // Not an edge on the boundary of the try block.
+ continue;
}
+ SplitTryBoundaryEdge(try_block, successor, HTryBoundary::kExit, code_item, try_item);
}
}
}
@@ -548,11 +572,10 @@ bool HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr,
uint32_t target = dex_pc + table.GetEntryAt(i + offset);
FindOrCreateBlockStartingAt(target);
- // The next case gets its own block.
- if (i < num_entries) {
- block = new (arena_) HBasicBlock(graph_, target);
- branch_targets_.Put(table.GetDexPcForIndex(i), block);
- }
+ // Create a block for the switch-case logic. The block gets the dex_pc
+ // of the SWITCH instruction because it is part of its semantics.
+ block = new (arena_) HBasicBlock(graph_, dex_pc);
+ branch_targets_.Put(table.GetDexPcForIndex(i), block);
}
// Fall-through. Add a block if there is more code afterwards.
@@ -634,7 +657,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);
@@ -2288,27 +2311,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;
}