Eliminate write barrier for global stores at compile time if value stored is a smi.

Omit smi check inside write barriers if the value is known to be a heap object.

Refine inferred types of some instructions.
Review URL: http://codereview.chromium.org/8256016

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9618 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 168b13b6
......@@ -1260,7 +1260,6 @@ class LStoreContextSlot: public LTemplateInstruction<0, 2, 0> {
LOperand* context() { return InputAt(0); }
LOperand* value() { return InputAt(1); }
int slot_index() { return hydrogen()->slot_index(); }
int needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); }
virtual void PrintDataTo(StringStream* stream);
};
......@@ -1561,7 +1560,6 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 0> {
Handle<Object> name() const { return hydrogen()->name(); }
bool is_in_object() { return hydrogen()->is_in_object(); }
int offset() { return hydrogen()->offset(); }
bool needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); }
Handle<Map> transition() const { return hydrogen()->transition(); }
};
......
......@@ -2251,13 +2251,19 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
__ str(value, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
// Cells are always in the remembered set.
__ RecordWriteField(scratch,
JSGlobalPropertyCell::kValueOffset,
value,
scratch2,
kLRHasBeenSaved,
kSaveFPRegs,
OMIT_REMEMBERED_SET);
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
__ RecordWriteField(scratch,
JSGlobalPropertyCell::kValueOffset,
value,
scratch2,
kLRHasBeenSaved,
kSaveFPRegs,
OMIT_REMEMBERED_SET,
check_needed);
}
}
......@@ -2285,13 +2291,18 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
Register value = ToRegister(instr->value());
MemOperand target = ContextOperand(context, instr->slot_index());
__ str(value, target);
if (instr->needs_write_barrier()) {
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
__ RecordWriteContextSlot(context,
target.offset(),
value,
scratch0(),
kLRHasBeenSaved,
kSaveFPRegs);
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
}
}
......@@ -3297,21 +3308,36 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
}
// Do the store.
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
if (instr->is_in_object()) {
__ str(value, FieldMemOperand(object, offset));
if (instr->needs_write_barrier()) {
if (instr->hydrogen()->NeedsWriteBarrier()) {
// Update the write barrier for the object for in-object properties.
__ RecordWriteField(
object, offset, value, scratch, kLRHasBeenSaved, kSaveFPRegs);
__ RecordWriteField(object,
offset,
value,
scratch,
kLRHasBeenSaved,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
}
} else {
__ ldr(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset));
__ str(value, FieldMemOperand(scratch, offset));
if (instr->needs_write_barrier()) {
if (instr->hydrogen()->NeedsWriteBarrier()) {
// Update the write barrier for the properties array.
// object is used as a scratch register.
__ RecordWriteField(
scratch, offset, value, object, kLRHasBeenSaved, kSaveFPRegs);
__ RecordWriteField(scratch,
offset,
value,
object,
kLRHasBeenSaved,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
}
}
}
......@@ -3362,9 +3388,18 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
}
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register.
__ add(key, scratch, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ RecordWrite(elements, key, value, kLRHasBeenSaved, kSaveFPRegs);
__ RecordWrite(elements,
key,
value,
kLRHasBeenSaved,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
}
}
......@@ -4349,8 +4384,9 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
false_label,
input,
instr->type_literal());
EmitBranch(true_block, false_block, final_branch_condition);
if (final_branch_condition != kNoCondition) {
EmitBranch(true_block, false_block, final_branch_condition);
}
}
......@@ -4420,9 +4456,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
final_branch_condition = eq;
} else {
final_branch_condition = ne;
__ b(false_label);
// A dead branch instruction will be generated after this point.
}
return final_branch_condition;
......
......@@ -272,8 +272,10 @@ class LCodeGen BASE_EMBEDDED {
// Emits optimized code for typeof x == "y". Modifies input register.
// Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough.
Condition EmitTypeofIs(Label* true_label, Label* false_label,
Register input, Handle<String> type_name);
Condition EmitTypeofIs(Label* true_label,
Label* false_label,
Register input,
Handle<String> type_name);
// Emits optimized code for %_IsObject(x). Preserves input register.
// Returns the condition on which a final split to
......
......@@ -1746,6 +1746,12 @@ HType HInstanceOfKnownGlobal::CalculateInferredType() {
}
HType HChange::CalculateInferredType() {
if (from().IsDouble() && to().IsTagged()) return HType::HeapNumber();
return type();
}
HType HBitwiseBinaryOperation::CalculateInferredType() {
return HType::TaggedNumber();
}
......@@ -1801,6 +1807,31 @@ HType HSar::CalculateInferredType() {
}
HType HStringCharFromCode::CalculateInferredType() {
return HType::String();
}
HType HArrayLiteral::CalculateInferredType() {
return HType::JSArray();
}
HType HObjectLiteral::CalculateInferredType() {
return HType::JSObject();
}
HType HRegExpLiteral::CalculateInferredType() {
return HType::JSObject();
}
HType HFunctionLiteral::CalculateInferredType() {
return HType::JSObject();
}
HValue* HUnaryMathOperation::EnsureAndPropagateNotMinusZero(
BitVector* visited) {
visited->Add(id());
......
......@@ -397,6 +397,11 @@ class HType {
return type_ == kUninitialized;
}
bool IsHeapObject() {
ASSERT(type_ != kUninitialized);
return IsHeapNumber() || IsString() || IsNonPrimitive();
}
static HType TypeFromValue(Handle<Object> value);
const char* ToString();
......@@ -1101,12 +1106,14 @@ class HChange: public HUnaryOperation {
ASSERT(!value->representation().IsNone() && !to.IsNone());
ASSERT(!value->representation().Equals(to));
set_representation(to);
set_type(HType::TaggedNumber());
SetFlag(kUseGVN);
if (deoptimize_on_undefined) SetFlag(kDeoptimizeOnUndefined);
if (is_truncating) SetFlag(kTruncatingToInt32);
}
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
virtual HType CalculateInferredType();
Representation from() { return value()->representation(); }
Representation to() { return representation(); }
......@@ -3260,6 +3267,13 @@ class HLoadGlobalGeneric: public HTemplateInstruction<2> {
};
static inline bool StoringValueNeedsWriteBarrier(HValue* value) {
return !value->type().IsBoolean()
&& !value->type().IsSmi()
&& !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
}
class HStoreGlobalCell: public HUnaryOperation {
public:
HStoreGlobalCell(HValue* value,
......@@ -3275,6 +3289,9 @@ class HStoreGlobalCell: public HUnaryOperation {
bool RequiresHoleCheck() {
return !details_.IsDontDelete() || details_.IsReadOnly();
}
bool NeedsWriteBarrier() {
return StoringValueNeedsWriteBarrier(value());
}
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
......@@ -3355,13 +3372,6 @@ class HLoadContextSlot: public HUnaryOperation {
};
static inline bool StoringValueNeedsWriteBarrier(HValue* value) {
return !value->type().IsBoolean()
&& !value->type().IsSmi()
&& !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
}
class HStoreContextSlot: public HTemplateInstruction<2> {
public:
HStoreContextSlot(HValue* context, int slot_index, HValue* value)
......@@ -3948,7 +3958,7 @@ class HStringCharFromCode: public HTemplateInstruction<2> {
HStringCharFromCode(HValue* context, HValue* char_code) {
SetOperandAt(0, context);
SetOperandAt(1, char_code);
set_representation(Representation::Tagged());
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
}
......@@ -3957,6 +3967,7 @@ class HStringCharFromCode: public HTemplateInstruction<2> {
? Representation::Tagged()
: Representation::Integer32();
}
virtual HType CalculateInferredType();
HValue* context() { return OperandAt(0); }
HValue* value() { return OperandAt(1); }
......@@ -4034,6 +4045,7 @@ class HArrayLiteral: public HMaterializedLiteral<1> {
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral)
......@@ -4068,6 +4080,7 @@ class HObjectLiteral: public HMaterializedLiteral<1> {
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral)
......@@ -4097,6 +4110,7 @@ class HRegExpLiteral: public HMaterializedLiteral<1> {
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
......@@ -4121,6 +4135,7 @@ class HFunctionLiteral: public HTemplateInstruction<1> {
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
......
......@@ -2116,12 +2116,18 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
__ mov(FieldOperand(object, offset), value);
// Cells are always in the remembered set.
__ RecordWriteField(object,
offset,
value,
address,
kSaveFPRegs,
OMIT_REMEMBERED_SET);
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
__ RecordWriteField(object,
offset,
value,
address,
kSaveFPRegs,
OMIT_REMEMBERED_SET,
check_needed);
}
}
......@@ -2149,10 +2155,19 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
Register context = ToRegister(instr->context());
Register value = ToRegister(instr->value());
__ mov(ContextOperand(context, instr->slot_index()), value);
if (instr->needs_write_barrier()) {
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
Register temp = ToRegister(instr->TempAt(0));
int offset = Context::SlotOffset(instr->slot_index());
__ RecordWriteContextSlot(context, offset, value, temp, kSaveFPRegs);
__ RecordWriteContextSlot(context,
offset,
value,
temp,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
}
}
......@@ -3146,21 +3161,36 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
}
// Do the store.
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
if (instr->is_in_object()) {
__ mov(FieldOperand(object, offset), value);
if (instr->needs_write_barrier()) {
if (instr->hydrogen()->NeedsWriteBarrier()) {
Register temp = ToRegister(instr->TempAt(0));
// Update the write barrier for the object for in-object properties.
__ RecordWriteField(object, offset, value, temp, kSaveFPRegs);
__ RecordWriteField(object,
offset,
value,
temp,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
}
} else {
Register temp = ToRegister(instr->TempAt(0));
__ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
__ mov(FieldOperand(temp, offset), value);
if (instr->needs_write_barrier()) {
if (instr->hydrogen()->NeedsWriteBarrier()) {
// Update the write barrier for the properties array.
// object is used as a scratch register.
__ RecordWriteField(temp, offset, value, object, kSaveFPRegs);
__ RecordWriteField(temp,
offset,
value,
object,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
}
}
}
......@@ -3259,13 +3289,21 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
}
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register.
__ lea(key,
FieldOperand(elements,
key,
times_pointer_size,
FixedArray::kHeaderSize));
__ RecordWrite(elements, key, value, kSaveFPRegs);
__ RecordWrite(elements,
key,
value,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
}
}
......@@ -4247,12 +4285,11 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
Condition final_branch_condition = EmitTypeofIs(true_label,
false_label,
input,
instr->type_literal());
EmitBranch(true_block, false_block, final_branch_condition);
Condition final_branch_condition =
EmitTypeofIs(true_label, false_label, input, instr->type_literal());
if (final_branch_condition != no_condition) {
EmitBranch(true_block, false_block, final_branch_condition);
}
}
......@@ -4319,11 +4356,8 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
final_branch_condition = zero;
} else {
final_branch_condition = not_equal;
__ jmp(false_label);
// A dead branch instruction will be generated after this point.
}
return final_branch_condition;
}
......
......@@ -270,8 +270,10 @@ class LCodeGen BASE_EMBEDDED {
// Emits optimized code for typeof x == "y". Modifies input register.
// Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough.
Condition EmitTypeofIs(Label* true_label, Label* false_label,
Register input, Handle<String> type_name);
Condition EmitTypeofIs(Label* true_label,
Label* false_label,
Register input,
Handle<String> type_name);
// Emits optimized code for %_IsObject(x). Preserves input register.
// Returns the condition on which a final split to
......
......@@ -1295,7 +1295,6 @@ class LStoreContextSlot: public LTemplateInstruction<0, 2, 1> {
LOperand* context() { return InputAt(0); }
LOperand* value() { return InputAt(1); }
int slot_index() { return hydrogen()->slot_index(); }
int needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); }
virtual void PrintDataTo(StringStream* stream);
};
......@@ -1617,7 +1616,6 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 1> {
Handle<Object> name() const { return hydrogen()->name(); }
bool is_in_object() { return hydrogen()->is_in_object(); }
int offset() { return hydrogen()->offset(); }
bool needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); }
Handle<Map> transition() const { return hydrogen()->transition(); }
};
......
......@@ -2055,19 +2055,24 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
// Store the value.
__ movq(Operand(address, 0), value);
Label smi_store;
__ JumpIfSmi(value, &smi_store, Label::kNear);
if (instr->hydrogen()->NeedsWriteBarrier()) {
Label smi_store;
HType type = instr->hydrogen()->value()->type();
if (!type.IsHeapNumber() && !type.IsString() && !type.IsNonPrimitive()) {
__ JumpIfSmi(value, &smi_store, Label::kNear);
}
int offset = JSGlobalPropertyCell::kValueOffset - kHeapObjectTag;
__ lea(object, Operand(address, -offset));
// Cells are always in the remembered set.
__ RecordWrite(object,
address,
value,
kSaveFPRegs,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ bind(&smi_store);
int offset = JSGlobalPropertyCell::kValueOffset - kHeapObjectTag;
__ lea(object, Operand(address, -offset));
// Cells are always in the remembered set.
__ RecordWrite(object,
address,
value,
kSaveFPRegs,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ bind(&smi_store);
}
}
......@@ -2094,10 +2099,19 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
Register context = ToRegister(instr->context());
Register value = ToRegister(instr->value());
__ movq(ContextOperand(context, instr->slot_index()), value);
if (instr->needs_write_barrier()) {
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
int offset = Context::SlotOffset(instr->slot_index());
Register scratch = ToRegister(instr->TempAt(0));
__ RecordWriteContextSlot(context, offset, value, scratch, kSaveFPRegs);
__ RecordWriteContextSlot(context,
offset,
value,
scratch,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
}
}
......@@ -3061,21 +3075,36 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
}
// Do the store.
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
if (instr->is_in_object()) {
__ movq(FieldOperand(object, offset), value);
if (instr->needs_write_barrier()) {
if (instr->hydrogen()->NeedsWriteBarrier()) {
Register temp = ToRegister(instr->TempAt(0));
// Update the write barrier for the object for in-object properties.
__ RecordWriteField(object, offset, value, temp, kSaveFPRegs);
__ RecordWriteField(object,
offset,
value,
temp,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
}
} else {
Register temp = ToRegister(instr->TempAt(0));
__ movq(temp, FieldOperand(object, JSObject::kPropertiesOffset));
__ movq(FieldOperand(temp, offset), value);
if (instr->needs_write_barrier()) {
if (instr->hydrogen()->NeedsWriteBarrier()) {
// Update the write barrier for the properties array.
// object is used as a scratch register.
__ RecordWriteField(temp, offset, value, object, kSaveFPRegs);
__ RecordWriteField(temp,
offset,
value,
object,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
}
}
}
......@@ -3182,12 +3211,20 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
}
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register.
__ lea(key, FieldOperand(elements,
key,
times_pointer_size,
FixedArray::kHeaderSize));
__ RecordWrite(elements, key, value, kSaveFPRegs);
__ RecordWrite(elements,
key,
value,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
}
}
......@@ -3975,12 +4012,11 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
Condition final_branch_condition = EmitTypeofIs(true_label,
false_label,
input,
instr->type_literal());
EmitBranch(true_block, false_block, final_branch_condition);
Condition final_branch_condition =
EmitTypeofIs(true_label, false_label, input, instr->type_literal());
if (final_branch_condition != no_condition) {
EmitBranch(true_block, false_block, final_branch_condition);
}
}
......@@ -4048,7 +4084,6 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
final_branch_condition = zero;
} else {
final_branch_condition = never;
__ jmp(false_label);
}
......
......@@ -260,8 +260,10 @@ class LCodeGen BASE_EMBEDDED {
// Emits optimized code for typeof x == "y". Modifies input register.
// Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough.
Condition EmitTypeofIs(Label* true_label, Label* false_label,
Register input, Handle<String> type_name);
Condition EmitTypeofIs(Label* true_label,
Label* false_label,
Register input,
Handle<String> type_name);
// Emits optimized code for %_IsObject(x). Preserves input register.
// Returns the condition on which a final split to
......
......@@ -1260,7 +1260,6 @@ class LStoreContextSlot: public LTemplateInstruction<0, 2, 1> {
LOperand* context() { return InputAt(0); }
LOperand* value() { return InputAt(1); }
int slot_index() { return hydrogen()->slot_index(); }
int needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); }
virtual void PrintDataTo(StringStream* stream);
};
......@@ -1551,7 +1550,6 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 1> {
Handle<Object> name() const { return hydrogen()->name(); }
bool is_in_object() { return hydrogen()->is_in_object(); }
int offset() { return hydrogen()->offset(); }
bool needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); }
Handle<Map> transition() const { return hydrogen()->transition(); }
};
......
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