diff options
Diffstat (limited to 'compiler/optimizing')
20 files changed, 103 insertions, 37 deletions
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index e7fa4e472b..51fbaea519 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -50,6 +50,7 @@  #include "mirror/array-inl.h"  #include "mirror/object_array-inl.h"  #include "mirror/object_reference.h" +#include "mirror/string.h"  #include "parallel_move_resolver.h"  #include "ssa_liveness_analysis.h"  #include "utils/assembler.h" @@ -139,6 +140,12 @@ size_t CodeGenerator::GetCachePointerOffset(uint32_t index) {    return pointer_size * index;  } +uint32_t CodeGenerator::GetArrayLengthOffset(HArrayLength* array_length) { +  return array_length->IsStringLength() +      ? mirror::String::CountOffset().Uint32Value() +      : mirror::Array::LengthOffset().Uint32Value(); +} +  bool CodeGenerator::GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const {    DCHECK_EQ((*block_order_)[current_block_index_], current);    return GetNextBlockToEmit() == FirstNonEmptyBlock(next); diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index d69c41055b..6e75e3bb2e 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -340,6 +340,11 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> {    // Pointer variant for ArtMethod and ArtField arrays.    size_t GetCachePointerOffset(uint32_t index); +  // Helper that returns the offset of the array's length field. +  // Note: Besides the normal arrays, we also use the HArrayLength for +  // accessing the String's `count` field in String intrinsics. +  static uint32_t GetArrayLengthOffset(HArrayLength* array_length); +    void EmitParallelMoves(Location from1,                           Location to1,                           Primitive::Type type1, diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 197e473473..e0106628c6 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -4742,7 +4742,7 @@ void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {  void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {    LocationSummary* locations = instruction->GetLocations(); -  uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); +  uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);    Register obj = locations->InAt(0).AsRegister<Register>();    Register out = locations->Out().AsRegister<Register>();    __ LoadFromOffset(kLoadWord, out, obj, offset); diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 9680f2bf45..261c04f062 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -2118,9 +2118,9 @@ void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {  }  void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) { +  uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);    BlockPoolsScope block_pools(GetVIXLAssembler()); -  __ Ldr(OutputRegister(instruction), -         HeapOperand(InputRegisterAt(instruction, 0), mirror::Array::LengthOffset())); +  __ Ldr(OutputRegister(instruction), HeapOperand(InputRegisterAt(instruction, 0), offset));    codegen_->MaybeRecordImplicitNullCheck(instruction);  } diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index 12d1164d03..fb50680c91 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -1803,7 +1803,7 @@ void LocationsBuilderMIPS::VisitArrayLength(HArrayLength* instruction) {  void InstructionCodeGeneratorMIPS::VisitArrayLength(HArrayLength* instruction) {    LocationSummary* locations = instruction->GetLocations(); -  uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); +  uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);    Register obj = locations->InAt(0).AsRegister<Register>();    Register out = locations->Out().AsRegister<Register>();    __ LoadFromOffset(kLoadWord, out, obj, offset); diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 56ac38ef84..e67d8d0dc5 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -1426,7 +1426,7 @@ void LocationsBuilderMIPS64::VisitArrayLength(HArrayLength* instruction) {  void InstructionCodeGeneratorMIPS64::VisitArrayLength(HArrayLength* instruction) {    LocationSummary* locations = instruction->GetLocations(); -  uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); +  uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);    GpuRegister obj = locations->InAt(0).AsRegister<GpuRegister>();    GpuRegister out = locations->Out().AsRegister<GpuRegister>();    __ LoadFromOffset(kLoadWord, out, obj, offset); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 6dc480bbee..50892a9d48 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -5480,7 +5480,7 @@ void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {  void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {    LocationSummary* locations = instruction->GetLocations(); -  uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); +  uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);    Register obj = locations->InAt(0).AsRegister<Register>();    Register out = locations->Out().AsRegister<Register>();    __ movl(out, Address(obj, offset)); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 96ec09c2a8..56c5b06945 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -4956,7 +4956,7 @@ void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {  void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {    LocationSummary* locations = instruction->GetLocations(); -  uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); +  uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);    CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();    CpuRegister out = locations->Out().AsRegister<CpuRegister>();    __ movl(out, Address(obj, offset)); diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc index 5f11024996..49cfff46d8 100644 --- a/compiler/optimizing/dead_code_elimination.cc +++ b/compiler/optimizing/dead_code_elimination.cc @@ -23,7 +23,7 @@  namespace art {  static void MarkReachableBlocks(HGraph* graph, ArenaBitVector* visited) { -  ArenaVector<HBasicBlock*> worklist(graph->GetArena()->Adapter()); +  ArenaVector<HBasicBlock*> worklist(graph->GetArena()->Adapter(kArenaAllocDCE));    constexpr size_t kDefaultWorlistSize = 8;    worklist.reserve(kDefaultWorlistSize);    visited->SetBit(graph->GetEntryBlock()->GetBlockId()); diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 9efc13f61b..568b8a8df6 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -389,6 +389,11 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor {          << instance_of->MustDoNullCheck() << std::noboolalpha;    } +  void VisitArrayLength(HArrayLength* array_length) OVERRIDE { +    StartAttributeStream("is_string_length") << std::boolalpha +        << array_length->IsStringLength() << std::noboolalpha; +  } +    void VisitArraySet(HArraySet* array_set) OVERRIDE {      StartAttributeStream("value_can_be_null") << std::boolalpha          << array_set->GetValueCanBeNull() << std::noboolalpha; diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index a834216d0c..aaddc01f1f 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -721,6 +721,11 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in        DCHECK(Runtime::Current()->IsAotCompiler());        return nullptr;      } +    if (!methods_class->IsAssignableFrom(compiling_class.Get())) { +      // We cannot statically determine the target method. The runtime will throw a +      // NoSuchMethodError on this one. +      return nullptr; +    }      ArtMethod* actual_method;      if (methods_class->IsInterface()) {        actual_method = methods_class->FindVirtualMethodForInterfaceSuper( diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index d7b3856bf4..fd79901ffc 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -101,6 +101,7 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor {    void SimplifyCompare(HInvoke* invoke, bool is_signum, Primitive::Type type);    void SimplifyIsNaN(HInvoke* invoke);    void SimplifyFP2Int(HInvoke* invoke); +  void SimplifyStringIsEmptyOrLength(HInvoke* invoke);    void SimplifyMemBarrier(HInvoke* invoke, MemBarrierKind barrier_kind);    OptimizingCompilerStats* stats_; @@ -1673,6 +1674,27 @@ void InstructionSimplifierVisitor::SimplifyFP2Int(HInvoke* invoke) {    invoke->ReplaceWithExceptInReplacementAtIndex(select, 0);  // false at index 0  } +void InstructionSimplifierVisitor::SimplifyStringIsEmptyOrLength(HInvoke* invoke) { +  HInstruction* str = invoke->InputAt(0); +  uint32_t dex_pc = invoke->GetDexPc(); +  // We treat String as an array to allow DCE and BCE to seamlessly work on strings, +  // so create the HArrayLength. +  HArrayLength* length = new (GetGraph()->GetArena()) HArrayLength(str, dex_pc); +  length->MarkAsStringLength(); +  HInstruction* replacement; +  if (invoke->GetIntrinsic() == Intrinsics::kStringIsEmpty) { +    // For String.isEmpty(), create the `HEqual` representing the `length == 0`. +    invoke->GetBlock()->InsertInstructionBefore(length, invoke); +    HIntConstant* zero = GetGraph()->GetIntConstant(0); +    HEqual* equal = new (GetGraph()->GetArena()) HEqual(length, zero, dex_pc); +    replacement = equal; +  } else { +    DCHECK_EQ(invoke->GetIntrinsic(), Intrinsics::kStringLength); +    replacement = length; +  } +  invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, replacement); +} +  void InstructionSimplifierVisitor::SimplifyMemBarrier(HInvoke* invoke, MemBarrierKind barrier_kind) {    uint32_t dex_pc = invoke->GetDexPc();    HMemoryBarrier* mem_barrier = new (GetGraph()->GetArena()) HMemoryBarrier(barrier_kind, dex_pc); @@ -1719,6 +1741,10 @@ void InstructionSimplifierVisitor::VisitInvoke(HInvoke* instruction) {      case Intrinsics::kDoubleDoubleToLongBits:        SimplifyFP2Int(instruction);        break; +    case Intrinsics::kStringIsEmpty: +    case Intrinsics::kStringLength: +      SimplifyStringIsEmptyOrLength(instruction); +      break;      case Intrinsics::kUnsafeLoadFence:        SimplifyMemBarrier(instruction, MemBarrierKind::kLoadAny);        break; diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 5d4c4e2950..418d59c6cb 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -388,10 +388,8 @@ static Intrinsics GetIntrinsic(InlineMethod method) {      case kIntrinsicGetCharsNoCheck:        return Intrinsics::kStringGetCharsNoCheck;      case kIntrinsicIsEmptyOrLength: -      // The inliner can handle these two cases - and this is the preferred approach -      // since after inlining the call is no longer visible (as opposed to waiting -      // until codegen to handle intrinsic). -      return Intrinsics::kNone; +      return ((method.d.data & kIntrinsicFlagIsEmpty) == 0) ? +          Intrinsics::kStringLength : Intrinsics::kStringIsEmpty;      case kIntrinsicIndexOf:        return ((method.d.data & kIntrinsicFlagBase0) == 0) ?            Intrinsics::kStringIndexOfAfter : Intrinsics::kStringIndexOf; diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h index 39a1313ba0..214250f337 100644 --- a/compiler/optimizing/intrinsics.h +++ b/compiler/optimizing/intrinsics.h @@ -239,6 +239,8 @@ UNREACHABLE_INTRINSIC(Arch, IntegerCompare)         \  UNREACHABLE_INTRINSIC(Arch, LongCompare)            \  UNREACHABLE_INTRINSIC(Arch, IntegerSignum)          \  UNREACHABLE_INTRINSIC(Arch, LongSignum)             \ +UNREACHABLE_INTRINSIC(Arch, StringIsEmpty)          \ +UNREACHABLE_INTRINSIC(Arch, StringLength)           \  UNREACHABLE_INTRINSIC(Arch, UnsafeLoadFence)        \  UNREACHABLE_INTRINSIC(Arch, UnsafeStoreFence)       \  UNREACHABLE_INTRINSIC(Arch, UnsafeFullFence) diff --git a/compiler/optimizing/intrinsics_list.h b/compiler/optimizing/intrinsics_list.h index dd9294d486..db60238fb4 100644 --- a/compiler/optimizing/intrinsics_list.h +++ b/compiler/optimizing/intrinsics_list.h @@ -107,6 +107,8 @@    V(StringGetCharsNoCheck, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \    V(StringIndexOf, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \    V(StringIndexOfAfter, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \ +  V(StringIsEmpty, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow) \ +  V(StringLength, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow) \    V(StringNewStringFromBytes, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \    V(StringNewStringFromChars, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \    V(StringNewStringFromString, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \ diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index 2de41580b6..8a75a90cfd 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -733,19 +733,14 @@ class LSEVisitor : public HGraphVisitor {        if (Primitive::PrimitiveKind(heap_value->GetType())                != Primitive::PrimitiveKind(instruction->GetType())) {          // The only situation where the same heap location has different type is when -        // we do an array get from a null constant. In order to stay properly typed -        // we do not merge the array gets. +        // we do an array get on an instruction that originates from the null constant +        // (the null could be behind a field access, an array access, a null check or +        // a bound type). +        // In order to stay properly typed on primitive types, we do not eliminate +        // the array gets.          if (kIsDebugBuild) {            DCHECK(heap_value->IsArrayGet()) << heap_value->DebugName();            DCHECK(instruction->IsArrayGet()) << instruction->DebugName(); -          HInstruction* array = instruction->AsArrayGet()->GetArray(); -          DCHECK(array->IsNullCheck()) << array->DebugName(); -          HInstruction* input = HuntForOriginalReference(array->InputAt(0)); -          DCHECK(input->IsNullConstant()) << input->DebugName(); -          array = heap_value->AsArrayGet()->GetArray(); -          DCHECK(array->IsNullCheck()) << array->DebugName(); -          input = HuntForOriginalReference(array->InputAt(0)); -          DCHECK(input->IsNullConstant()) << input->DebugName();          }          return;        } diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index eb9c381c4e..1e6bf07e42 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -56,9 +56,11 @@ void HGraph::FindBackEdges(ArenaBitVector* visited) {    // Nodes that we're currently visiting, indexed by block id.    ArenaBitVector visiting(arena_, blocks_.size(), false, kArenaAllocGraphBuilder);    // Number of successors visited from a given node, indexed by block id. -  ArenaVector<size_t> successors_visited(blocks_.size(), 0u, arena_->Adapter()); +  ArenaVector<size_t> successors_visited(blocks_.size(), +                                         0u, +                                         arena_->Adapter(kArenaAllocGraphBuilder));    // Stack of nodes that we're currently visiting (same as marked in "visiting" above). -  ArenaVector<HBasicBlock*> worklist(arena_->Adapter()); +  ArenaVector<HBasicBlock*> worklist(arena_->Adapter(kArenaAllocGraphBuilder));    constexpr size_t kDefaultWorklistSize = 8;    worklist.reserve(kDefaultWorklistSize);    visited->SetBit(entry_block_->GetBlockId()); @@ -228,11 +230,13 @@ void HGraph::ComputeDominanceInformation() {    reverse_post_order_.push_back(entry_block_);    // Number of visits of a given node, indexed by block id. -  ArenaVector<size_t> visits(blocks_.size(), 0u, arena_->Adapter()); +  ArenaVector<size_t> visits(blocks_.size(), 0u, arena_->Adapter(kArenaAllocGraphBuilder));    // Number of successors visited from a given node, indexed by block id. -  ArenaVector<size_t> successors_visited(blocks_.size(), 0u, arena_->Adapter()); +  ArenaVector<size_t> successors_visited(blocks_.size(), +                                         0u, +                                         arena_->Adapter(kArenaAllocGraphBuilder));    // Nodes for which we need to visit successors. -  ArenaVector<HBasicBlock*> worklist(arena_->Adapter()); +  ArenaVector<HBasicBlock*> worklist(arena_->Adapter(kArenaAllocGraphBuilder));    constexpr size_t kDefaultWorklistSize = 8;    worklist.reserve(kDefaultWorklistSize);    worklist.push_back(entry_block_); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 829fe71a78..934d355e82 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -5228,9 +5228,22 @@ class HArrayLength : public HExpression<1> {      return obj == InputAt(0);    } +  void MarkAsStringLength() { SetPackedFlag<kFlagIsStringLength>(); } +  bool IsStringLength() const { return GetPackedFlag<kFlagIsStringLength>(); } +    DECLARE_INSTRUCTION(ArrayLength);   private: +  // We treat a String as an array, creating the HArrayLength from String.length() +  // or String.isEmpty() intrinsic in the instruction simplifier. We can always +  // determine whether a particular HArrayLength is actually a String.length() by +  // looking at the type of the input but that requires holding the mutator lock, so +  // we prefer to use a flag, so that code generators don't need to do the locking. +  static constexpr size_t kFlagIsStringLength = kNumberOfExpressionPackedBits; +  static constexpr size_t kNumberOfArrayLengthPackedBits = kFlagIsStringLength + 1; +  static_assert(kNumberOfArrayLengthPackedBits <= HInstruction::kMaxNumberOfPackedBits, +                "Too many packed fields."); +    DISALLOW_COPY_AND_ASSIGN(HArrayLength);  }; diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc index c2aa0c0075..f96ca321c9 100644 --- a/compiler/optimizing/ssa_builder.cc +++ b/compiler/optimizing/ssa_builder.cc @@ -233,7 +233,7 @@ bool SsaBuilder::UpdatePrimitiveType(HPhi* phi, ArenaVector<HPhi*>* worklist) {  }  void SsaBuilder::RunPrimitiveTypePropagation() { -  ArenaVector<HPhi*> worklist(graph_->GetArena()->Adapter()); +  ArenaVector<HPhi*> worklist(graph_->GetArena()->Adapter(kArenaAllocGraphBuilder));    for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {      HBasicBlock* block = it.Current(); @@ -319,7 +319,7 @@ bool SsaBuilder::FixAmbiguousArrayOps() {    // uses (because they are untyped) and environment uses (if --debuggable).    // After resolving all ambiguous ArrayGets, we will re-run primitive type    // propagation on the Phis which need to be updated. -  ArenaVector<HPhi*> worklist(graph_->GetArena()->Adapter()); +  ArenaVector<HPhi*> worklist(graph_->GetArena()->Adapter(kArenaAllocGraphBuilder));    {      ScopedObjectAccess soa(Thread::Current()); diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc index 0978ae17f8..c67612e651 100644 --- a/compiler/optimizing/ssa_phi_elimination.cc +++ b/compiler/optimizing/ssa_phi_elimination.cc @@ -17,6 +17,7 @@  #include "ssa_phi_elimination.h"  #include "base/arena_containers.h" +#include "base/arena_bit_vector.h"  #include "base/bit_vector-inl.h"  namespace art { @@ -30,7 +31,7 @@ void SsaDeadPhiElimination::MarkDeadPhis() {    // Phis are constructed live and should not be revived if previously marked    // dead. This algorithm temporarily breaks that invariant but we DCHECK that    // only phis which were initially live are revived. -  ArenaSet<HPhi*> initially_live(graph_->GetArena()->Adapter()); +  ArenaSet<HPhi*> initially_live(graph_->GetArena()->Adapter(kArenaAllocSsaPhiElimination));    // Add to the worklist phis referenced by non-phi instructions.    for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) { @@ -127,8 +128,11 @@ void SsaRedundantPhiElimination::Run() {      }    } -  ArenaSet<uint32_t> visited_phis_in_cycle(graph_->GetArena()->Adapter()); -  ArenaVector<HPhi*> cycle_worklist(graph_->GetArena()->Adapter()); +  ArenaBitVector visited_phis_in_cycle(graph_->GetArena(), +                                       graph_->GetCurrentInstructionId(), +                                       /* expandable */ false, +                                       kArenaAllocSsaPhiElimination); +  ArenaVector<HPhi*> cycle_worklist(graph_->GetArena()->Adapter(kArenaAllocSsaPhiElimination));    while (!worklist_.empty()) {      HPhi* phi = worklist_.back(); @@ -146,11 +150,11 @@ void SsaRedundantPhiElimination::Run() {      }      HInstruction* candidate = nullptr; -    visited_phis_in_cycle.clear(); +    visited_phis_in_cycle.ClearAllBits();      cycle_worklist.clear();      cycle_worklist.push_back(phi); -    visited_phis_in_cycle.insert(phi->GetId()); +    visited_phis_in_cycle.SetBit(phi->GetId());      bool catch_phi_in_cycle = phi->IsCatchPhi();      bool irreducible_loop_phi_in_cycle = phi->IsIrreducibleLoopHeaderPhi(); @@ -182,9 +186,9 @@ void SsaRedundantPhiElimination::Run() {            if (input == current) {              continue;            } else if (input->IsPhi()) { -            if (!ContainsElement(visited_phis_in_cycle, input->GetId())) { +            if (!visited_phis_in_cycle.IsBitSet(input->GetId())) {                cycle_worklist.push_back(input->AsPhi()); -              visited_phis_in_cycle.insert(input->GetId()); +              visited_phis_in_cycle.SetBit(input->GetId());                catch_phi_in_cycle |= input->AsPhi()->IsCatchPhi();                irreducible_loop_phi_in_cycle |= input->IsIrreducibleLoopHeaderPhi();              } else { @@ -233,7 +237,7 @@ void SsaRedundantPhiElimination::Run() {        // for elimination. Add phis that use this phi to the worklist.        for (const HUseListNode<HInstruction*>& use : current->GetUses()) {          HInstruction* user = use.GetUser(); -        if (user->IsPhi() && !ContainsElement(visited_phis_in_cycle, user->GetId())) { +        if (user->IsPhi() && !visited_phis_in_cycle.IsBitSet(user->GetId())) {            worklist_.push_back(user->AsPhi());          }        }  |