diff options
Diffstat (limited to 'compiler/optimizing/nodes.cc')
| -rw-r--r-- | compiler/optimizing/nodes.cc | 39 | 
1 files changed, 31 insertions, 8 deletions
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 68fb0acf7f..4d79b55771 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -366,7 +366,11 @@ void HGraph::ComputeTryBlockInformation() {      HBasicBlock* first_predecessor = block->GetPredecessors()[0];      DCHECK(!block->IsLoopHeader() || !block->GetLoopInformation()->IsBackEdge(*first_predecessor));      const HTryBoundary* try_entry = first_predecessor->ComputeTryEntryOfSuccessors(); -    if (try_entry != nullptr) { +    if (try_entry != nullptr && +        (block->GetTryCatchInformation() == nullptr || +         try_entry != &block->GetTryCatchInformation()->GetTryEntry())) { +      // We are either setting try block membership for the first time or it +      // has changed.        block->SetTryCatchInformation(new (arena_) TryCatchInformation(*try_entry));      }    } @@ -1372,13 +1376,30 @@ void HBasicBlock::DisconnectAndDelete() {    // instructions.    for (HBasicBlock* predecessor : predecessors_) {      HInstruction* last_instruction = predecessor->GetLastInstruction(); +    if (last_instruction->IsTryBoundary() && !IsCatchBlock()) { +      // This block is the only normal-flow successor of the TryBoundary which +      // makes `predecessor` dead. Since DCE removes blocks in post order, +      // exception handlers of this TryBoundary were already visited and any +      // remaining handlers therefore must be live. We remove `predecessor` from +      // their list of predecessors. +      DCHECK_EQ(last_instruction->AsTryBoundary()->GetNormalFlowSuccessor(), this); +      while (predecessor->GetSuccessors().size() > 1) { +        HBasicBlock* handler = predecessor->GetSuccessors()[1]; +        DCHECK(handler->IsCatchBlock()); +        predecessor->RemoveSuccessor(handler); +        handler->RemovePredecessor(predecessor); +      } +    } +      predecessor->RemoveSuccessor(this);      uint32_t num_pred_successors = predecessor->GetSuccessors().size();      if (num_pred_successors == 1u) {        // If we have one successor after removing one, then we must have -      // had an HIf or HPackedSwitch, as they have more than one successor. -      // Replace those with a HGoto. -      DCHECK(last_instruction->IsIf() || last_instruction->IsPackedSwitch()); +      // had an HIf, HPackedSwitch or HTryBoundary, as they have more than one +      // successor. Replace those with a HGoto. +      DCHECK(last_instruction->IsIf() || +             last_instruction->IsPackedSwitch() || +             (last_instruction->IsTryBoundary() && IsCatchBlock()));        predecessor->RemoveInstruction(last_instruction);        predecessor->AddInstruction(new (graph_->GetArena()) HGoto(last_instruction->GetDexPc()));      } else if (num_pred_successors == 0u) { @@ -1387,10 +1408,12 @@ void HBasicBlock::DisconnectAndDelete() {        // SSAChecker fails unless it is not removed during the pass too.        predecessor->RemoveInstruction(last_instruction);      } else { -      // There are multiple successors left.  This must come from a HPackedSwitch -      // and we are in the middle of removing the HPackedSwitch. Like above, leave -      // this alone, and the SSAChecker will fail if it is not removed as well. -      DCHECK(last_instruction->IsPackedSwitch()); +      // There are multiple successors left. The removed block might be a successor +      // of a PackedSwitch which will be completely removed (perhaps replaced with +      // a Goto), or we are deleting a catch block from a TryBoundary. In either +      // case, leave `last_instruction` as is for now. +      DCHECK(last_instruction->IsPackedSwitch() || +             (last_instruction->IsTryBoundary() && IsCatchBlock()));      }    }    predecessors_.clear();  |