Commit b09989ec authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

Refactor transitioning stores.

There's actually no need to have the transition as part of the HStoreNamedField instruction. In fact, it is cleaner and faster to generate a separate HStoreNamedField for the transition map. This will also help to eliminate map stores with store elimination, as well as reduce register pressure for transitioning stores on ia32.

R=hpayer@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21383 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 2a62cce1
......@@ -2279,8 +2279,6 @@ LInstruction* LChunkBuilder::DoTrapAllocationMemento(
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
bool is_in_object = instr->access().IsInobject();
bool needs_write_barrier = instr->NeedsWriteBarrier();
bool needs_write_barrier_for_map = instr->has_transition() &&
instr->NeedsWriteBarrierForMap();
LOperand* obj;
if (needs_write_barrier) {
......@@ -2288,9 +2286,7 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
? UseRegister(instr->object())
: UseTempRegister(instr->object());
} else {
obj = needs_write_barrier_for_map
? UseRegister(instr->object())
: UseRegisterAtStart(instr->object());
obj = UseRegisterAtStart(instr->object());
}
LOperand* val;
......@@ -2302,10 +2298,7 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
val = UseRegister(instr->value());
}
// We need a temporary register for write barrier of the map field.
LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
LInstruction* result = new(zone()) LStoreNamedField(obj, val, temp);
LInstruction* result = new(zone()) LStoreNamedField(obj, val);
if (!instr->access().IsExternalMemory() &&
instr->field_representation().IsHeapObject() &&
!instr->value()->type().IsHeapObject()) {
......
......@@ -2145,17 +2145,15 @@ class LSmiUntag V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LStoreNamedField V8_FINAL : public LTemplateInstruction<0, 2, 1> {
class LStoreNamedField V8_FINAL : public LTemplateInstruction<0, 2, 0> {
public:
LStoreNamedField(LOperand* object, LOperand* value, LOperand* temp) {
LStoreNamedField(LOperand* object, LOperand* value) {
inputs_[0] = object;
inputs_[1] = value;
temps_[0] = temp;
}
LOperand* object() { return inputs_[0]; }
LOperand* value() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
......
......@@ -4097,32 +4097,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
}
} else if (representation.IsDouble()) {
ASSERT(access.IsInobject());
ASSERT(!instr->hydrogen()->has_transition());
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
DwVfpRegister value = ToDoubleRegister(instr->value());
__ vstr(value, FieldMemOperand(object, offset));
return;
}
if (instr->hydrogen()->has_transition()) {
Handle<Map> transition = instr->hydrogen()->transition_map();
AddDeprecationDependency(transition);
__ mov(scratch, Operand(transition));
__ str(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
Register temp = ToRegister(instr->temp());
// Update the write barrier for the map field.
__ RecordWriteField(object,
HeapObject::kMapOffset,
scratch,
temp,
GetLinkRegisterState(),
kSaveFPRegs,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
}
}
// Do the store.
Register value = ToRegister(instr->value());
if (access.IsInobject()) {
......
......@@ -2371,10 +2371,6 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
value = UseRegisterAndClobber(instr->value());
temp0 = TempRegister();
temp1 = TempRegister();
} else if (instr->NeedsWriteBarrierForMap()) {
value = UseRegister(instr->value());
temp0 = TempRegister();
temp1 = TempRegister();
} else {
value = UseRegister(instr->value());
temp0 = TempRegister();
......
......@@ -5302,14 +5302,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
int offset = access.offset();
if (access.IsExternalMemory()) {
ASSERT(!instr->hydrogen()->has_transition());
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
Register value = ToRegister(instr->value());
__ Store(value, MemOperand(object, offset), representation);
return;
} else if (representation.IsDouble()) {
ASSERT(access.IsInobject());
ASSERT(!instr->hydrogen()->has_transition());
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
FPRegister value = ToDoubleRegister(instr->value());
__ Str(value, FieldMemOperand(object, offset));
......@@ -5332,26 +5330,6 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
check_needed = OMIT_SMI_CHECK;
}
if (instr->hydrogen()->has_transition()) {
Handle<Map> transition = instr->hydrogen()->transition_map();
AddDeprecationDependency(transition);
// Store the new map value.
Register new_map_value = ToRegister(instr->temp0());
__ Mov(new_map_value, Operand(transition));
__ Str(new_map_value, FieldMemOperand(object, HeapObject::kMapOffset));
if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
// Update the write barrier for the map field.
__ RecordWriteField(object,
HeapObject::kMapOffset,
new_map_value,
ToRegister(instr->temp1()),
GetLinkRegisterState(),
kSaveFPRegs,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
}
}
// Do the store.
Register destination;
if (access.IsInobject()) {
......
......@@ -451,15 +451,7 @@ class HCheckTable : public ZoneObject {
void ReduceStoreNamedField(HStoreNamedField* instr) {
HValue* object = instr->object()->ActualValue();
if (instr->has_transition()) {
// This store transitions the object to a new map.
Kill(object);
HConstant* c_transition = HConstant::cast(instr->transition());
HCheckTableEntry::State state = c_transition->HasStableMapValue()
? HCheckTableEntry::CHECKED_STABLE
: HCheckTableEntry::CHECKED;
Insert(object, NULL, c_transition->MapValue(), state);
} else if (instr->access().IsMap()) {
if (instr->access().IsMap()) {
// This is a store directly to the map field of the object.
Kill(object);
if (!instr->value()->IsConstant()) return;
......@@ -714,7 +706,7 @@ class HCheckMapsEffects : public ZoneObject {
switch (instr->opcode()) {
case HValue::kStoreNamedField: {
HStoreNamedField* store = HStoreNamedField::cast(instr);
if (store->access().IsMap() || store->has_transition()) {
if (store->access().IsMap()) {
objects_.Add(store->object(), zone);
}
break;
......
......@@ -206,16 +206,12 @@ void HEscapeAnalysisPhase::AnalyzeDataFlow(HInstruction* allocate) {
ASSERT(store->access().IsInobject());
state = NewStateCopy(store->previous(), state);
state->SetOperandAt(index, store->value());
if (store->has_transition()) {
state->SetOperandAt(0, store->transition());
}
if (store->HasObservableSideEffects()) {
state->ReuseSideEffectsFromStore(store);
}
store->DeleteAndReplaceWith(store->ActualValue());
if (FLAG_trace_escape_analysis) {
PrintF("Replacing store #%d%s\n", instr->id(),
store->has_transition() ? " (with transition)" : "");
PrintF("Replacing store #%d\n", instr->id());
}
break;
}
......
......@@ -3589,9 +3589,6 @@ void HStoreNamedField::PrintDataTo(StringStream* stream) {
if (NeedsWriteBarrier()) {
stream->Add(" (write-barrier)");
}
if (has_transition()) {
stream->Add(" (transition map %p)", *transition_map());
}
}
......
......@@ -6656,7 +6656,7 @@ enum StoreFieldOrKeyedMode {
};
class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
class HStoreNamedField V8_FINAL : public HTemplateInstruction<2> {
public:
DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
HObjectAccess, HValue*);
......@@ -6711,30 +6711,12 @@ class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
HValue* object() const { return OperandAt(0); }
HValue* value() const { return OperandAt(1); }
HValue* transition() const { return OperandAt(2); }
HObjectAccess access() const { return access_; }
HValue* new_space_dominator() const { return new_space_dominator_; }
bool has_transition() const { return has_transition_; }
StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
Handle<Map> transition_map() const {
if (has_transition()) {
return Handle<Map>::cast(
HConstant::cast(transition())->handle(Isolate::Current()));
} else {
return Handle<Map>();
}
}
void SetTransition(HConstant* transition) {
ASSERT(!has_transition()); // Only set once.
SetOperandAt(2, transition);
has_transition_ = true;
}
bool NeedsWriteBarrier() {
ASSERT(!field_representation().IsDouble() || !has_transition());
if (IsSkipWriteBarrier()) return false;
if (field_representation().IsDouble()) return false;
if (field_representation().IsSmi()) return false;
......@@ -6745,12 +6727,6 @@ class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
new_space_dominator());
}
bool NeedsWriteBarrierForMap() {
if (IsSkipWriteBarrier()) return false;
return ReceiverObjectNeedsWriteBarrier(object(), transition(),
new_space_dominator());
}
Representation field_representation() const {
return access_.representation();
}
......@@ -6767,7 +6743,6 @@ class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
: access_(access),
new_space_dominator_(NULL),
write_barrier_mode_(UPDATE_WRITE_BARRIER),
has_transition_(false),
store_mode_(store_mode) {
// Stores to a non existing in-object property are allowed only to the
// newly allocated objects (via HAllocate or HInnerAllocatedObject).
......@@ -6775,14 +6750,12 @@ class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
obj->IsAllocate() || obj->IsInnerAllocatedObject());
SetOperandAt(0, obj);
SetOperandAt(1, val);
SetOperandAt(2, obj);
access.SetGVNFlags(this, STORE);
}
HObjectAccess access_;
HValue* new_space_dominator_;
WriteBarrierMode write_barrier_mode_ : 1;
bool has_transition_ : 1;
StoreFieldOrKeyedMode store_mode_ : 1;
};
......
......@@ -240,12 +240,7 @@ class HLoadEliminationTable : public ZoneObject {
HValue* object = instr->object()->ActualValue();
HValue* value = instr->value();
if (instr->has_transition()) {
// A transition introduces a new field and alters the map of the object.
// Since the field in the object is new, it cannot alias existing entries.
// TODO(titzer): introduce a constant for the new map and remember it.
KillFieldInternal(object, FieldOf(JSObject::kMapOffset), NULL);
} else {
if (instr->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
// Kill non-equivalent may-alias entries.
KillFieldInternal(object, field, value);
}
......
......@@ -58,7 +58,11 @@ void HStoreEliminationPhase::ProcessStore(HStoreNamedField* store) {
while (i < unobserved_.length()) {
HStoreNamedField* prev = unobserved_.at(i);
if (aliasing_->MustAlias(object, prev->object()->ActualValue()) &&
store->access().Equals(prev->access())) {
store->access().Equals(prev->access()) &&
(!SmiValuesAre32Bits() ||
!store->field_representation().IsSmi() ||
store->store_mode() == STORE_TO_INITIALIZED_ENTRY ||
prev->store_mode() == INITIALIZING_STORE)) {
// This store is guaranteed to overwrite the previous store.
prev->DeleteAndReplaceWith(NULL);
TRACE(("++ Unobserved store S%d overwritten by S%d\n",
......@@ -69,11 +73,8 @@ void HStoreEliminationPhase::ProcessStore(HStoreNamedField* store) {
i++;
}
}
// Only non-transitioning stores are removable.
if (!store->has_transition()) {
TRACE(("-- Might remove store S%d\n", store->id()));
unobserved_.Add(store, zone());
}
TRACE(("-- Might remove store S%d\n", store->id()));
unobserved_.Add(store, zone());
}
......
......@@ -5529,7 +5529,14 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
if (transition_to_field) {
Handle<Map> transition(info->transition());
ASSERT(!transition->is_deprecated());
instr->SetTransition(Add<HConstant>(transition));
if (transition->CanBeDeprecated()) {
Map::AddDependentCompilationInfo(
transition, DependentCode::kTransitionGroup, top_info());
}
Add<HStoreNamedField>(checked_object->ActualValue(),
HObjectAccess::ForMap(),
Add<HConstant>(transition),
STORE_TO_INITIALIZED_ENTRY);
}
return instr;
}
......
......@@ -4003,34 +4003,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
}
} else if (representation.IsDouble()) {
ASSERT(access.IsInobject());
ASSERT(!instr->hydrogen()->has_transition());
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
XMMRegister value = ToDoubleRegister(instr->value());
__ movsd(FieldOperand(object, offset), value);
return;
}
if (instr->hydrogen()->has_transition()) {
Handle<Map> transition = instr->hydrogen()->transition_map();
AddDeprecationDependency(transition);
if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
__ mov(FieldOperand(object, HeapObject::kMapOffset), transition);
} else {
Register temp = ToRegister(instr->temp());
Register temp_map = ToRegister(instr->temp_map());
__ mov(temp_map, transition);
__ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
// Update the write barrier for the map field.
__ RecordWriteField(object,
HeapObject::kMapOffset,
temp_map,
temp,
kSaveFPRegs,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
}
}
// Do the store.
Register write_register = object;
if (!access.IsInobject()) {
......
......@@ -2340,8 +2340,6 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
bool is_external_location = instr->access().IsExternalMemory() &&
instr->access().offset() == 0;
bool needs_write_barrier = instr->NeedsWriteBarrier();
bool needs_write_barrier_for_map = instr->has_transition() &&
instr->NeedsWriteBarrierForMap();
LOperand* obj;
if (needs_write_barrier) {
......@@ -2351,12 +2349,9 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
} else if (is_external_location) {
ASSERT(!is_in_object);
ASSERT(!needs_write_barrier);
ASSERT(!needs_write_barrier_for_map);
obj = UseRegisterOrConstant(instr->object());
} else {
obj = needs_write_barrier_for_map
? UseRegister(instr->object())
: UseRegisterAtStart(instr->object());
obj = UseRegisterAtStart(instr->object());
}
bool can_be_constant = instr->value()->IsConstant() &&
......@@ -2383,14 +2378,11 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
// We only need a scratch register if we have a write barrier or we
// have a store into the properties array (not in-object-property).
LOperand* temp = (!is_in_object || needs_write_barrier ||
needs_write_barrier_for_map) ? TempRegister() : NULL;
// We need a temporary register for write barrier of the map field.
LOperand* temp_map = needs_write_barrier_for_map ? TempRegister() : NULL;
LOperand* temp = (!is_in_object || needs_write_barrier)
? TempRegister() : NULL;
LInstruction* result =
new(zone()) LStoreNamedField(obj, val, temp, temp_map);
new(zone()) LStoreNamedField(obj, val, temp);
if (!instr->access().IsExternalMemory() &&
instr->field_representation().IsHeapObject() &&
(val->IsConstantOperand()
......
......@@ -2151,22 +2151,19 @@ class LSmiUntag V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LStoreNamedField V8_FINAL : public LTemplateInstruction<0, 2, 2> {
class LStoreNamedField V8_FINAL : public LTemplateInstruction<0, 2, 1> {
public:
LStoreNamedField(LOperand* obj,
LOperand* val,
LOperand* temp,
LOperand* temp_map) {
LOperand* temp) {
inputs_[0] = obj;
inputs_[1] = val;
temps_[0] = temp;
temps_[1] = temp_map;
}
LOperand* object() { return inputs_[0]; }
LOperand* value() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
LOperand* temp_map() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
......
......@@ -216,12 +216,6 @@ void LCodeGenBase::Abort(BailoutReason reason) {
}
void LCodeGenBase::AddDeprecationDependency(Handle<Map> map) {
if (map->is_deprecated()) return Abort(kMapBecameDeprecated);
chunk_->AddDeprecationDependency(map);
}
void LCodeGenBase::AddStabilityDependency(Handle<Map> map) {
if (!map->is_stable()) return Abort(kMapBecameUnstable);
chunk_->AddStabilityDependency(map);
......
......@@ -76,7 +76,6 @@ class LCodeGenBase BASE_EMBEDDED {
void Abort(BailoutReason reason);
// Methods for code dependencies.
void AddDeprecationDependency(Handle<Map> map);
void AddStabilityDependency(Handle<Map> map);
};
......
......@@ -238,7 +238,6 @@ LChunk::LChunk(CompilationInfo* info, HGraph* graph)
instructions_(32, graph->zone()),
pointer_maps_(8, graph->zone()),
inlined_closures_(1, graph->zone()),
deprecation_dependencies_(MapLess(), MapAllocator(graph->zone())),
stability_dependencies_(MapLess(), MapAllocator(graph->zone())) {
}
......@@ -379,14 +378,6 @@ Representation LChunk::LookupLiteralRepresentation(
void LChunk::CommitDependencies(Handle<Code> code) const {
for (MapSet::const_iterator it = deprecation_dependencies_.begin(),
iend = deprecation_dependencies_.end(); it != iend; ++it) {
Handle<Map> map = *it;
ASSERT(!map->is_deprecated());
ASSERT(map->CanBeDeprecated());
Map::AddDependentCode(map, DependentCode::kTransitionGroup, code);
}
for (MapSet::const_iterator it = stability_dependencies_.begin(),
iend = stability_dependencies_.end(); it != iend; ++it) {
Handle<Map> map = *it;
......
......@@ -650,13 +650,6 @@ class LChunk : public ZoneObject {
inlined_closures_.Add(closure, zone());
}
void AddDeprecationDependency(Handle<Map> map) {
ASSERT(!map->is_deprecated());
if (!map->CanBeDeprecated()) return;
ASSERT(!info_->IsStub());
deprecation_dependencies_.insert(map);
}
void AddStabilityDependency(Handle<Map> map) {
ASSERT(map->is_stable());
if (!map->CanTransition()) return;
......@@ -691,7 +684,6 @@ class LChunk : public ZoneObject {
ZoneList<LInstruction*> instructions_;
ZoneList<LPointerMap*> pointer_maps_;
ZoneList<Handle<JSFunction> > inlined_closures_;
MapSet deprecation_dependencies_;
MapSet stability_dependencies_;
};
......
......@@ -4021,33 +4021,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
}
} else if (representation.IsDouble()) {
ASSERT(access.IsInobject());
ASSERT(!hinstr->has_transition());
ASSERT(!hinstr->NeedsWriteBarrier());
XMMRegister value = ToDoubleRegister(instr->value());
__ movsd(FieldOperand(object, offset), value);
return;
}
if (hinstr->has_transition()) {
Handle<Map> transition = hinstr->transition_map();
AddDeprecationDependency(transition);
if (!hinstr->NeedsWriteBarrierForMap()) {
__ Move(FieldOperand(object, HeapObject::kMapOffset), transition);
} else {
Register temp = ToRegister(instr->temp());
__ Move(kScratchRegister, transition);
__ movp(FieldOperand(object, HeapObject::kMapOffset), kScratchRegister);
// Update the write barrier for the map field.
__ RecordWriteField(object,
HeapObject::kMapOffset,
kScratchRegister,
temp,
kSaveFPRegs,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
}
}
// Do the store.
Register write_register = object;
if (!access.IsInobject()) {
......
......@@ -2276,8 +2276,6 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
bool is_external_location = instr->access().IsExternalMemory() &&
instr->access().offset() == 0;
bool needs_write_barrier = instr->NeedsWriteBarrier();
bool needs_write_barrier_for_map = instr->has_transition() &&
instr->NeedsWriteBarrierForMap();
LOperand* obj;
if (needs_write_barrier) {
......@@ -2287,12 +2285,9 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
} else if (is_external_location) {
ASSERT(!is_in_object);
ASSERT(!needs_write_barrier);
ASSERT(!needs_write_barrier_for_map);
obj = UseRegisterOrConstant(instr->object());
} else {
obj = needs_write_barrier_for_map
? UseRegister(instr->object())
: UseRegisterAtStart(instr->object());
obj = UseRegisterAtStart(instr->object());
}
bool can_be_constant = instr->value()->IsConstant() &&
......@@ -2316,8 +2311,8 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
// We only need a scratch register if we have a write barrier or we
// have a store into the properties array (not in-object-property).
LOperand* temp = (!is_in_object || needs_write_barrier ||
needs_write_barrier_for_map) ? TempRegister() : NULL;
LOperand* temp = (!is_in_object || needs_write_barrier)
? TempRegister() : NULL;
LInstruction* result = new(zone()) LStoreNamedField(obj, val, temp);
if (!instr->access().IsExternalMemory() &&
......
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