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