Revision: 11270
Author:   [email protected]
Date:     Wed Apr 11 03:56:16 2012
Log:      Remove write-barriers for stores to new-space objects.

This change allows hydrogen instructions to keep track of instructions
that dominate certain side-effects (GVN flags) in the hydrogen graph. We
use the GVN pass to keep track of side-effects because accurate flags
are already in place.

It also adds a new side-effect (kChangesNewSpacePromotion) indicating
whether an instruction can cause a GC and have objects be promoted to
old-space. An object allocated in new-space is sure to stay on paths not
having said side-effect.

[email protected]
TEST=mjsunit/compiler/inline-construct

Review URL: https://chromiumcodereview.appspot.com/10031031
http://code.google.com/p/v8/source/detail?r=11270

Modified:
 /branches/bleeding_edge/src/hydrogen-instructions.cc
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/hydrogen.h

=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Fri Mar 23 09:37:54 2012 +++ /branches/bleeding_edge/src/hydrogen-instructions.cc Wed Apr 11 03:56:16 2012
@@ -462,7 +462,8 @@
       add_comma = true;                           \
       stream->Add(#type);                         \
     }
-    GVN_FLAG_LIST(PRINT_DO);
+    GVN_TRACKED_FLAG_LIST(PRINT_DO);
+    GVN_UNTRACKED_FLAG_LIST(PRINT_DO);
 #undef PRINT_DO
   }
   stream->Add("]");
@@ -1733,6 +1734,9 @@
   stream->Add(" = ");
   value()->PrintNameTo(stream);
   stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
+  if (NeedsWriteBarrier()) {
+    stream->Add(" (write-barrier)");
+  }
   if (!transition().is_null()) {
     stream->Add(" (transition map %p)", *transition());
   }
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Thu Apr 5 08:36:31 2012 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Wed Apr 11 03:56:16 2012
@@ -188,7 +188,10 @@
   V(DateField)                                 \
   V(WrapReceiver)

-#define GVN_FLAG_LIST(V)                       \
+#define GVN_TRACKED_FLAG_LIST(V)               \
+  V(NewSpacePromotion)
+
+#define GVN_UNTRACKED_FLAG_LIST(V)             \
   V(Calls)                                     \
   V(InobjectFields)                            \
   V(BackingStoreFields)                        \
@@ -506,14 +509,18 @@

// There must be one corresponding kDepends flag for every kChanges flag and // the order of the kChanges flags must be exactly the same as of the kDepends
-// flags.
+// flags. All tracked flags should appear before untracked ones.
 enum GVNFlag {
   // Declare global value numbering flags.
 #define DECLARE_FLAG(type) kChanges##type, kDependsOn##type,
-  GVN_FLAG_LIST(DECLARE_FLAG)
+  GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
+  GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
 #undef DECLARE_FLAG
   kAfterLastFlag,
-  kLastFlag = kAfterLastFlag - 1
+  kLastFlag = kAfterLastFlag - 1,
+#define COUNT_FLAG(type) + 1
+  kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG)
+#undef COUNT_FLAG
 };

 typedef EnumSet<GVNFlag> GVNFlagSet;
@@ -530,6 +537,10 @@
     // implement DataEquals(), which will be used to determine if other
     // occurrences of the instruction are indeed the same.
     kUseGVN,
+ // Track instructions that are dominating side effects. If an instruction + // sets this flag, it must implement SetSideEffectDominator() and should
+    // indicate which side effects to track by setting GVN flags.
+    kTrackSideEffectDominators,
     kCanOverflow,
     kBailoutOnMinusZero,
     kCanBeDivByZero,
@@ -544,6 +555,12 @@

   static const int kChangesToDependsFlagsLeftShift = 1;

+  static GVNFlag ChangesFlagFromInt(int x) {
+    return static_cast<GVNFlag>(x * 2);
+  }
+  static GVNFlag DependsOnFlagFromInt(int x) {
+    return static_cast<GVNFlag>(x * 2 + 1);
+  }
   static GVNFlagSet ConvertChangesToDependsFlags(GVNFlagSet flags) {
return GVNFlagSet(flags.ToIntegral() << kChangesToDependsFlagsLeftShift);
   }
@@ -725,6 +742,13 @@
   bool UpdateInferredType();

   virtual HType CalculateInferredType();
+
+  // This function must be overridden for instructions which have the
+  // kTrackSideEffectDominators flag set, to track instructions that are
+  // dominating side effects.
+ virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) {
+    UNREACHABLE();
+  }

 #ifdef DEBUG
   virtual void Verify() = 0;
@@ -756,7 +780,8 @@
     GVNFlagSet result;
     // Create changes mask.
 #define ADD_FLAG(type) result.Add(kDependsOn##type);
-  GVN_FLAG_LIST(ADD_FLAG)
+  GVN_TRACKED_FLAG_LIST(ADD_FLAG)
+  GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
 #undef ADD_FLAG
     return result;
   }
@@ -765,7 +790,8 @@
     GVNFlagSet result;
     // Create changes mask.
 #define ADD_FLAG(type) result.Add(kChanges##type);
-  GVN_FLAG_LIST(ADD_FLAG)
+  GVN_TRACKED_FLAG_LIST(ADD_FLAG)
+  GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
 #undef ADD_FLAG
     return result;
   }
@@ -781,6 +807,7 @@
   // an executing program (i.e. are not safe to repeat, move or remove);
   static GVNFlagSet AllObservableSideEffectsFlagSet() {
     GVNFlagSet result = AllChangesFlagSet();
+    result.Remove(kChangesNewSpacePromotion);
     result.Remove(kChangesElementsKind);
     result.Remove(kChangesElementsPointer);
     result.Remove(kChangesMaps);
@@ -3555,6 +3582,12 @@
       && !value->type().IsSmi()
&& !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
 }
+
+
+inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
+                                            HValue* new_space_dominator) {
+  return !object->IsAllocateObject() || (object != new_space_dominator);
+}


 class HStoreGlobalCell: public HUnaryOperation {
@@ -4023,9 +4056,12 @@
                    int offset)
       : name_(name),
         is_in_object_(in_object),
-        offset_(offset) {
+        offset_(offset),
+        new_space_dominator_(NULL) {
     SetOperandAt(0, obj);
     SetOperandAt(1, val);
+    SetFlag(kTrackSideEffectDominators);
+    SetGVNFlag(kDependsOnNewSpacePromotion);
     if (is_in_object_) {
       SetGVNFlag(kChangesInobjectFields);
     } else {
@@ -4038,6 +4074,10 @@
   virtual Representation RequiredInputRepresentation(int index) {
     return Representation::Tagged();
   }
+ virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) {
+    ASSERT(side_effect == kChangesNewSpacePromotion);
+    new_space_dominator_ = dominator;
+  }
   virtual void PrintDataTo(StringStream* stream);

   HValue* object() { return OperandAt(0); }
@@ -4048,9 +4088,11 @@
   int offset() const { return offset_; }
   Handle<Map> transition() const { return transition_; }
   void set_transition(Handle<Map> map) { transition_ = map; }
+  HValue* new_space_dominator() const { return new_space_dominator_; }

   bool NeedsWriteBarrier() {
-    return StoringValueNeedsWriteBarrier(value());
+    return StoringValueNeedsWriteBarrier(value()) &&
+        ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator());
   }

  private:
@@ -4058,6 +4100,7 @@
   bool is_in_object_;
   int offset_;
   Handle<Map> transition_;
+  HValue* new_space_dominator_;
 };


@@ -4404,6 +4447,7 @@
       : constructor_(constructor) {
     SetOperandAt(0, context);
     set_representation(Representation::Tagged());
+    SetGVNFlag(kChangesNewSpacePromotion);
   }

   // Maximum instance size for which allocations will be inlined.
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Tue Apr 10 06:41:00 2012
+++ /branches/bleeding_edge/src/hydrogen.cc     Wed Apr 11 03:56:16 2012
@@ -1319,6 +1319,38 @@
     array_[pos].next = new_element_pos;
   }
 }
+
+
+HSideEffectMap::HSideEffectMap() : count_(0) {
+  memset(data_, 0, kNumberOfTrackedSideEffects * kPointerSize);
+}
+
+
+HSideEffectMap::HSideEffectMap(HSideEffectMap* other) : count_(other->count_) {
+  memcpy(data_, other->data_, kNumberOfTrackedSideEffects * kPointerSize);
+}
+
+
+void HSideEffectMap::Kill(GVNFlagSet flags) {
+  for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
+    GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
+    if (flags.Contains(changes_flag)) {
+      if (data_[i] != NULL) count_--;
+      data_[i] = NULL;
+    }
+  }
+}
+
+
+void HSideEffectMap::Store(GVNFlagSet flags, HInstruction* instr) {
+  for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
+    GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
+    if (flags.Contains(changes_flag)) {
+      if (data_[i] == NULL) count_++;
+      data_[i] = instr;
+    }
+  }
+}


 class HStackCheckEliminator BASE_EMBEDDED {
@@ -1427,7 +1459,9 @@
   GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock(
       HBasicBlock* dominator,
       HBasicBlock* dominated);
-  void AnalyzeBlock(HBasicBlock* block, HValueMap* map);
+  void AnalyzeBlock(HBasicBlock* block,
+                    HValueMap* map,
+                    HSideEffectMap* dominators);
   void ComputeBlockSideEffects();
   void LoopInvariantCodeMotion();
   void ProcessLoopBlock(HBasicBlock* block,
@@ -1465,7 +1499,8 @@
     LoopInvariantCodeMotion();
   }
   HValueMap* map = new(zone()) HValueMap();
-  AnalyzeBlock(graph_->entry_block(), map);
+  HSideEffectMap side_effect_dominators;
+  AnalyzeBlock(graph_->entry_block(), map, &side_effect_dominators);
   return removed_side_effects_;
 }

@@ -1660,7 +1695,9 @@
 }


-void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
+void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block,
+                                        HValueMap* map,
+                                        HSideEffectMap* dominators) {
   TraceGVN("Analyzing block B%d%s\n",
            block->block_id(),
            block->IsLoopHeader() ? " (loop header)" : "");
@@ -1677,7 +1714,9 @@
     GVNFlagSet flags = instr->ChangesFlags();
     if (!flags.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);
       TraceGVN("Instruction %d kills\n", instr->id());
     }
     if (instr->CheckFlag(HValue::kUseGVN)) {
@@ -1696,6 +1735,23 @@
         map->Add(instr);
       }
     }
+    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)) {
+          TraceGVN("Side-effect #%d in %d (%s) is dominated by %d (%s)\n",
+                   i,
+                   instr->id(),
+                   instr->Mnemonic(),
+                   other->id(),
+                   other->Mnemonic());
+          instr->SetSideEffectDominator(changes_flag, other);
+        }
+      }
+    }
     instr = next;
   }

@@ -1705,20 +1761,22 @@
     HBasicBlock* dominated = block->dominated_blocks()->at(i);
     // No need to copy the map for the last child in the dominator tree.
     HValueMap* successor_map = (i == length - 1) ? map : map->Copy(zone());
+    HSideEffectMap successor_dominators(dominators);

     // Kill everything killed on any path between this block and the
-    // dominated block.
-    // We don't have to traverse these paths if the value map is
-    // already empty.
-    // If the range of block ids (block_id, dominated_id) is empty
-    // there are no such paths.
-    if (!successor_map->IsEmpty() &&
+    // dominated block.  We don't have to traverse these paths if the
+    // value map and the dominators list is already empty.  If the range
+    // of block ids (block_id, dominated_id) is empty there are no such
+    // paths.
+    if ((!successor_map->IsEmpty() || !successor_dominators.IsEmpty()) &&
         block->block_id() + 1 < dominated->block_id()) {
       visited_on_paths_.Clear();
-      successor_map->Kill(CollectSideEffectsOnPathsToDominatedBlock(block,
- dominated));
-    }
-    AnalyzeBlock(dominated, successor_map);
+      GVNFlagSet side_effects_on_all_paths =
+          CollectSideEffectsOnPathsToDominatedBlock(block, dominated);
+      successor_map->Kill(side_effects_on_all_paths);
+      successor_dominators.Kill(side_effects_on_all_paths);
+    }
+    AnalyzeBlock(dominated, successor_map, &successor_dominators);
   }
 }

=======================================
--- /branches/bleeding_edge/src/hydrogen.h      Fri Mar 23 09:37:54 2012
+++ /branches/bleeding_edge/src/hydrogen.h      Wed Apr 11 03:56:16 2012
@@ -1223,6 +1223,30 @@
 };


+class HSideEffectMap BASE_EMBEDDED {
+ public:
+  HSideEffectMap();
+  HSideEffectMap(HSideEffectMap* other);
+
+  void Kill(GVNFlagSet flags);
+
+  void Store(GVNFlagSet flags, HInstruction* instr);
+
+  bool IsEmpty() const { return count_ == 0; }
+
+  inline HInstruction* operator[](int i) const {
+    ASSERT(0 <= i);
+    ASSERT(i < kNumberOfTrackedSideEffects);
+    return data_[i];
+  }
+  inline HInstruction* at(int i) const { return operator[](i); }
+
+ private:
+  int count_;
+  HInstruction* data_[kNumberOfTrackedSideEffects];
+};
+
+
 class HStatistics: public Malloced {
  public:
   void Initialize(CompilationInfo* info);

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to