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.

R=erik.corry@gmail.com
TEST=mjsunit/compiler/inline-construct

Review URL: https://chromiumcodereview.appspot.com/10031031

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11270 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent dd0be92a
...@@ -462,7 +462,8 @@ void HValue::PrintChangesTo(StringStream* stream) { ...@@ -462,7 +462,8 @@ void HValue::PrintChangesTo(StringStream* stream) {
add_comma = true; \ add_comma = true; \
stream->Add(#type); \ stream->Add(#type); \
} }
GVN_FLAG_LIST(PRINT_DO); GVN_TRACKED_FLAG_LIST(PRINT_DO);
GVN_UNTRACKED_FLAG_LIST(PRINT_DO);
#undef PRINT_DO #undef PRINT_DO
} }
stream->Add("]"); stream->Add("]");
...@@ -1733,6 +1734,9 @@ void HStoreNamedField::PrintDataTo(StringStream* stream) { ...@@ -1733,6 +1734,9 @@ void HStoreNamedField::PrintDataTo(StringStream* stream) {
stream->Add(" = "); stream->Add(" = ");
value()->PrintNameTo(stream); value()->PrintNameTo(stream);
stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : ""); stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
if (NeedsWriteBarrier()) {
stream->Add(" (write-barrier)");
}
if (!transition().is_null()) { if (!transition().is_null()) {
stream->Add(" (transition map %p)", *transition()); stream->Add(" (transition map %p)", *transition());
} }
......
...@@ -188,7 +188,10 @@ class LChunkBuilder; ...@@ -188,7 +188,10 @@ class LChunkBuilder;
V(DateField) \ V(DateField) \
V(WrapReceiver) V(WrapReceiver)
#define GVN_FLAG_LIST(V) \ #define GVN_TRACKED_FLAG_LIST(V) \
V(NewSpacePromotion)
#define GVN_UNTRACKED_FLAG_LIST(V) \
V(Calls) \ V(Calls) \
V(InobjectFields) \ V(InobjectFields) \
V(BackingStoreFields) \ V(BackingStoreFields) \
...@@ -506,14 +509,18 @@ class HUseIterator BASE_EMBEDDED { ...@@ -506,14 +509,18 @@ class HUseIterator BASE_EMBEDDED {
// There must be one corresponding kDepends flag for every kChanges flag and // 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 // 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 { enum GVNFlag {
// Declare global value numbering flags. // Declare global value numbering flags.
#define DECLARE_FLAG(type) kChanges##type, kDependsOn##type, #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 #undef DECLARE_FLAG
kAfterLastFlag, 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; typedef EnumSet<GVNFlag> GVNFlagSet;
...@@ -530,6 +537,10 @@ class HValue: public ZoneObject { ...@@ -530,6 +537,10 @@ class HValue: public ZoneObject {
// implement DataEquals(), which will be used to determine if other // implement DataEquals(), which will be used to determine if other
// occurrences of the instruction are indeed the same. // occurrences of the instruction are indeed the same.
kUseGVN, 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, kCanOverflow,
kBailoutOnMinusZero, kBailoutOnMinusZero,
kCanBeDivByZero, kCanBeDivByZero,
...@@ -544,6 +555,12 @@ class HValue: public ZoneObject { ...@@ -544,6 +555,12 @@ class HValue: public ZoneObject {
static const int kChangesToDependsFlagsLeftShift = 1; 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) { static GVNFlagSet ConvertChangesToDependsFlags(GVNFlagSet flags) {
return GVNFlagSet(flags.ToIntegral() << kChangesToDependsFlagsLeftShift); return GVNFlagSet(flags.ToIntegral() << kChangesToDependsFlagsLeftShift);
} }
...@@ -726,6 +743,13 @@ class HValue: public ZoneObject { ...@@ -726,6 +743,13 @@ class HValue: public ZoneObject {
virtual HType CalculateInferredType(); 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 #ifdef DEBUG
virtual void Verify() = 0; virtual void Verify() = 0;
#endif #endif
...@@ -756,7 +780,8 @@ class HValue: public ZoneObject { ...@@ -756,7 +780,8 @@ class HValue: public ZoneObject {
GVNFlagSet result; GVNFlagSet result;
// Create changes mask. // Create changes mask.
#define ADD_FLAG(type) result.Add(kDependsOn##type); #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 #undef ADD_FLAG
return result; return result;
} }
...@@ -765,7 +790,8 @@ class HValue: public ZoneObject { ...@@ -765,7 +790,8 @@ class HValue: public ZoneObject {
GVNFlagSet result; GVNFlagSet result;
// Create changes mask. // Create changes mask.
#define ADD_FLAG(type) result.Add(kChanges##type); #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 #undef ADD_FLAG
return result; return result;
} }
...@@ -781,6 +807,7 @@ class HValue: public ZoneObject { ...@@ -781,6 +807,7 @@ class HValue: public ZoneObject {
// an executing program (i.e. are not safe to repeat, move or remove); // an executing program (i.e. are not safe to repeat, move or remove);
static GVNFlagSet AllObservableSideEffectsFlagSet() { static GVNFlagSet AllObservableSideEffectsFlagSet() {
GVNFlagSet result = AllChangesFlagSet(); GVNFlagSet result = AllChangesFlagSet();
result.Remove(kChangesNewSpacePromotion);
result.Remove(kChangesElementsKind); result.Remove(kChangesElementsKind);
result.Remove(kChangesElementsPointer); result.Remove(kChangesElementsPointer);
result.Remove(kChangesMaps); result.Remove(kChangesMaps);
...@@ -3557,6 +3584,12 @@ inline bool StoringValueNeedsWriteBarrier(HValue* value) { ...@@ -3557,6 +3584,12 @@ inline bool StoringValueNeedsWriteBarrier(HValue* value) {
} }
inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
HValue* new_space_dominator) {
return !object->IsAllocateObject() || (object != new_space_dominator);
}
class HStoreGlobalCell: public HUnaryOperation { class HStoreGlobalCell: public HUnaryOperation {
public: public:
HStoreGlobalCell(HValue* value, HStoreGlobalCell(HValue* value,
...@@ -4023,9 +4056,12 @@ class HStoreNamedField: public HTemplateInstruction<2> { ...@@ -4023,9 +4056,12 @@ class HStoreNamedField: public HTemplateInstruction<2> {
int offset) int offset)
: name_(name), : name_(name),
is_in_object_(in_object), is_in_object_(in_object),
offset_(offset) { offset_(offset),
new_space_dominator_(NULL) {
SetOperandAt(0, obj); SetOperandAt(0, obj);
SetOperandAt(1, val); SetOperandAt(1, val);
SetFlag(kTrackSideEffectDominators);
SetGVNFlag(kDependsOnNewSpacePromotion);
if (is_in_object_) { if (is_in_object_) {
SetGVNFlag(kChangesInobjectFields); SetGVNFlag(kChangesInobjectFields);
} else { } else {
...@@ -4038,6 +4074,10 @@ class HStoreNamedField: public HTemplateInstruction<2> { ...@@ -4038,6 +4074,10 @@ class HStoreNamedField: public HTemplateInstruction<2> {
virtual Representation RequiredInputRepresentation(int index) { virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged(); return Representation::Tagged();
} }
virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) {
ASSERT(side_effect == kChangesNewSpacePromotion);
new_space_dominator_ = dominator;
}
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
HValue* object() { return OperandAt(0); } HValue* object() { return OperandAt(0); }
...@@ -4048,9 +4088,11 @@ class HStoreNamedField: public HTemplateInstruction<2> { ...@@ -4048,9 +4088,11 @@ class HStoreNamedField: public HTemplateInstruction<2> {
int offset() const { return offset_; } int offset() const { return offset_; }
Handle<Map> transition() const { return transition_; } Handle<Map> transition() const { return transition_; }
void set_transition(Handle<Map> map) { transition_ = map; } void set_transition(Handle<Map> map) { transition_ = map; }
HValue* new_space_dominator() const { return new_space_dominator_; }
bool NeedsWriteBarrier() { bool NeedsWriteBarrier() {
return StoringValueNeedsWriteBarrier(value()); return StoringValueNeedsWriteBarrier(value()) &&
ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator());
} }
private: private:
...@@ -4058,6 +4100,7 @@ class HStoreNamedField: public HTemplateInstruction<2> { ...@@ -4058,6 +4100,7 @@ class HStoreNamedField: public HTemplateInstruction<2> {
bool is_in_object_; bool is_in_object_;
int offset_; int offset_;
Handle<Map> transition_; Handle<Map> transition_;
HValue* new_space_dominator_;
}; };
...@@ -4404,6 +4447,7 @@ class HAllocateObject: public HTemplateInstruction<1> { ...@@ -4404,6 +4447,7 @@ class HAllocateObject: public HTemplateInstruction<1> {
: constructor_(constructor) { : constructor_(constructor) {
SetOperandAt(0, context); SetOperandAt(0, context);
set_representation(Representation::Tagged()); set_representation(Representation::Tagged());
SetGVNFlag(kChangesNewSpacePromotion);
} }
// Maximum instance size for which allocations will be inlined. // Maximum instance size for which allocations will be inlined.
......
...@@ -1321,6 +1321,38 @@ void HValueMap::Insert(HValue* value) { ...@@ -1321,6 +1321,38 @@ void HValueMap::Insert(HValue* value) {
} }
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 { class HStackCheckEliminator BASE_EMBEDDED {
public: public:
explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { } explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { }
...@@ -1427,7 +1459,9 @@ class HGlobalValueNumberer BASE_EMBEDDED { ...@@ -1427,7 +1459,9 @@ class HGlobalValueNumberer BASE_EMBEDDED {
GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock( GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock(
HBasicBlock* dominator, HBasicBlock* dominator,
HBasicBlock* dominated); HBasicBlock* dominated);
void AnalyzeBlock(HBasicBlock* block, HValueMap* map); void AnalyzeBlock(HBasicBlock* block,
HValueMap* map,
HSideEffectMap* dominators);
void ComputeBlockSideEffects(); void ComputeBlockSideEffects();
void LoopInvariantCodeMotion(); void LoopInvariantCodeMotion();
void ProcessLoopBlock(HBasicBlock* block, void ProcessLoopBlock(HBasicBlock* block,
...@@ -1465,7 +1499,8 @@ bool HGlobalValueNumberer::Analyze() { ...@@ -1465,7 +1499,8 @@ bool HGlobalValueNumberer::Analyze() {
LoopInvariantCodeMotion(); LoopInvariantCodeMotion();
} }
HValueMap* map = new(zone()) HValueMap(); 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_; return removed_side_effects_;
} }
...@@ -1660,7 +1695,9 @@ GVNFlagSet HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock( ...@@ -1660,7 +1695,9 @@ GVNFlagSet HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock(
} }
void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block,
HValueMap* map,
HSideEffectMap* dominators) {
TraceGVN("Analyzing block B%d%s\n", TraceGVN("Analyzing block B%d%s\n",
block->block_id(), block->block_id(),
block->IsLoopHeader() ? " (loop header)" : ""); block->IsLoopHeader() ? " (loop header)" : "");
...@@ -1677,7 +1714,9 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { ...@@ -1677,7 +1714,9 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
GVNFlagSet flags = instr->ChangesFlags(); GVNFlagSet flags = instr->ChangesFlags();
if (!flags.IsEmpty()) { if (!flags.IsEmpty()) {
// Clear all instructions in the map that are affected by side effects. // 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); map->Kill(flags);
dominators->Store(flags, instr);
TraceGVN("Instruction %d kills\n", instr->id()); TraceGVN("Instruction %d kills\n", instr->id());
} }
if (instr->CheckFlag(HValue::kUseGVN)) { if (instr->CheckFlag(HValue::kUseGVN)) {
...@@ -1696,6 +1735,23 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { ...@@ -1696,6 +1735,23 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
map->Add(instr); 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; instr = next;
} }
...@@ -1705,20 +1761,22 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { ...@@ -1705,20 +1761,22 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
HBasicBlock* dominated = block->dominated_blocks()->at(i); HBasicBlock* dominated = block->dominated_blocks()->at(i);
// No need to copy the map for the last child in the dominator tree. // No need to copy the map for the last child in the dominator tree.
HValueMap* successor_map = (i == length - 1) ? map : map->Copy(zone()); 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 // Kill everything killed on any path between this block and the
// dominated block. // dominated block. We don't have to traverse these paths if the
// We don't have to traverse these paths if the value map is // value map and the dominators list is already empty. If the range
// already empty. // of block ids (block_id, dominated_id) is empty there are no such
// If the range of block ids (block_id, dominated_id) is empty // paths.
// there are no such paths. if ((!successor_map->IsEmpty() || !successor_dominators.IsEmpty()) &&
if (!successor_map->IsEmpty() &&
block->block_id() + 1 < dominated->block_id()) { block->block_id() + 1 < dominated->block_id()) {
visited_on_paths_.Clear(); visited_on_paths_.Clear();
successor_map->Kill(CollectSideEffectsOnPathsToDominatedBlock(block, GVNFlagSet side_effects_on_all_paths =
dominated)); CollectSideEffectsOnPathsToDominatedBlock(block, dominated);
successor_map->Kill(side_effects_on_all_paths);
successor_dominators.Kill(side_effects_on_all_paths);
} }
AnalyzeBlock(dominated, successor_map); AnalyzeBlock(dominated, successor_map, &successor_dominators);
} }
} }
......
...@@ -1223,6 +1223,30 @@ class HValueMap: public ZoneObject { ...@@ -1223,6 +1223,30 @@ class HValueMap: public ZoneObject {
}; };
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 { class HStatistics: public Malloced {
public: public:
void Initialize(CompilationInfo* info); void Initialize(CompilationInfo* info);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment