Handle HCheckInstanceType and HIsStringAndBranch in check elimination.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Jun 2014 12:17:05 +0000 (12:17 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Jun 2014 12:17:05 +0000 (12:17 +0000)
R=ishell@chromium.org

Committed: https://code.google.com/p/v8/source/detail?r=21593

Review URL: https://codereview.chromium.org/300423003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21606 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/hydrogen-check-elimination.cc
src/hydrogen-check-elimination.h
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/unique.h

index 506a045..d971381 100644 (file)
@@ -104,6 +104,10 @@ class HCheckTable : public ZoneObject {
         ReduceCompareObjectEqAndBranch(HCompareObjectEqAndBranch::cast(instr));
         break;
       }
+      case HValue::kIsStringAndBranch: {
+        ReduceIsStringAndBranch(HIsStringAndBranch::cast(instr));
+        break;
+      }
       case HValue::kTransitionElementsKind: {
         ReduceTransitionElementsKind(
             HTransitionElementsKind::cast(instr));
@@ -113,6 +117,10 @@ class HCheckTable : public ZoneObject {
         ReduceCheckHeapObject(HCheckHeapObject::cast(instr));
         break;
       }
+      case HValue::kCheckInstanceType: {
+        ReduceCheckInstanceType(HCheckInstanceType::cast(instr));
+        break;
+      }
       default: {
         // If the instruction changes maps uncontrollably, drop everything.
         if (instr->CheckChangesFlag(kOsrEntries)) {
@@ -125,7 +133,7 @@ class HCheckTable : public ZoneObject {
         }
       }
       // Improvements possible:
-      // - eliminate redundant HCheckSmi, HCheckInstanceType instructions
+      // - eliminate redundant HCheckSmi instructions
       // - track which values have been HCheckHeapObject'd
     }
 
@@ -261,6 +269,28 @@ class HCheckTable : public ZoneObject {
           ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, re->state_);
         }
         learned = true;
+      } else if (end->IsIsStringAndBranch()) {
+        HIsStringAndBranch* cmp = HIsStringAndBranch::cast(end);
+        HValue* object = cmp->value()->ActualValue();
+        HCheckTableEntry* entry = copy->Find(object);
+        if (is_true_branch) {
+          // Learn on the true branch of if(IsString(x)).
+          if (entry == NULL) {
+            copy->Insert(object, NULL, string_maps(),
+                         HCheckTableEntry::CHECKED);
+          } else {
+            EnsureChecked(entry, object, cmp);
+            entry->maps_ = entry->maps_->Intersect(string_maps(), zone);
+            ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, entry->state_);
+          }
+        } else {
+          // Learn on the false branch of if(IsString(x)).
+          if (entry != NULL) {
+            EnsureChecked(entry, object, cmp);
+            entry->maps_ = entry->maps_->Subtract(string_maps(), zone);
+            ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, entry->state_);
+          }
+        }
       }
       // Learning on false branches requires storing negative facts.
     }
@@ -415,6 +445,50 @@ class HCheckTable : public ZoneObject {
     }
   }
 
+  void ReduceCheckInstanceType(HCheckInstanceType* instr) {
+    HValue* value = instr->value()->ActualValue();
+    HCheckTableEntry* entry = Find(value);
+    if (entry == NULL) {
+      if (instr->check() == HCheckInstanceType::IS_STRING) {
+        Insert(value, NULL, string_maps(), HCheckTableEntry::CHECKED);
+      }
+      return;
+    }
+    UniqueSet<Map>* maps = new(zone()) UniqueSet<Map>(
+        entry->maps_->size(), zone());
+    for (int i = 0; i < entry->maps_->size(); ++i) {
+      InstanceType type;
+      Unique<Map> map = entry->maps_->at(i);
+      {
+        // This is safe, because maps don't move and their instance type does
+        // not change.
+        AllowHandleDereference allow_deref;
+        type = map.handle()->instance_type();
+      }
+      if (instr->is_interval_check()) {
+        InstanceType first_type, last_type;
+        instr->GetCheckInterval(&first_type, &last_type);
+        if (first_type <= type && type <= last_type) maps->Add(map, zone());
+      } else {
+        uint8_t mask, tag;
+        instr->GetCheckMaskAndTag(&mask, &tag);
+        if ((type & mask) == tag) maps->Add(map, zone());
+      }
+    }
+    if (maps->size() == entry->maps_->size()) {
+      TRACE(("Removing redundant CheckInstanceType #%d at B%d\n",
+              instr->id(), instr->block()->block_id()));
+      EnsureChecked(entry, value, instr);
+      instr->DeleteAndReplaceWith(value);
+      INC_STAT(removed_cit_);
+    } else if (maps->size() != 0) {
+      entry->maps_ = maps;
+      if (entry->state_ == HCheckTableEntry::UNCHECKED_STABLE) {
+        entry->state_ = HCheckTableEntry::CHECKED_STABLE;
+      }
+    }
+  }
+
   void ReduceLoadNamedField(HLoadNamedField* instr) {
     // Reduce a load of the map field when it is known to be a constant.
     if (!instr->access().IsMap()) {
@@ -528,6 +602,28 @@ class HCheckTable : public ZoneObject {
     instr->block()->MarkSuccEdgeUnreachable(unreachable_succ);
   }
 
+  void ReduceIsStringAndBranch(HIsStringAndBranch* instr) {
+    HValue* value = instr->value()->ActualValue();
+    HCheckTableEntry* entry = Find(value);
+    if (entry == NULL) return;
+    EnsureChecked(entry, value, instr);
+    int succ;
+    if (entry->maps_->IsSubset(string_maps())) {
+      TRACE(("Marking redundant IsStringAndBranch #%d at B%d as true\n",
+             instr->id(), instr->block()->block_id()));
+      succ = 0;
+    } else {
+      MapSet intersection = entry->maps_->Intersect(string_maps(), zone());
+      if (intersection->size() > 0) return;
+      TRACE(("Marking redundant IsStringAndBranch #%d at B%d as false\n",
+            instr->id(), instr->block()->block_id()));
+      succ = 1;
+    }
+    instr->set_known_successor_index(succ);
+    int unreachable_succ = 1 - succ;
+    instr->block()->MarkSuccEdgeUnreachable(unreachable_succ);
+  }
+
   void ReduceTransitionElementsKind(HTransitionElementsKind* instr) {
     HValue* object = instr->object()->ActualValue();
     HCheckTableEntry* entry = Find(object);
@@ -688,6 +784,7 @@ class HCheckTable : public ZoneObject {
   }
 
   Zone* zone() const { return phase_->zone(); }
+  MapSet string_maps() const { return phase_->string_maps(); }
 
   friend class HCheckMapsEffects;
   friend class HCheckEliminationPhase;
@@ -794,6 +891,7 @@ void HCheckEliminationPhase::PrintStats() {
   PRINT_STAT(redundant);
   PRINT_STAT(removed);
   PRINT_STAT(removed_cho);
+  PRINT_STAT(removed_cit);
   PRINT_STAT(narrowed);
   PRINT_STAT(loads);
   PRINT_STAT(empty);
index b38447b..9f3b198 100644 (file)
@@ -16,11 +16,20 @@ namespace internal {
 class HCheckEliminationPhase : public HPhase {
  public:
   explicit HCheckEliminationPhase(HGraph* graph)
-      : HPhase("H_Check Elimination", graph), aliasing_() {
+      : HPhase("H_Check Elimination", graph), aliasing_(),
+        string_maps_(kStringMapsSize, zone()) {
+    // Compute the set of string maps.
+    #define ADD_STRING_MAP(type, size, name, Name)                  \
+      string_maps_.Add(Unique<Map>::CreateImmovable(                \
+              graph->isolate()->factory()->name##_map()), zone());
+    STRING_TYPE_LIST(ADD_STRING_MAP)
+    #undef ADD_STRING_MAP
+    ASSERT_EQ(kStringMapsSize, string_maps_.size());
 #ifdef DEBUG
     redundant_ = 0;
     removed_ = 0;
     removed_cho_ = 0;
+    removed_cit_ = 0;
     narrowed_ = 0;
     loads_ = 0;
     empty_ = 0;
@@ -35,13 +44,20 @@ class HCheckEliminationPhase : public HPhase {
   friend class HCheckTable;
 
  private:
+  const UniqueSet<Map>* string_maps() const { return &string_maps_; }
+
   void PrintStats();
 
   HAliasAnalyzer* aliasing_;
+  #define COUNT(type, size, name, Name) + 1
+  static const int kStringMapsSize = 0 STRING_TYPE_LIST(COUNT);
+  #undef COUNT
+  UniqueSet<Map> string_maps_;
 #ifdef DEBUG
   int redundant_;
   int removed_;
   int removed_cho_;
+  int removed_cit_;
   int narrowed_;
   int loads_;
   int empty_;
index 6303cd1..e7ef516 100644 (file)
@@ -3256,11 +3256,27 @@ bool HIsObjectAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
 
 
 bool HIsStringAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
+  if (known_successor_index() != kNoKnownSuccessorIndex) {
+    *block = SuccessorAt(known_successor_index());
+    return true;
+  }
   if (FLAG_fold_constants && value()->IsConstant()) {
     *block = HConstant::cast(value())->HasStringValue()
         ? FirstSuccessor() : SecondSuccessor();
     return true;
   }
+  if (value()->type().IsString()) {
+    *block = FirstSuccessor();
+    return true;
+  }
+  if (value()->type().IsSmi() ||
+      value()->type().IsNull() ||
+      value()->type().IsBoolean() ||
+      value()->type().IsUndefined() ||
+      value()->type().IsJSObject()) {
+    *block = SecondSuccessor();
+    return true;
+  }
   *block = NULL;
   return false;
 }
index d413af0..01bd32b 100644 (file)
@@ -2909,6 +2909,8 @@ class HCheckInstanceType V8_FINAL : public HUnaryOperation {
   void GetCheckInterval(InstanceType* first, InstanceType* last);
   void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
 
+  Check check() const { return check_; }
+
   DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
 
  protected:
@@ -4425,6 +4427,12 @@ class HIsStringAndBranch V8_FINAL : public HUnaryControlInstruction {
 
   virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
 
+  static const int kNoKnownSuccessorIndex = -1;
+  int known_successor_index() const { return known_successor_index_; }
+  void set_known_successor_index(int known_successor_index) {
+    known_successor_index_ = known_successor_index;
+  }
+
   DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
 
  protected:
@@ -4434,7 +4442,10 @@ class HIsStringAndBranch V8_FINAL : public HUnaryControlInstruction {
   HIsStringAndBranch(HValue* value,
                      HBasicBlock* true_target = NULL,
                      HBasicBlock* false_target = NULL)
-    : HUnaryControlInstruction(value, true_target, false_target) {}
+    : HUnaryControlInstruction(value, true_target, false_target),
+      known_successor_index_(kNoKnownSuccessorIndex) { }
+
+  int known_successor_index_;
 };
 
 
index 8ed2682..370ee49 100644 (file)
@@ -275,6 +275,26 @@ class UniqueSet V8_FINAL : public ZoneObject {
     return out;
   }
 
+  // Returns a new set representing all elements from this set which are not in
+  // that set. O(|this| * |that|).
+  UniqueSet<T>* Subtract(const UniqueSet<T>* that, Zone* zone) const {
+    if (that->size_ == 0) return this->Copy(zone);
+
+    UniqueSet<T>* out = new(zone) UniqueSet<T>(this->size_, zone);
+
+    int i = 0, j = 0;
+    while (i < this->size_) {
+      Unique<T> cand = this->array_[i];
+      if (!that->Contains(cand)) {
+        out->array_[j++] = cand;
+      }
+      i++;
+    }
+
+    out->size_ = j;
+    return out;
+  }
+
   // Makes an exact copy of this set. O(|this|).
   UniqueSet<T>* Copy(Zone* zone) const {
     UniqueSet<T>* copy = new(zone) UniqueSet<T>(this->size_, zone);