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) {
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 @@ void HStoreNamedField::PrintDataTo(StringStream* stream) {
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());
}
......
......@@ -188,7 +188,10 @@ class LChunkBuilder;
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 @@ class HUseIterator BASE_EMBEDDED {
// 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 @@ class HValue: public ZoneObject {
// 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 @@ class HValue: public ZoneObject {
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);
}
......@@ -726,6 +743,13 @@ class HValue: public ZoneObject {
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;
#endif
......@@ -756,7 +780,8 @@ class HValue: public ZoneObject {
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 @@ class HValue: public ZoneObject {
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 @@ class HValue: public ZoneObject {
// 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);
......@@ -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 {
public:
HStoreGlobalCell(HValue* value,
......@@ -4023,9 +4056,12 @@ class HStoreNamedField: public HTemplateInstruction<2> {
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 @@ class HStoreNamedField: public HTemplateInstruction<2> {
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 @@ class HStoreNamedField: public HTemplateInstruction<2> {
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 @@ class HStoreNamedField: public HTemplateInstruction<2> {
bool is_in_object_;
int offset_;
Handle<Map> transition_;
HValue* new_space_dominator_;
};
......@@ -4404,6 +4447,7 @@ class HAllocateObject: public HTemplateInstruction<1> {
: constructor_(constructor) {
SetOperandAt(0, context);
set_representation(Representation::Tagged());
SetGVNFlag(kChangesNewSpacePromotion);
}
// Maximum instance size for which allocations will be inlined.
......
......@@ -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 {
public:
explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { }
......@@ -1427,7 +1459,9 @@ class HGlobalValueNumberer BASE_EMBEDDED {
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 @@ bool HGlobalValueNumberer::Analyze() {
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 @@ 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",
block->block_id(),
block->IsLoopHeader() ? " (loop header)" : "");
......@@ -1677,7 +1714,9 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
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 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
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 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
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));
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);
AnalyzeBlock(dominated, successor_map, &successor_dominators);
}
}
......
......@@ -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 {
public:
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