| Index: src/hydrogen-gvn.cc | 
| diff --git a/src/hydrogen-gvn.cc b/src/hydrogen-gvn.cc | 
| index bc836890bb136544c560474c222d7b354c9ddb4a..6bf5a1b68e4fc3a2a8cdcaf02da63e614c63e1ee 100644 | 
| --- a/src/hydrogen-gvn.cc | 
| +++ b/src/hydrogen-gvn.cc | 
| @@ -32,39 +32,39 @@ | 
| namespace v8 { | 
| namespace internal { | 
|  | 
| -class HValueMap: public ZoneObject { | 
| +class HInstructionMap V8_FINAL : public ZoneObject { | 
| public: | 
| -  explicit HValueMap(Zone* zone) | 
| +  HInstructionMap(Zone* zone, SideEffectsTracker* side_effects_tracker) | 
| : array_size_(0), | 
| lists_size_(0), | 
| count_(0), | 
| -        present_flags_(0), | 
| array_(NULL), | 
| lists_(NULL), | 
| -        free_list_head_(kNil) { | 
| +        free_list_head_(kNil), | 
| +        side_effects_tracker_(side_effects_tracker) { | 
| ResizeLists(kInitialSize, zone); | 
| Resize(kInitialSize, zone); | 
| } | 
|  | 
| -  void Kill(GVNFlagSet flags); | 
| +  void Kill(SideEffects side_effects); | 
|  | 
| -  void Add(HValue* value, Zone* zone) { | 
| -    present_flags_.Add(value->gvn_flags()); | 
| -    Insert(value, zone); | 
| +  void Add(HInstruction* instr, Zone* zone) { | 
| +    present_depends_on_.Add(side_effects_tracker_->ComputeDependsOn(instr)); | 
| +    Insert(instr, zone); | 
| } | 
|  | 
| -  HValue* Lookup(HValue* value) const; | 
| +  HInstruction* Lookup(HInstruction* instr) const; | 
|  | 
| -  HValueMap* Copy(Zone* zone) const { | 
| -    return new(zone) HValueMap(zone, this); | 
| +  HInstructionMap* Copy(Zone* zone) const { | 
| +    return new(zone) HInstructionMap(zone, this); | 
| } | 
|  | 
| bool IsEmpty() const { return count_ == 0; } | 
|  | 
| private: | 
| -  // A linked list of HValue* values.  Stored in arrays. | 
| -  struct HValueMapListElement { | 
| -    HValue* value; | 
| +  // A linked list of HInstruction* values.  Stored in arrays. | 
| +  struct HInstructionMapListElement { | 
| +    HInstruction* instr; | 
| int next;  // Index in the array of the next list element. | 
| }; | 
| static const int kNil = -1;  // The end of a linked list | 
| @@ -72,34 +72,36 @@ class HValueMap: public ZoneObject { | 
| // Must be a power of 2. | 
| static const int kInitialSize = 16; | 
|  | 
| -  HValueMap(Zone* zone, const HValueMap* other); | 
| +  HInstructionMap(Zone* zone, const HInstructionMap* other); | 
|  | 
| void Resize(int new_size, Zone* zone); | 
| void ResizeLists(int new_size, Zone* zone); | 
| -  void Insert(HValue* value, Zone* zone); | 
| +  void Insert(HInstruction* instr, Zone* zone); | 
| uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); } | 
|  | 
| int array_size_; | 
| int lists_size_; | 
| -  int count_;  // The number of values stored in the HValueMap. | 
| -  GVNFlagSet present_flags_;  // All flags that are in any value in the | 
| -                              // HValueMap. | 
| -  HValueMapListElement* array_;  // Primary store - contains the first value | 
| +  int count_;  // The number of values stored in the HInstructionMap. | 
| +  SideEffects present_depends_on_; | 
| +  HInstructionMapListElement* array_; | 
| +  // Primary store - contains the first value | 
| // with a given hash.  Colliding elements are stored in linked lists. | 
| -  HValueMapListElement* lists_;  // The linked lists containing hash collisions. | 
| +  HInstructionMapListElement* lists_; | 
| +  // The linked lists containing hash collisions. | 
| int free_list_head_;  // Unused elements in lists_ are on the free list. | 
| +  SideEffectsTracker* side_effects_tracker_; | 
| }; | 
|  | 
|  | 
| -class HSideEffectMap BASE_EMBEDDED { | 
| +class HSideEffectMap V8_FINAL BASE_EMBEDDED { | 
| public: | 
| HSideEffectMap(); | 
| explicit HSideEffectMap(HSideEffectMap* other); | 
| HSideEffectMap& operator= (const HSideEffectMap& other); | 
|  | 
| -  void Kill(GVNFlagSet flags); | 
| +  void Kill(SideEffects side_effects); | 
|  | 
| -  void Store(GVNFlagSet flags, HInstruction* instr); | 
| +  void Store(SideEffects side_effects, HInstruction* instr); | 
|  | 
| bool IsEmpty() const { return count_ == 0; } | 
|  | 
| @@ -152,35 +154,36 @@ void TraceGVN(const char* msg, ...) { | 
| } | 
|  | 
|  | 
| -HValueMap::HValueMap(Zone* zone, const HValueMap* other) | 
| +HInstructionMap::HInstructionMap(Zone* zone, const HInstructionMap* other) | 
| : array_size_(other->array_size_), | 
| lists_size_(other->lists_size_), | 
| count_(other->count_), | 
| -      present_flags_(other->present_flags_), | 
| -      array_(zone->NewArray<HValueMapListElement>(other->array_size_)), | 
| -      lists_(zone->NewArray<HValueMapListElement>(other->lists_size_)), | 
| -      free_list_head_(other->free_list_head_) { | 
| +      present_depends_on_(other->present_depends_on_), | 
| +      array_(zone->NewArray<HInstructionMapListElement>(other->array_size_)), | 
| +      lists_(zone->NewArray<HInstructionMapListElement>(other->lists_size_)), | 
| +      free_list_head_(other->free_list_head_), | 
| +      side_effects_tracker_(other->side_effects_tracker_) { | 
| OS::MemCopy( | 
| -      array_, other->array_, array_size_ * sizeof(HValueMapListElement)); | 
| +      array_, other->array_, array_size_ * sizeof(HInstructionMapListElement)); | 
| OS::MemCopy( | 
| -      lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement)); | 
| +      lists_, other->lists_, lists_size_ * sizeof(HInstructionMapListElement)); | 
| } | 
|  | 
|  | 
| -void HValueMap::Kill(GVNFlagSet flags) { | 
| -  GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(flags); | 
| -  if (!present_flags_.ContainsAnyOf(depends_flags)) return; | 
| -  present_flags_.RemoveAll(); | 
| +void HInstructionMap::Kill(SideEffects changes) { | 
| +  if (!present_depends_on_.ContainsAnyOf(changes)) return; | 
| +  present_depends_on_.RemoveAll(); | 
| for (int i = 0; i < array_size_; ++i) { | 
| -    HValue* value = array_[i].value; | 
| -    if (value != NULL) { | 
| +    HInstruction* instr = array_[i].instr; | 
| +    if (instr != NULL) { | 
| // Clear list of collisions first, so we know if it becomes empty. | 
| int kept = kNil;  // List of kept elements. | 
| int next; | 
| for (int current = array_[i].next; current != kNil; current = next) { | 
| next = lists_[current].next; | 
| -        HValue* value = lists_[current].value; | 
| -        if (value->gvn_flags().ContainsAnyOf(depends_flags)) { | 
| +        HInstruction* instr = lists_[current].instr; | 
| +        SideEffects depends_on = side_effects_tracker_->ComputeDependsOn(instr); | 
| +        if (depends_on.ContainsAnyOf(changes)) { | 
| // Drop it. | 
| count_--; | 
| lists_[current].next = free_list_head_; | 
| @@ -189,40 +192,41 @@ void HValueMap::Kill(GVNFlagSet flags) { | 
| // Keep it. | 
| lists_[current].next = kept; | 
| kept = current; | 
| -          present_flags_.Add(value->gvn_flags()); | 
| +          present_depends_on_.Add(depends_on); | 
| } | 
| } | 
| array_[i].next = kept; | 
|  | 
| // Now possibly drop directly indexed element. | 
| -      value = array_[i].value; | 
| -      if (value->gvn_flags().ContainsAnyOf(depends_flags)) {  // Drop it. | 
| +      instr = array_[i].instr; | 
| +      SideEffects depends_on = side_effects_tracker_->ComputeDependsOn(instr); | 
| +      if (depends_on.ContainsAnyOf(changes)) {  // Drop it. | 
| count_--; | 
| int head = array_[i].next; | 
| if (head == kNil) { | 
| -          array_[i].value = NULL; | 
| +          array_[i].instr = NULL; | 
| } else { | 
| -          array_[i].value = lists_[head].value; | 
| +          array_[i].instr = lists_[head].instr; | 
| array_[i].next = lists_[head].next; | 
| lists_[head].next = free_list_head_; | 
| free_list_head_ = head; | 
| } | 
| } else { | 
| -        present_flags_.Add(value->gvn_flags());  // Keep it. | 
| +        present_depends_on_.Add(depends_on);  // Keep it. | 
| } | 
| } | 
| } | 
| } | 
|  | 
|  | 
| -HValue* HValueMap::Lookup(HValue* value) const { | 
| -  uint32_t hash = static_cast<uint32_t>(value->Hashcode()); | 
| +HInstruction* HInstructionMap::Lookup(HInstruction* instr) const { | 
| +  uint32_t hash = static_cast<uint32_t>(instr->Hashcode()); | 
| uint32_t pos = Bound(hash); | 
| -  if (array_[pos].value != NULL) { | 
| -    if (array_[pos].value->Equals(value)) return array_[pos].value; | 
| +  if (array_[pos].instr != NULL) { | 
| +    if (array_[pos].instr->Equals(instr)) return array_[pos].instr; | 
| int next = array_[pos].next; | 
| while (next != kNil) { | 
| -      if (lists_[next].value->Equals(value)) return lists_[next].value; | 
| +      if (lists_[next].instr->Equals(instr)) return lists_[next].instr; | 
| next = lists_[next].next; | 
| } | 
| } | 
| @@ -230,7 +234,7 @@ HValue* HValueMap::Lookup(HValue* value) const { | 
| } | 
|  | 
|  | 
| -void HValueMap::Resize(int new_size, Zone* zone) { | 
| +void HInstructionMap::Resize(int new_size, Zone* zone) { | 
| ASSERT(new_size > count_); | 
| // Hashing the values into the new array has no more collisions than in the | 
| // old hash map, so we can use the existing lists_ array, if we are careful. | 
| @@ -240,33 +244,33 @@ void HValueMap::Resize(int new_size, Zone* zone) { | 
| ResizeLists(lists_size_ << 1, zone); | 
| } | 
|  | 
| -  HValueMapListElement* new_array = | 
| -      zone->NewArray<HValueMapListElement>(new_size); | 
| -  memset(new_array, 0, sizeof(HValueMapListElement) * new_size); | 
| +  HInstructionMapListElement* new_array = | 
| +      zone->NewArray<HInstructionMapListElement>(new_size); | 
| +  memset(new_array, 0, sizeof(HInstructionMapListElement) * new_size); | 
|  | 
| -  HValueMapListElement* old_array = array_; | 
| +  HInstructionMapListElement* old_array = array_; | 
| int old_size = array_size_; | 
|  | 
| int old_count = count_; | 
| count_ = 0; | 
| -  // Do not modify present_flags_.  It is currently correct. | 
| +  // Do not modify present_depends_on_.  It is currently correct. | 
| array_size_ = new_size; | 
| array_ = new_array; | 
|  | 
| if (old_array != NULL) { | 
| // Iterate over all the elements in lists, rehashing them. | 
| for (int i = 0; i < old_size; ++i) { | 
| -      if (old_array[i].value != NULL) { | 
| +      if (old_array[i].instr != NULL) { | 
| int current = old_array[i].next; | 
| while (current != kNil) { | 
| -          Insert(lists_[current].value, zone); | 
| +          Insert(lists_[current].instr, zone); | 
| int next = lists_[current].next; | 
| lists_[current].next = free_list_head_; | 
| free_list_head_ = current; | 
| current = next; | 
| } | 
| -        // Rehash the directly stored value. | 
| -        Insert(old_array[i].value, zone); | 
| +        // Rehash the directly stored instruction. | 
| +        Insert(old_array[i].instr, zone); | 
| } | 
| } | 
| } | 
| @@ -275,21 +279,22 @@ void HValueMap::Resize(int new_size, Zone* zone) { | 
| } | 
|  | 
|  | 
| -void HValueMap::ResizeLists(int new_size, Zone* zone) { | 
| +void HInstructionMap::ResizeLists(int new_size, Zone* zone) { | 
| ASSERT(new_size > lists_size_); | 
|  | 
| -  HValueMapListElement* new_lists = | 
| -      zone->NewArray<HValueMapListElement>(new_size); | 
| -  memset(new_lists, 0, sizeof(HValueMapListElement) * new_size); | 
| +  HInstructionMapListElement* new_lists = | 
| +      zone->NewArray<HInstructionMapListElement>(new_size); | 
| +  memset(new_lists, 0, sizeof(HInstructionMapListElement) * new_size); | 
|  | 
| -  HValueMapListElement* old_lists = lists_; | 
| +  HInstructionMapListElement* old_lists = lists_; | 
| int old_size = lists_size_; | 
|  | 
| lists_size_ = new_size; | 
| lists_ = new_lists; | 
|  | 
| if (old_lists != NULL) { | 
| -    OS::MemCopy(lists_, old_lists, old_size * sizeof(HValueMapListElement)); | 
| +    OS::MemCopy( | 
| +        lists_, old_lists, old_size * sizeof(HInstructionMapListElement)); | 
| } | 
| for (int i = old_size; i < lists_size_; ++i) { | 
| lists_[i].next = free_list_head_; | 
| @@ -298,15 +303,15 @@ void HValueMap::ResizeLists(int new_size, Zone* zone) { | 
| } | 
|  | 
|  | 
| -void HValueMap::Insert(HValue* value, Zone* zone) { | 
| -  ASSERT(value != NULL); | 
| +void HInstructionMap::Insert(HInstruction* instr, Zone* zone) { | 
| +  ASSERT(instr != NULL); | 
| // Resizing when half of the hashtable is filled up. | 
| if (count_ >= array_size_ >> 1) Resize(array_size_ << 1, zone); | 
| ASSERT(count_ < array_size_); | 
| count_++; | 
| -  uint32_t pos = Bound(static_cast<uint32_t>(value->Hashcode())); | 
| -  if (array_[pos].value == NULL) { | 
| -    array_[pos].value = value; | 
| +  uint32_t pos = Bound(static_cast<uint32_t>(instr->Hashcode())); | 
| +  if (array_[pos].instr == NULL) { | 
| +    array_[pos].instr = instr; | 
| array_[pos].next = kNil; | 
| } else { | 
| if (free_list_head_ == kNil) { | 
| @@ -315,9 +320,9 @@ void HValueMap::Insert(HValue* value, Zone* zone) { | 
| int new_element_pos = free_list_head_; | 
| ASSERT(new_element_pos != kNil); | 
| free_list_head_ = lists_[free_list_head_].next; | 
| -    lists_[new_element_pos].value = value; | 
| +    lists_[new_element_pos].instr = instr; | 
| lists_[new_element_pos].next = array_[pos].next; | 
| -    ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].value != NULL); | 
| +    ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].instr != NULL); | 
| array_[pos].next = new_element_pos; | 
| } | 
| } | 
| @@ -341,10 +346,9 @@ HSideEffectMap& HSideEffectMap::operator= (const HSideEffectMap& other) { | 
| } | 
|  | 
|  | 
| -void HSideEffectMap::Kill(GVNFlagSet flags) { | 
| +void HSideEffectMap::Kill(SideEffects side_effects) { | 
| for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { | 
| -    GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); | 
| -    if (flags.Contains(changes_flag)) { | 
| +    if (side_effects.ContainsFlag(GVNFlagFromInt(i))) { | 
| if (data_[i] != NULL) count_--; | 
| data_[i] = NULL; | 
| } | 
| @@ -352,10 +356,9 @@ void HSideEffectMap::Kill(GVNFlagSet flags) { | 
| } | 
|  | 
|  | 
| -void HSideEffectMap::Store(GVNFlagSet flags, HInstruction* instr) { | 
| +void HSideEffectMap::Store(SideEffects side_effects, HInstruction* instr) { | 
| for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { | 
| -    GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); | 
| -    if (flags.Contains(changes_flag)) { | 
| +    if (side_effects.ContainsFlag(GVNFlagFromInt(i))) { | 
| if (data_[i] == NULL) count_++; | 
| data_[i] = instr; | 
| } | 
| @@ -363,6 +366,96 @@ void HSideEffectMap::Store(GVNFlagSet flags, HInstruction* instr) { | 
| } | 
|  | 
|  | 
| +SideEffects SideEffectsTracker::ComputeChanges(HInstruction* instr) { | 
| +  SideEffects result(instr->ChangesFlags()); | 
| +  if (result.ContainsFlag(kInobjectFields)) { | 
| +    int index; | 
| +    if (instr->IsStoreNamedField() && | 
| +        ComputeInobjectField(HStoreNamedField::cast(instr)->access(), &index)) { | 
| +      result.RemoveFlag(kInobjectFields); | 
| +      result.AddSpecial(index); | 
| +    } else { | 
| +      result.AddAllSpecial(); | 
| +    } | 
| +  } | 
| +  return result; | 
| +} | 
| + | 
| + | 
| +SideEffects SideEffectsTracker::ComputeDependsOn(HInstruction* instr) { | 
| +  SideEffects result(instr->DependsOnFlags()); | 
| +  if (result.ContainsFlag(kInobjectFields)) { | 
| +    int index; | 
| +    if (instr->IsLoadNamedField() && | 
| +        ComputeInobjectField(HLoadNamedField::cast(instr)->access(), &index)) { | 
| +      result.RemoveFlag(kInobjectFields); | 
| +      result.AddSpecial(index); | 
| +    } else { | 
| +      result.AddAllSpecial(); | 
| +    } | 
| +  } | 
| +  return result; | 
| +} | 
| + | 
| + | 
| +void SideEffectsTracker::PrintSideEffectsTo(StringStream* stream, | 
| +                                          SideEffects side_effects) const { | 
| +  const char* separator = ""; | 
| +  stream->Add("["); | 
| +  for (int bit = 0; bit < kNumberOfFlags; ++bit) { | 
| +    GVNFlag flag = GVNFlagFromInt(bit); | 
| +    if (side_effects.ContainsFlag(flag)) { | 
| +      stream->Add(separator); | 
| +      separator = ", "; | 
| +      switch (flag) { | 
| +#define DECLARE_FLAG(Type)      \ | 
| +        case k##Type:           \ | 
| +          stream->Add(#Type);   \ | 
| +          break; | 
| +GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) | 
| +GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) | 
| +#undef DECLARE_FLAG | 
| +        default: | 
| +            break; | 
| +      } | 
| +    } | 
| +  } | 
| +  for (int index = 0; index < num_inobject_fields_; ++index) { | 
| +    if (side_effects.ContainsSpecial(index)) { | 
| +      stream->Add(separator); | 
| +      separator = ", "; | 
| +      inobject_fields_[index].PrintTo(stream); | 
| +    } | 
| +  } | 
| +  stream->Add("]"); | 
| +} | 
| + | 
| + | 
| +bool SideEffectsTracker::ComputeInobjectField(HObjectAccess access, | 
| +                                              int* index) { | 
| +  for (int i = 0; i < num_inobject_fields_; ++i) { | 
| +    if (access.Equals(inobject_fields_[i])) { | 
| +      *index = i; | 
| +      return true; | 
| +    } | 
| +  } | 
| +  if (num_inobject_fields_ < SideEffects::kNumberOfSpecials) { | 
| +    if (FLAG_trace_gvn) { | 
| +      HeapStringAllocator allocator; | 
| +      StringStream stream(&allocator); | 
| +      stream.Add("Tracking inobject field access "); | 
| +      access.PrintTo(&stream); | 
| +      stream.Add(" (mapped to special index %d)\n", num_inobject_fields_); | 
| +      stream.OutputToStdOut(); | 
| +    } | 
| +    *index = num_inobject_fields_; | 
| +    inobject_fields_[num_inobject_fields_++] = access; | 
| +    return true; | 
| +  } | 
| +  return false; | 
| +} | 
| + | 
| + | 
| HGlobalValueNumberingPhase::HGlobalValueNumberingPhase(HGraph* graph) | 
| : HPhase("H_Global value numbering", graph), | 
| removed_side_effects_(false), | 
| @@ -370,10 +463,10 @@ HGlobalValueNumberingPhase::HGlobalValueNumberingPhase(HGraph* graph) | 
| loop_side_effects_(graph->blocks()->length(), zone()), | 
| visited_on_paths_(graph->blocks()->length(), zone()) { | 
| ASSERT(!AllowHandleAllocation::IsAllowed()); | 
| -  block_side_effects_.AddBlock(GVNFlagSet(), graph->blocks()->length(), | 
| -                                zone()); | 
| -  loop_side_effects_.AddBlock(GVNFlagSet(), graph->blocks()->length(), | 
| -                              zone()); | 
| +  block_side_effects_.AddBlock( | 
| +      SideEffects(), graph->blocks()->length(), zone()); | 
| +  loop_side_effects_.AddBlock( | 
| +      SideEffects(), graph->blocks()->length(), zone()); | 
| } | 
|  | 
|  | 
| @@ -409,12 +502,12 @@ void HGlobalValueNumberingPhase::ComputeBlockSideEffects() { | 
| for (int i = graph()->blocks()->length() - 1; i >= 0; --i) { | 
| // Compute side effects for the block. | 
| HBasicBlock* block = graph()->blocks()->at(i); | 
| -    GVNFlagSet side_effects; | 
| +    SideEffects side_effects; | 
| if (block->IsReachable() && !block->IsDeoptimizing()) { | 
| int id = block->block_id(); | 
| for (HInstructionIterator it(block); !it.Done(); it.Advance()) { | 
| HInstruction* instr = it.Current(); | 
| -        side_effects.Add(instr->ChangesFlags()); | 
| +        side_effects.Add(side_effects_tracker_.ComputeChanges(instr)); | 
| } | 
| block_side_effects_[id].Add(side_effects); | 
|  | 
| @@ -438,103 +531,22 @@ void HGlobalValueNumberingPhase::ComputeBlockSideEffects() { | 
| } | 
|  | 
|  | 
| -SmartArrayPointer<char> GetGVNFlagsString(GVNFlagSet flags) { | 
| -  char underlying_buffer[kNumberOfFlags * 128]; | 
| -  Vector<char> buffer(underlying_buffer, sizeof(underlying_buffer)); | 
| -#if DEBUG | 
| -  int offset = 0; | 
| -  const char* separator = ""; | 
| -  const char* comma = ", "; | 
| -  buffer[0] = 0; | 
| -  uint32_t set_depends_on = 0; | 
| -  uint32_t set_changes = 0; | 
| -  for (int bit = 0; bit < kNumberOfFlags; ++bit) { | 
| -    if (flags.Contains(static_cast<GVNFlag>(bit))) { | 
| -      if (bit % 2 == 0) { | 
| -        set_changes++; | 
| -      } else { | 
| -        set_depends_on++; | 
| -      } | 
| -    } | 
| -  } | 
| -  bool positive_changes = set_changes < (kNumberOfFlags / 2); | 
| -  bool positive_depends_on = set_depends_on < (kNumberOfFlags / 2); | 
| -  if (set_changes > 0) { | 
| -    if (positive_changes) { | 
| -      offset += OS::SNPrintF(buffer + offset, "changes ["); | 
| -    } else { | 
| -      offset += OS::SNPrintF(buffer + offset, "changes all except ["); | 
| -    } | 
| -    for (int bit = 0; bit < kNumberOfFlags; ++bit) { | 
| -      if (flags.Contains(static_cast<GVNFlag>(bit)) == positive_changes) { | 
| -        switch (static_cast<GVNFlag>(bit)) { | 
| -#define DECLARE_FLAG(type)                                       \ | 
| -          case kChanges##type:                                   \ | 
| -            offset += OS::SNPrintF(buffer + offset, separator);  \ | 
| -            offset += OS::SNPrintF(buffer + offset, #type);      \ | 
| -            separator = comma;                                   \ | 
| -            break; | 
| -GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) | 
| -GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) | 
| -#undef DECLARE_FLAG | 
| -          default: | 
| -              break; | 
| -        } | 
| -      } | 
| -    } | 
| -    offset += OS::SNPrintF(buffer + offset, "]"); | 
| -  } | 
| -  if (set_depends_on > 0) { | 
| -    separator = ""; | 
| -    if (set_changes > 0) { | 
| -      offset += OS::SNPrintF(buffer + offset, ", "); | 
| -    } | 
| -    if (positive_depends_on) { | 
| -      offset += OS::SNPrintF(buffer + offset, "depends on ["); | 
| -    } else { | 
| -      offset += OS::SNPrintF(buffer + offset, "depends on all except ["); | 
| -    } | 
| -    for (int bit = 0; bit < kNumberOfFlags; ++bit) { | 
| -      if (flags.Contains(static_cast<GVNFlag>(bit)) == positive_depends_on) { | 
| -        switch (static_cast<GVNFlag>(bit)) { | 
| -#define DECLARE_FLAG(type)                                       \ | 
| -          case kDependsOn##type:                                 \ | 
| -            offset += OS::SNPrintF(buffer + offset, separator);  \ | 
| -            offset += OS::SNPrintF(buffer + offset, #type);      \ | 
| -            separator = comma;                                   \ | 
| -            break; | 
| -GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) | 
| -GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) | 
| -#undef DECLARE_FLAG | 
| -          default: | 
| -            break; | 
| -        } | 
| -      } | 
| -    } | 
| -    offset += OS::SNPrintF(buffer + offset, "]"); | 
| -  } | 
| -#else | 
| -  OS::SNPrintF(buffer, "0x%08X", flags.ToIntegral()); | 
| -#endif | 
| -  size_t string_len = strlen(underlying_buffer) + 1; | 
| -  ASSERT(string_len <= sizeof(underlying_buffer)); | 
| -  char* result = new char[strlen(underlying_buffer) + 1]; | 
| -  OS::MemCopy(result, underlying_buffer, string_len); | 
| -  return SmartArrayPointer<char>(result); | 
| -} | 
| - | 
| - | 
| void HGlobalValueNumberingPhase::LoopInvariantCodeMotion() { | 
| TRACE_GVN_1("Using optimistic loop invariant code motion: %s\n", | 
| graph()->use_optimistic_licm() ? "yes" : "no"); | 
| for (int i = graph()->blocks()->length() - 1; i >= 0; --i) { | 
| HBasicBlock* block = graph()->blocks()->at(i); | 
| if (block->IsLoopHeader()) { | 
| -      GVNFlagSet side_effects = loop_side_effects_[block->block_id()]; | 
| -      TRACE_GVN_2("Try loop invariant motion for block B%d %s\n", | 
| -                  block->block_id(), | 
| -                  GetGVNFlagsString(side_effects).get()); | 
| - | 
| +      SideEffects side_effects = loop_side_effects_[block->block_id()]; | 
| +      if (FLAG_trace_gvn) { | 
| +        HeapStringAllocator allocator; | 
| +        StringStream stream(&allocator); | 
| +        stream.Add("Try loop invariant motion for block B%d changes ", | 
| +                   block->block_id()); | 
| +        side_effects_tracker_.PrintSideEffectsTo(&stream, side_effects); | 
| +        stream.Add("\n"); | 
| +        stream.OutputToStdOut(); | 
| +      } | 
| HBasicBlock* last = block->loop_information()->GetLastBackEdge(); | 
| for (int j = block->block_id(); j <= last->block_id(); ++j) { | 
| ProcessLoopBlock(graph()->blocks()->at(j), block, side_effects); | 
| @@ -547,22 +559,37 @@ void HGlobalValueNumberingPhase::LoopInvariantCodeMotion() { | 
| void HGlobalValueNumberingPhase::ProcessLoopBlock( | 
| HBasicBlock* block, | 
| HBasicBlock* loop_header, | 
| -    GVNFlagSet loop_kills) { | 
| +    SideEffects loop_kills) { | 
| HBasicBlock* pre_header = loop_header->predecessors()->at(0); | 
| -  GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); | 
| -  TRACE_GVN_2("Loop invariant motion for B%d %s\n", | 
| -              block->block_id(), | 
| -              GetGVNFlagsString(depends_flags).get()); | 
| +  if (FLAG_trace_gvn) { | 
| +    HeapStringAllocator allocator; | 
| +    StringStream stream(&allocator); | 
| +    stream.Add("Loop invariant code motion for B%d depends on ", | 
| +               block->block_id()); | 
| +    side_effects_tracker_.PrintSideEffectsTo(&stream, loop_kills); | 
| +    stream.Add("\n"); | 
| +    stream.OutputToStdOut(); | 
| +  } | 
| HInstruction* instr = block->first(); | 
| while (instr != NULL) { | 
| HInstruction* next = instr->next(); | 
| if (instr->CheckFlag(HValue::kUseGVN)) { | 
| -      TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n", | 
| -                  instr->id(), | 
| -                  instr->Mnemonic(), | 
| -                  GetGVNFlagsString(instr->gvn_flags()).get(), | 
| -                  GetGVNFlagsString(loop_kills).get()); | 
| -      bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); | 
| +      SideEffects changes = side_effects_tracker_.ComputeChanges(instr); | 
| +      SideEffects depends_on = side_effects_tracker_.ComputeDependsOn(instr); | 
| +      if (FLAG_trace_gvn) { | 
| +        HeapStringAllocator allocator; | 
| +        StringStream stream(&allocator); | 
| +        stream.Add("Checking instruction i%d (%s) changes ", | 
| +                   instr->id(), instr->Mnemonic()); | 
| +        side_effects_tracker_.PrintSideEffectsTo(&stream, changes); | 
| +        stream.Add(", depends on "); | 
| +        side_effects_tracker_.PrintSideEffectsTo(&stream, depends_on); | 
| +        stream.Add(". Loop changes "); | 
| +        side_effects_tracker_.PrintSideEffectsTo(&stream, loop_kills); | 
| +        stream.Add("\n"); | 
| +        stream.OutputToStdOut(); | 
| +      } | 
| +      bool can_hoist = !depends_on.ContainsAnyOf(loop_kills); | 
| if (can_hoist && !graph()->use_optimistic_licm()) { | 
| can_hoist = block->IsLoopSuccessorDominator(); | 
| } | 
| @@ -604,10 +631,10 @@ bool HGlobalValueNumberingPhase::ShouldMove(HInstruction* instr, | 
| } | 
|  | 
|  | 
| -GVNFlagSet | 
| +SideEffects | 
| HGlobalValueNumberingPhase::CollectSideEffectsOnPathsToDominatedBlock( | 
| HBasicBlock* dominator, HBasicBlock* dominated) { | 
| -  GVNFlagSet side_effects; | 
| +  SideEffects side_effects; | 
| for (int i = 0; i < dominated->predecessors()->length(); ++i) { | 
| HBasicBlock* block = dominated->predecessors()->at(i); | 
| if (dominator->block_id() < block->block_id() && | 
| @@ -636,13 +663,13 @@ class GvnBasicBlockState: public ZoneObject { | 
| public: | 
| static GvnBasicBlockState* CreateEntry(Zone* zone, | 
| HBasicBlock* entry_block, | 
| -                                         HValueMap* entry_map) { | 
| +                                         HInstructionMap* entry_map) { | 
| return new(zone) | 
| GvnBasicBlockState(NULL, entry_block, entry_map, NULL, zone); | 
| } | 
|  | 
| HBasicBlock* block() { return block_; } | 
| -  HValueMap* map() { return map_; } | 
| +  HInstructionMap* map() { return map_; } | 
| HSideEffectMap* dominators() { return &dominators_; } | 
|  | 
| GvnBasicBlockState* next_in_dominator_tree_traversal( | 
| @@ -669,7 +696,7 @@ class GvnBasicBlockState: public ZoneObject { | 
|  | 
| private: | 
| void Initialize(HBasicBlock* block, | 
| -                  HValueMap* map, | 
| +                  HInstructionMap* map, | 
| HSideEffectMap* dominators, | 
| bool copy_map, | 
| Zone* zone) { | 
| @@ -685,7 +712,7 @@ class GvnBasicBlockState: public ZoneObject { | 
|  | 
| GvnBasicBlockState(GvnBasicBlockState* previous, | 
| HBasicBlock* block, | 
| -                     HValueMap* map, | 
| +                     HInstructionMap* map, | 
| HSideEffectMap* dominators, | 
| Zone* zone) | 
| : previous_(previous), next_(NULL) { | 
| @@ -732,7 +759,7 @@ class GvnBasicBlockState: public ZoneObject { | 
| GvnBasicBlockState* previous_; | 
| GvnBasicBlockState* next_; | 
| HBasicBlock* block_; | 
| -  HValueMap* map_; | 
| +  HInstructionMap* map_; | 
| HSideEffectMap dominators_; | 
| int dominated_index_; | 
| int length_; | 
| @@ -745,13 +772,14 @@ class GvnBasicBlockState: public ZoneObject { | 
| // GvnBasicBlockState instances. | 
| void HGlobalValueNumberingPhase::AnalyzeGraph() { | 
| HBasicBlock* entry_block = graph()->entry_block(); | 
| -  HValueMap* entry_map = new(zone()) HValueMap(zone()); | 
| +  HInstructionMap* entry_map = | 
| +      new(zone()) HInstructionMap(zone(), &side_effects_tracker_); | 
| GvnBasicBlockState* current = | 
| GvnBasicBlockState::CreateEntry(zone(), entry_block, entry_map); | 
|  | 
| while (current != NULL) { | 
| HBasicBlock* block = current->block(); | 
| -    HValueMap* map = current->map(); | 
| +    HInstructionMap* map = current->map(); | 
| HSideEffectMap* dominators = current->dominators(); | 
|  | 
| TRACE_GVN_2("Analyzing block B%d%s\n", | 
| @@ -770,17 +798,15 @@ void HGlobalValueNumberingPhase::AnalyzeGraph() { | 
| if (instr->CheckFlag(HValue::kTrackSideEffectDominators)) { | 
| for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { | 
| HValue* other = dominators->at(i); | 
| -          GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); | 
| -          GVNFlag depends_on_flag = HValue::DependsOnFlagFromInt(i); | 
| -          if (instr->DependsOnFlags().Contains(depends_on_flag) && | 
| -              (other != NULL)) { | 
| +          GVNFlag flag = GVNFlagFromInt(i); | 
| +          if (instr->DependsOnFlags().Contains(flag) && other != NULL) { | 
| TRACE_GVN_5("Side-effect #%d in %d (%s) is dominated by %d (%s)\n", | 
| i, | 
| instr->id(), | 
| instr->Mnemonic(), | 
| other->id(), | 
| other->Mnemonic()); | 
| -            if (instr->HandleSideEffectDominator(changes_flag, other)) { | 
| +            if (instr->HandleSideEffectDominator(flag, other)) { | 
| removed_side_effects_ = true; | 
| } | 
| } | 
| @@ -789,21 +815,27 @@ void HGlobalValueNumberingPhase::AnalyzeGraph() { | 
| // Instruction was unlinked during graph traversal. | 
| if (!instr->IsLinked()) continue; | 
|  | 
| -      GVNFlagSet flags = instr->ChangesFlags(); | 
| -      if (!flags.IsEmpty()) { | 
| +      SideEffects changes = side_effects_tracker_.ComputeChanges(instr); | 
| +      if (!changes.IsEmpty()) { | 
| // Clear all instructions in the map that are affected by side effects. | 
| // Store instruction as the dominating one for tracked side effects. | 
| -        map->Kill(flags); | 
| -        dominators->Store(flags, instr); | 
| -        TRACE_GVN_2("Instruction %d %s\n", instr->id(), | 
| -                    GetGVNFlagsString(flags).get()); | 
| +        map->Kill(changes); | 
| +        dominators->Store(changes, instr); | 
| +        if (FLAG_trace_gvn) { | 
| +          HeapStringAllocator allocator; | 
| +          StringStream stream(&allocator); | 
| +          stream.Add("Instruction i%d changes ", instr->id()); | 
| +          side_effects_tracker_.PrintSideEffectsTo(&stream, changes); | 
| +          stream.Add("\n"); | 
| +          stream.OutputToStdOut(); | 
| +        } | 
| } | 
| if (instr->CheckFlag(HValue::kUseGVN)) { | 
| ASSERT(!instr->HasObservableSideEffects()); | 
| -        HValue* other = map->Lookup(instr); | 
| +        HInstruction* other = map->Lookup(instr); | 
| if (other != NULL) { | 
| ASSERT(instr->Equals(other) && other->Equals(instr)); | 
| -          TRACE_GVN_4("Replacing value %d (%s) with value %d (%s)\n", | 
| +          TRACE_GVN_4("Replacing instruction i%d (%s) with i%d (%s)\n", | 
| instr->id(), | 
| instr->Mnemonic(), | 
| other->id(), | 
| @@ -823,7 +855,7 @@ void HGlobalValueNumberingPhase::AnalyzeGraph() { | 
|  | 
| if (next != NULL) { | 
| HBasicBlock* dominated = next->block(); | 
| -      HValueMap* successor_map = next->map(); | 
| +      HInstructionMap* successor_map = next->map(); | 
| HSideEffectMap* successor_dominators = next->dominators(); | 
|  | 
| // Kill everything killed on any path between this block and the | 
| @@ -834,7 +866,7 @@ void HGlobalValueNumberingPhase::AnalyzeGraph() { | 
| if ((!successor_map->IsEmpty() || !successor_dominators->IsEmpty()) && | 
| dominator_block->block_id() + 1 < dominated->block_id()) { | 
| visited_on_paths_.Clear(); | 
| -        GVNFlagSet side_effects_on_all_paths = | 
| +        SideEffects side_effects_on_all_paths = | 
| CollectSideEffectsOnPathsToDominatedBlock(dominator_block, | 
| dominated); | 
| successor_map->Kill(side_effects_on_all_paths); | 
|  |