Avoid HeapObject check in HStoreNamedField.

This way an HStoreNamedField instruction can never deoptimize
itself, which is another important step towards a working
store elimination.

R=jarin@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21509 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
bmeurer@chromium.org 2014-05-27 07:17:08 +00:00
parent 94b4aef7d6
commit 7e8678bbaa
15 changed files with 63 additions and 121 deletions

View File

@ -2316,13 +2316,7 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
// 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);
if (!instr->access().IsExternalMemory() &&
instr->field_representation().IsHeapObject() &&
!instr->value()->type().IsHeapObject()) {
result = AssignEnvironment(result);
}
return result;
return new(zone()) LStoreNamedField(obj, val, temp);
}

View File

@ -4062,23 +4062,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
return;
}
SmiCheck check_needed =
instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
__ AssertNotSmi(object);
ASSERT(!(representation.IsSmi() &&
instr->value()->IsConstantOperand() &&
!IsSmi(LConstantOperand::cast(instr->value()))));
if (representation.IsHeapObject()) {
Register value = ToRegister(instr->value());
if (!instr->hydrogen()->value()->type().IsHeapObject()) {
__ SmiTst(value);
DeoptimizeIf(eq, instr->environment());
// We know now that value is not a smi, so we can omit the check below.
check_needed = OMIT_SMI_CHECK;
}
} else if (representation.IsDouble()) {
ASSERT(!representation.IsSmi() ||
!instr->value()->IsConstantOperand() ||
IsSmi(LConstantOperand::cast(instr->value())));
if (representation.IsDouble()) {
ASSERT(access.IsInobject());
ASSERT(!instr->hydrogen()->has_transition());
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
@ -4120,7 +4109,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
GetLinkRegisterState(),
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
instr->hydrogen()->SmiCheckForWriteBarrier());
}
} else {
__ ldr(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset));
@ -4136,7 +4125,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
GetLinkRegisterState(),
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
instr->hydrogen()->SmiCheckForWriteBarrier());
}
}
}

View File

@ -401,6 +401,11 @@ void MacroAssembler::Store(Register src,
} else if (r.IsInteger16() || r.IsUInteger16()) {
strh(src, dst);
} else {
if (r.IsHeapObject()) {
AssertNotSmi(src);
} else if (r.IsSmi()) {
AssertSmi(src);
}
str(src, dst);
}
}

View File

@ -2399,13 +2399,7 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
temp0 = TempRegister();
}
LStoreNamedField* result =
new(zone()) LStoreNamedField(object, value, temp0, temp1);
if (instr->field_representation().IsHeapObject() &&
!instr->value()->type().IsHeapObject()) {
return AssignEnvironment(result);
}
return result;
return new(zone()) LStoreNamedField(object, value, temp0, temp1);
}

View File

@ -5320,7 +5320,11 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
Register value = ToRegister(instr->value());
__ Store(value, MemOperand(object, offset), representation);
return;
} else if (representation.IsDouble()) {
}
__ AssertNotSmi(object);
if (representation.IsDouble()) {
ASSERT(access.IsInobject());
ASSERT(!instr->hydrogen()->has_transition());
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
@ -5331,19 +5335,9 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
Register value = ToRegister(instr->value());
SmiCheck check_needed = instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ASSERT(!(representation.IsSmi() &&
instr->value()->IsConstantOperand() &&
!IsInteger32Constant(LConstantOperand::cast(instr->value()))));
if (representation.IsHeapObject() &&
!instr->hydrogen()->value()->type().IsHeapObject()) {
DeoptimizeIfSmi(value, instr->environment());
// We know now that value is not a smi, so we can omit the check below.
check_needed = OMIT_SMI_CHECK;
}
ASSERT(!representation.IsSmi() ||
!instr->value()->IsConstantOperand() ||
IsInteger32Constant(LConstantOperand::cast(instr->value())));
if (instr->hydrogen()->has_transition()) {
Handle<Map> transition = instr->hydrogen()->transition_map();
@ -5403,7 +5397,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
GetLinkRegisterState(),
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
instr->hydrogen()->SmiCheckForWriteBarrier());
}
}

View File

@ -559,6 +559,11 @@ void MacroAssembler::Store(const Register& rt,
Str(rt.W(), addr);
} else {
ASSERT(rt.Is64Bits());
if (r.IsHeapObject()) {
AssertNotSmi(rt);
} else if (r.IsSmi()) {
AssertSmi(rt);
}
Str(rt, addr);
}
}

View File

@ -878,6 +878,7 @@ bool HInstruction::CanDeoptimize() {
case HValue::kSeqStringGetChar:
case HValue::kStoreCodeEntry:
case HValue::kStoreKeyed:
case HValue::kStoreNamedField:
case HValue::kStoreNamedGeneric:
case HValue::kStringCharCodeAt:
case HValue::kStringCharFromCode:
@ -926,7 +927,6 @@ bool HInstruction::CanDeoptimize() {
case HValue::kStoreContextSlot:
case HValue::kStoreGlobalCell:
case HValue::kStoreKeyedGeneric:
case HValue::kStoreNamedField:
case HValue::kStringAdd:
case HValue::kStringCompareAndBranch:
case HValue::kSub:

View File

@ -6816,6 +6816,12 @@ class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
new_space_dominator());
}
SmiCheck SmiCheckForWriteBarrier() const {
if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
if (value()->IsHeapObject()) return OMIT_SMI_CHECK;
return INLINE_SMI_CHECK;
}
Representation field_representation() const {
return access_.representation();
}

View File

@ -5505,16 +5505,13 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
value, STORE_TO_INITIALIZED_ENTRY);
}
} else {
if (field_access.representation().IsHeapObject()) {
BuildCheckHeapObject(value);
}
if (!info->field_maps()->is_empty()) {
ASSERT(field_access.representation().IsHeapObject());
BuildCheckHeapObject(value);
value = Add<HCheckMaps>(value, info->field_maps());
// TODO(bmeurer): This is a dirty hack to avoid repeating the smi check
// that was already performed by the HCheckHeapObject above in the
// HStoreNamedField below. We should really do this right instead and
// make Crankshaft aware of Representation::HeapObject().
field_access = field_access.WithRepresentation(Representation::Tagged());
}
// This is a normal store.

View File

@ -3978,30 +3978,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
}
Register object = ToRegister(instr->object());
SmiCheck check_needed =
instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
__ AssertNotSmi(object);
ASSERT(!(representation.IsSmi() &&
instr->value()->IsConstantOperand() &&
!IsSmi(LConstantOperand::cast(instr->value()))));
if (representation.IsHeapObject()) {
if (instr->value()->IsConstantOperand()) {
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
if (chunk_->LookupConstant(operand_value)->HasSmiValue()) {
DeoptimizeIf(no_condition, instr->environment());
}
} else {
if (!instr->hydrogen()->value()->type().IsHeapObject()) {
Register value = ToRegister(instr->value());
__ test(value, Immediate(kSmiTagMask));
DeoptimizeIf(zero, instr->environment());
// We know now that value is not a smi, so we can omit the check below.
check_needed = OMIT_SMI_CHECK;
}
}
} else if (representation.IsDouble()) {
ASSERT(!representation.IsSmi() ||
!instr->value()->IsConstantOperand() ||
IsSmi(LConstantOperand::cast(instr->value())));
if (representation.IsDouble()) {
ASSERT(access.IsInobject());
ASSERT(!instr->hydrogen()->has_transition());
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
@ -4068,7 +4050,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
temp,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
instr->hydrogen()->SmiCheckForWriteBarrier());
}
}

View File

@ -2394,16 +2394,7 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
// We need a temporary register for write barrier of the map field.
LOperand* temp_map = needs_write_barrier_for_map ? TempRegister() : NULL;
LInstruction* result =
new(zone()) LStoreNamedField(obj, val, temp, temp_map);
if (!instr->access().IsExternalMemory() &&
instr->field_representation().IsHeapObject() &&
(val->IsConstantOperand()
? HConstant::cast(instr->value())->HasSmiValue()
: !instr->value()->type().IsHeapObject())) {
result = AssignEnvironment(result);
}
return result;
return new(zone()) LStoreNamedField(obj, val, temp, temp_map);
}

View File

@ -55,6 +55,11 @@ void MacroAssembler::Store(Register src, const Operand& dst, Representation r) {
} else if (r.IsInteger16() || r.IsUInteger16()) {
mov_w(dst, src);
} else {
if (r.IsHeapObject()) {
AssertNotSmi(src);
} else if (r.IsSmi()) {
AssertSmi(src);
}
mov(dst, src);
}
}

View File

@ -4000,29 +4000,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
}
Register object = ToRegister(instr->object());
SmiCheck check_needed = hinstr->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
__ AssertNotSmi(object);
ASSERT(!(representation.IsSmi() &&
instr->value()->IsConstantOperand() &&
!IsInteger32Constant(LConstantOperand::cast(instr->value()))));
if (representation.IsHeapObject()) {
if (instr->value()->IsConstantOperand()) {
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
if (chunk_->LookupConstant(operand_value)->HasSmiValue()) {
DeoptimizeIf(no_condition, instr->environment());
}
} else {
if (!hinstr->value()->type().IsHeapObject()) {
Register value = ToRegister(instr->value());
Condition cc = masm()->CheckSmi(value);
DeoptimizeIf(cc, instr->environment());
// We know now that value is not a smi, so we can omit the check below.
check_needed = OMIT_SMI_CHECK;
}
}
} else if (representation.IsDouble()) {
ASSERT(!representation.IsSmi() ||
!instr->value()->IsConstantOperand() ||
IsInteger32Constant(LConstantOperand::cast(instr->value())));
if (representation.IsDouble()) {
ASSERT(access.IsInobject());
ASSERT(!hinstr->has_transition());
ASSERT(!hinstr->NeedsWriteBarrier());
@ -4107,7 +4090,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
temp,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
hinstr->SmiCheckForWriteBarrier());
}
}

View File

@ -2327,15 +2327,7 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
LOperand* temp = (!is_in_object || needs_write_barrier ||
needs_write_barrier_for_map) ? TempRegister() : NULL;
LInstruction* result = new(zone()) LStoreNamedField(obj, val, temp);
if (!instr->access().IsExternalMemory() &&
instr->field_representation().IsHeapObject() &&
(val->IsConstantOperand()
? HConstant::cast(instr->value())->HasSmiValue()
: !instr->value()->type().IsHeapObject())) {
result = AssignEnvironment(result);
}
return result;
return new(zone()) LStoreNamedField(obj, val, temp);
}

View File

@ -924,6 +924,11 @@ void MacroAssembler::Store(const Operand& dst, Register src, Representation r) {
} else if (r.IsInteger32()) {
movl(dst, src);
} else {
if (r.IsHeapObject()) {
AssertNotSmi(src);
} else if (r.IsSmi()) {
AssertSmi(src);
}
movp(dst, src);
}
}