diff options
Diffstat (limited to 'compiler/optimizing/nodes.cc')
| -rw-r--r-- | compiler/optimizing/nodes.cc | 166 | 
1 files changed, 121 insertions, 45 deletions
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index de3f2668b6..716888a269 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -362,7 +362,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));      }    } @@ -381,8 +385,9 @@ void HGraph::SimplifyCFG() {        // Only split normal-flow edges. We cannot split exceptional edges as they        // are synthesized (approximate real control flow), and we do not need to        // anyway. Moves that would be inserted there are performed by the runtime. -      for (size_t j = 0, e = block->NumberOfNormalSuccessors(); j < e; ++j) { -        HBasicBlock* successor = block->GetSuccessors()[j]; +      ArrayRef<HBasicBlock* const> normal_successors = block->GetNormalSuccessors(); +      for (size_t j = 0, e = normal_successors.size(); j < e; ++j) { +        HBasicBlock* successor = normal_successors[j];          DCHECK(!successor->IsCatchBlock());          if (successor == exit_block_) {            // Throw->TryBoundary->Exit. Special case which we do not want to split @@ -391,7 +396,11 @@ void HGraph::SimplifyCFG() {            DCHECK(block->GetSinglePredecessor()->GetLastInstruction()->IsThrow());          } else if (successor->GetPredecessors().size() > 1) {            SplitCriticalEdge(block, successor); -          --j; +          // SplitCriticalEdge could have invalidated the `normal_successors` +          // ArrayRef. We must re-acquire it. +          normal_successors = block->GetNormalSuccessors(); +          DCHECK_EQ(normal_successors[j]->GetSingleSuccessor(), successor); +          DCHECK_EQ(e, normal_successors.size());          }        }      } @@ -1086,6 +1095,8 @@ HConstant* HBinaryOperation::TryStaticEvaluation() const {      } else if (GetRight()->IsLongConstant()) {        return Evaluate(GetLeft()->AsLongConstant(), GetRight()->AsLongConstant());      } +  } else if (GetLeft()->IsNullConstant() && GetRight()->IsNullConstant()) { +    return Evaluate(GetLeft()->AsNullConstant(), GetRight()->AsNullConstant());    }    return nullptr;  } @@ -1325,17 +1336,38 @@ bool HBasicBlock::HasSinglePhi() const {    return !GetPhis().IsEmpty() && GetFirstPhi()->GetNext() == nullptr;  } +ArrayRef<HBasicBlock* const> HBasicBlock::GetNormalSuccessors() const { +  if (EndsWithTryBoundary()) { +    // The normal-flow successor of HTryBoundary is always stored at index zero. +    DCHECK_EQ(successors_[0], GetLastInstruction()->AsTryBoundary()->GetNormalFlowSuccessor()); +    return ArrayRef<HBasicBlock* const>(successors_).SubArray(0u, 1u); +  } else { +    // All successors of blocks not ending with TryBoundary are normal. +    return ArrayRef<HBasicBlock* const>(successors_); +  } +} + +ArrayRef<HBasicBlock* const> HBasicBlock::GetExceptionalSuccessors() const { +  if (EndsWithTryBoundary()) { +    return GetLastInstruction()->AsTryBoundary()->GetExceptionHandlers(); +  } else { +    // Blocks not ending with TryBoundary do not have exceptional successors. +    return ArrayRef<HBasicBlock* const>(); +  } +} +  bool HTryBoundary::HasSameExceptionHandlersAs(const HTryBoundary& other) const { -  if (GetBlock()->GetSuccessors().size() != other.GetBlock()->GetSuccessors().size()) { +  ArrayRef<HBasicBlock* const> handlers1 = GetExceptionHandlers(); +  ArrayRef<HBasicBlock* const> handlers2 = other.GetExceptionHandlers(); + +  size_t length = handlers1.size(); +  if (length != handlers2.size()) {      return false;    }    // Exception handlers need to be stored in the same order. -  for (HExceptionHandlerIterator it1(*this), it2(other); -       !it1.Done(); -       it1.Advance(), it2.Advance()) { -    DCHECK(!it2.Done()); -    if (it1.Current() != it2.Current()) { +  for (size_t i = 0; i < length; ++i) { +    if (handlers1[i] != handlers2[i]) {        return false;      }    } @@ -1388,7 +1420,7 @@ void HBasicBlock::DisconnectAndDelete() {    // iteration.    DCHECK(dominated_blocks_.empty()); -  // Remove the block from all loops it is included in. +  // (1) Remove the block from all loops it is included in.    for (HLoopInformationOutwardIterator it(*this); !it.Done(); it.Advance()) {      HLoopInformation* loop_info = it.Current();      loop_info->Remove(this); @@ -1400,17 +1432,34 @@ void HBasicBlock::DisconnectAndDelete() {      }    } -  // Disconnect the block from its predecessors and update their control-flow -  // instructions. +  // (2) Disconnect the block from its predecessors and update their +  //     control-flow 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) { @@ -1419,15 +1468,17 @@ 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(); -  // Disconnect the block from its successors and update their phis. +  // (3) Disconnect the block from its successors and update their phis.    for (HBasicBlock* successor : successors_) {      // Delete this block from the list of predecessors.      size_t this_index = successor->GetPredecessorIndexOf(this); @@ -1437,30 +1488,57 @@ void HBasicBlock::DisconnectAndDelete() {      // dominator of `successor` which violates the order DCHECKed at the top.      DCHECK(!successor->predecessors_.empty()); -    // Remove this block's entries in the successor's phis. -    if (successor->predecessors_.size() == 1u) { -      // The successor has just one predecessor left. Replace phis with the only -      // remaining input. -      for (HInstructionIterator phi_it(successor->GetPhis()); !phi_it.Done(); phi_it.Advance()) { -        HPhi* phi = phi_it.Current()->AsPhi(); -        phi->ReplaceWith(phi->InputAt(1 - this_index)); -        successor->RemovePhi(phi); -      } -    } else { -      for (HInstructionIterator phi_it(successor->GetPhis()); !phi_it.Done(); phi_it.Advance()) { -        phi_it.Current()->AsPhi()->RemoveInputAt(this_index); +    // Remove this block's entries in the successor's phis. Skip exceptional +    // successors because catch phi inputs do not correspond to predecessor +    // blocks but throwing instructions. Their inputs will be updated in step (4). +    if (!successor->IsCatchBlock()) { +      if (successor->predecessors_.size() == 1u) { +        // The successor has just one predecessor left. Replace phis with the only +        // remaining input. +        for (HInstructionIterator phi_it(successor->GetPhis()); !phi_it.Done(); phi_it.Advance()) { +          HPhi* phi = phi_it.Current()->AsPhi(); +          phi->ReplaceWith(phi->InputAt(1 - this_index)); +          successor->RemovePhi(phi); +        } +      } else { +        for (HInstructionIterator phi_it(successor->GetPhis()); !phi_it.Done(); phi_it.Advance()) { +          phi_it.Current()->AsPhi()->RemoveInputAt(this_index); +        }        }      }    }    successors_.clear(); +  // (4) Remove instructions and phis. Instructions should have no remaining uses +  //     except in catch phis. If an instruction is used by a catch phi at `index`, +  //     remove `index`-th input of all phis in the catch block since they are +  //     guaranteed dead. Note that we may miss dead inputs this way but the +  //     graph will always remain consistent. +  for (HBackwardInstructionIterator it(GetInstructions()); !it.Done(); it.Advance()) { +    HInstruction* insn = it.Current(); +    while (insn->HasUses()) { +      DCHECK(IsTryBlock()); +      HUseListNode<HInstruction*>* use = insn->GetUses().GetFirst(); +      size_t use_index = use->GetIndex(); +      HBasicBlock* user_block =  use->GetUser()->GetBlock(); +      DCHECK(use->GetUser()->IsPhi() && user_block->IsCatchBlock()); +      for (HInstructionIterator phi_it(user_block->GetPhis()); !phi_it.Done(); phi_it.Advance()) { +        phi_it.Current()->AsPhi()->RemoveInputAt(use_index); +      } +    } + +    RemoveInstruction(insn); +  } +  for (HInstructionIterator it(GetPhis()); !it.Done(); it.Advance()) { +    RemovePhi(it.Current()->AsPhi()); +  } +    // Disconnect from the dominator.    dominator_->RemoveDominatedBlock(this);    SetDominator(nullptr); -  // Delete from the graph. The function safely deletes remaining instructions -  // and updates the reverse post order. -  graph_->DeleteDeadBlock(this); +  // Delete from the graph, update reverse post order. +  graph_->DeleteDeadEmptyBlock(this);    SetGraph(nullptr);  } @@ -1507,7 +1585,7 @@ void HBasicBlock::MergeWith(HBasicBlock* other) {    other->predecessors_.clear();    // Delete `other` from the graph. The function updates reverse post order. -  graph_->DeleteDeadBlock(other); +  graph_->DeleteDeadEmptyBlock(other);    other->SetGraph(nullptr);  } @@ -1571,19 +1649,14 @@ static void MakeRoomFor(ArenaVector<HBasicBlock*>* blocks,    std::copy_backward(blocks->begin() + after + 1u, blocks->begin() + old_size, blocks->end());  } -void HGraph::DeleteDeadBlock(HBasicBlock* block) { +void HGraph::DeleteDeadEmptyBlock(HBasicBlock* block) {    DCHECK_EQ(block->GetGraph(), this);    DCHECK(block->GetSuccessors().empty());    DCHECK(block->GetPredecessors().empty());    DCHECK(block->GetDominatedBlocks().empty());    DCHECK(block->GetDominator() == nullptr); - -  for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { -    block->RemoveInstruction(it.Current()); -  } -  for (HBackwardInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { -    block->RemovePhi(it.Current()->AsPhi()); -  } +  DCHECK(block->GetInstructions().IsEmpty()); +  DCHECK(block->GetPhis().IsEmpty());    if (block->IsExitBlock()) {      exit_block_ = nullptr; @@ -1686,6 +1759,9 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {      // (2) the reverse post order of that graph,      // (3) the potential loop information they are now in,      // (4) try block membership. +    // Note that we do not need to update catch phi inputs because they +    // correspond to the register file of the outer method which the inlinee +    // cannot modify.      // We don't add the entry block, the exit block, and the first block, which      // has been merged with `at`.  |