Hydrogenize (and share) StoreField except heapobject (for now).

BUG=
R=jkummerow@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22909 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
verwaest@chromium.org 2014-08-06 09:31:10 +00:00
parent df7057b3ce
commit b8ab822040
8 changed files with 182 additions and 309 deletions

View File

@ -598,82 +598,38 @@ void NamedStoreHandlerCompiler::GenerateStoreField(
FieldIndex index = lookup->GetFieldIndex();
Representation representation = lookup->representation();
DCHECK(!representation.IsNone());
if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
__ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Label do_store;
while (true) {
__ CompareMap(scratch1, it.Current(), &do_store);
it.Advance();
if (it.Done()) {
__ b(ne, miss_label);
break;
}
__ b(eq, &do_store);
DCHECK(lookup->representation().IsHeapObject());
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
__ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Label do_store;
while (true) {
__ CompareMap(scratch1, it.Current(), &do_store);
it.Advance();
if (it.Done()) {
__ b(ne, miss_label);
break;
}
__ bind(&do_store);
__ b(eq, &do_store);
}
} else if (representation.IsDouble()) {
// Load the double storage.
if (index.is_inobject()) {
__ ldr(scratch1, FieldMemOperand(receiver_reg, index.offset()));
} else {
__ ldr(scratch1,
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ ldr(scratch1, FieldMemOperand(scratch1, index.offset()));
}
// Store the value into the storage.
Label do_store, heap_number;
__ JumpIfNotSmi(value_reg, &heap_number);
__ SmiUntag(scratch2, value_reg);
__ vmov(s0, scratch2);
__ vcvt_f64_s32(d0, s0);
__ jmp(&do_store);
__ bind(&heap_number);
__ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex,
miss_label, DONT_DO_SMI_CHECK);
__ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
__ bind(&do_store);
__ vstr(d0, FieldMemOperand(scratch1, HeapNumber::kValueOffset));
// Return the value (register r0).
DCHECK(value_reg.is(r0));
__ Ret();
return;
}
// TODO(verwaest): Share this code as a code stub.
SmiCheck smi_check = representation.IsTagged()
? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
if (index.is_inobject()) {
// Set the property straight into the object.
__ str(value_reg, FieldMemOperand(receiver_reg, index.offset()));
if (!representation.IsSmi()) {
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Pass the now unused name_reg as a scratch register.
__ mov(name_reg, value_reg);
__ RecordWriteField(receiver_reg,
index.offset(),
name_reg,
scratch1,
kLRHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
// Update the write barrier for the array address.
// Pass the now unused name_reg as a scratch register.
__ mov(name_reg, value_reg);
__ RecordWriteField(receiver_reg, index.offset(), name_reg, scratch1,
kLRHasNotBeenSaved, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
} else {
// Write to the properties array.
// Get the properties array
@ -681,22 +637,15 @@ void NamedStoreHandlerCompiler::GenerateStoreField(
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ str(value_reg, FieldMemOperand(scratch1, index.offset()));
if (!representation.IsSmi()) {
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Ok to clobber receiver_reg and name_reg, since we return.
__ mov(name_reg, value_reg);
__ RecordWriteField(scratch1,
index.offset(),
name_reg,
receiver_reg,
kLRHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
// Update the write barrier for the array address.
// Ok to clobber receiver_reg and name_reg, since we return.
__ mov(name_reg, value_reg);
__ RecordWriteField(scratch1, index.offset(), name_reg, receiver_reg,
kLRHasNotBeenSaved, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
}
// Return the value (register r0).

View File

@ -548,84 +548,38 @@ void NamedStoreHandlerCompiler::GenerateStoreField(
FieldIndex index = lookup->GetFieldIndex();
Representation representation = lookup->representation();
DCHECK(!representation.IsNone());
if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
__ Ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Label do_store;
while (true) {
__ CompareMap(scratch1, it.Current());
it.Advance();
if (it.Done()) {
__ B(ne, miss_label);
break;
}
__ B(eq, &do_store);
DCHECK(lookup->representation().IsHeapObject());
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
__ Ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Label do_store;
while (true) {
__ CompareMap(scratch1, it.Current());
it.Advance();
if (it.Done()) {
__ B(ne, miss_label);
break;
}
__ Bind(&do_store);
__ B(eq, &do_store);
}
} else if (representation.IsDouble()) {
UseScratchRegisterScope temps(masm());
DoubleRegister temp_double = temps.AcquireD();
__ SmiUntagToDouble(temp_double, value_reg, kSpeculativeUntag);
// Load the double storage.
if (index.is_inobject()) {
__ Ldr(scratch1, FieldMemOperand(receiver_reg, index.offset()));
} else {
__ Ldr(scratch1,
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ Ldr(scratch1, FieldMemOperand(scratch1, index.offset()));
}
// Store the value into the storage.
Label do_store, heap_number;
__ JumpIfSmi(value_reg, &do_store);
__ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex,
miss_label, DONT_DO_SMI_CHECK);
__ Ldr(temp_double, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
__ Bind(&do_store);
__ Str(temp_double, FieldMemOperand(scratch1, HeapNumber::kValueOffset));
// Return the value (register x0).
DCHECK(value_reg.is(x0));
__ Ret();
return;
}
// TODO(verwaest): Share this code as a code stub.
SmiCheck smi_check = representation.IsTagged()
? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
if (index.is_inobject()) {
// Set the property straight into the object.
__ Str(value_reg, FieldMemOperand(receiver_reg, index.offset()));
if (!representation.IsSmi()) {
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Pass the now unused name_reg as a scratch register.
__ Mov(name_reg, value_reg);
__ RecordWriteField(receiver_reg,
index.offset(),
name_reg,
scratch1,
kLRHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
// Update the write barrier for the array address.
// Pass the now unused name_reg as a scratch register.
__ Mov(name_reg, value_reg);
__ RecordWriteField(receiver_reg, index.offset(), name_reg, scratch1,
kLRHasNotBeenSaved, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
} else {
// Write to the properties array.
// Get the properties array
@ -633,22 +587,15 @@ void NamedStoreHandlerCompiler::GenerateStoreField(
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ Str(value_reg, FieldMemOperand(scratch1, index.offset()));
if (!representation.IsSmi()) {
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Ok to clobber receiver_reg and name_reg, since we return.
__ Mov(name_reg, value_reg);
__ RecordWriteField(scratch1,
index.offset(),
name_reg,
receiver_reg,
kLRHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
// Update the write barrier for the array address.
// Ok to clobber receiver_reg and name_reg, since we return.
__ Mov(name_reg, value_reg);
__ RecordWriteField(scratch1, index.offset(), name_reg, receiver_reg,
kLRHasNotBeenSaved, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
}
__ Bind(&exit);

View File

@ -62,6 +62,8 @@ class CodeStubGraphBuilderBase : public HGraphBuilder {
HLoadNamedField* BuildLoadNamedField(HValue* object,
FieldIndex index);
void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index,
Representation representation);
enum ArgumentClass {
NONE,
@ -607,6 +609,42 @@ HValue* CodeStubGraphBuilder<LoadConstantStub>::BuildCodeStub() {
Handle<Code> LoadConstantStub::GenerateCode() { return DoGenerateCode(this); }
void CodeStubGraphBuilderBase::BuildStoreNamedField(
HValue* object, HValue* value, FieldIndex index,
Representation representation) {
DCHECK(!index.is_double() || representation.IsDouble());
int offset = index.offset();
HObjectAccess access =
index.is_inobject()
? HObjectAccess::ForObservableJSObjectOffset(offset, representation)
: HObjectAccess::ForBackingStoreOffset(offset, representation);
if (representation.IsDouble()) {
// Load the heap number.
object = Add<HLoadNamedField>(
object, static_cast<HValue*>(NULL),
access.WithRepresentation(Representation::Tagged()));
// Store the double value into it.
access = HObjectAccess::ForHeapNumberValue();
} else if (representation.IsHeapObject()) {
BuildCheckHeapObject(value);
}
Add<HStoreNamedField>(object, access, value, STORE_TO_INITIALIZED_ENTRY);
}
template <>
HValue* CodeStubGraphBuilder<StoreFieldStub>::BuildCodeStub() {
BuildStoreNamedField(GetParameter(0), GetParameter(2), casted_stub()->index(),
casted_stub()->representation());
return GetParameter(2);
}
Handle<Code> StoreFieldStub::GenerateCode() { return DoGenerateCode(this); }
template <>
HValue* CodeStubGraphBuilder<StringLengthStub>::BuildCodeStub() {
HValue* string = BuildLoadNamedField(GetParameter(0),

View File

@ -76,6 +76,7 @@ namespace internal {
V(CallApiGetter) \
/* IC Handler stubs */ \
V(LoadField) \
V(StoreField) \
V(LoadConstant) \
V(StringLength)
@ -920,19 +921,13 @@ class LoadFieldStub: public HandlerStub {
public:
LoadFieldStub(Isolate* isolate, FieldIndex index)
: HandlerStub(isolate), index_(index) {
int property_index_key = index_.GetLoadFieldStubKey();
int property_index_key = index_.GetFieldAccessStubKey();
bit_field_ = EncodedLoadFieldByIndexBits::encode(property_index_key);
}
virtual Handle<Code> GenerateCode() V8_OVERRIDE;
Representation representation() {
if (unboxed_double()) return Representation::Double();
return Representation::Tagged();
}
FieldIndex index() const { return index_; }
bool unboxed_double() { return index_.is_double(); }
protected:
explicit LoadFieldStub(Isolate* isolate);
@ -980,6 +975,36 @@ class StringLengthStub: public HandlerStub {
};
class StoreFieldStub : public HandlerStub {
public:
StoreFieldStub(Isolate* isolate, FieldIndex index,
Representation representation)
: HandlerStub(isolate), index_(index), representation_(representation) {
int property_index_key = index_.GetFieldAccessStubKey();
bit_field_ = EncodedStoreFieldByIndexBits::encode(property_index_key) |
RepresentationBits::encode(
PropertyDetails::EncodeRepresentation(representation));
}
virtual Handle<Code> GenerateCode() V8_OVERRIDE;
FieldIndex index() const { return index_; }
Representation representation() { return representation_; }
protected:
explicit StoreFieldStub(Isolate* isolate);
virtual Code::Kind kind() const { return Code::STORE_IC; }
virtual Code::StubType GetStubType() { return Code::FAST; }
private:
class EncodedStoreFieldByIndexBits : public BitField<int, 0, 13> {};
class RepresentationBits : public BitField<int, 13, 4> {};
virtual CodeStub::Major MajorKey() const { return StoreField; }
FieldIndex index_;
Representation representation_;
};
class StoreGlobalStub : public HandlerStub {
public:
StoreGlobalStub(Isolate* isolate, bool is_constant, bool check_global)

View File

@ -65,7 +65,7 @@ class FieldIndex V8_FINAL {
int GetKeyedLookupCacheIndex() const;
int GetLoadFieldStubKey() const {
int GetFieldAccessStubKey() const {
return bit_field_ &
(IsInObjectBits::kMask | IsDoubleBits::kMask | IndexBits::kMask);
}

View File

@ -579,94 +579,44 @@ void NamedStoreHandlerCompiler::GenerateStoreField(
DCHECK(!object->IsJSGlobalProxy());
FieldIndex index = lookup->GetFieldIndex();
Representation representation = lookup->representation();
DCHECK(!representation.IsNone());
if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
Label do_store;
while (true) {
__ CompareMap(value_reg, it.Current());
it.Advance();
if (it.Done()) {
__ j(not_equal, miss_label);
break;
}
__ j(equal, &do_store, Label::kNear);
DCHECK(lookup->representation().IsHeapObject());
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
Label do_store;
while (true) {
__ CompareMap(value_reg, it.Current());
it.Advance();
if (it.Done()) {
__ j(not_equal, miss_label);
break;
}
__ bind(&do_store);
__ j(equal, &do_store, Label::kNear);
}
} else if (representation.IsDouble()) {
// Load the double storage.
if (index.is_inobject()) {
__ mov(scratch1, FieldOperand(receiver_reg, index.offset()));
} else {
__ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
__ mov(scratch1, FieldOperand(scratch1, index.offset()));
}
// Store the value into the storage.
Label do_store, heap_number;
__ JumpIfNotSmi(value_reg, &heap_number);
__ SmiUntag(value_reg);
__ Cvtsi2sd(xmm0, value_reg);
__ SmiTag(value_reg);
__ jmp(&do_store);
__ bind(&heap_number);
__ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label,
DONT_DO_SMI_CHECK);
__ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
__ bind(&do_store);
__ movsd(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0);
// Return the value (register eax).
DCHECK(value_reg.is(eax));
__ ret(0);
return;
}
DCHECK(!representation.IsDouble());
// TODO(verwaest): Share this code as a code stub.
SmiCheck smi_check = representation.IsTagged()
? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
if (index.is_inobject()) {
// Set the property straight into the object.
__ mov(FieldOperand(receiver_reg, index.offset()), value_reg);
if (!representation.IsSmi()) {
// Update the write barrier for the array address.
// Pass the value being stored in the now unused name_reg.
__ mov(name_reg, value_reg);
__ RecordWriteField(receiver_reg,
index.offset(),
name_reg,
scratch1,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
// Update the write barrier for the array address.
// Pass the value being stored in the now unused name_reg.
__ mov(name_reg, value_reg);
__ RecordWriteField(receiver_reg, index.offset(), name_reg, scratch1,
kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
} else {
// Write to the properties array.
// Get the properties array (optimistically).
__ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
__ mov(FieldOperand(scratch1, index.offset()), value_reg);
if (!representation.IsSmi()) {
// Update the write barrier for the array address.
// Pass the value being stored in the now unused name_reg.
__ mov(name_reg, value_reg);
__ RecordWriteField(scratch1,
index.offset(),
name_reg,
receiver_reg,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
// Update the write barrier for the array address.
// Pass the value being stored in the now unused name_reg.
__ mov(name_reg, value_reg);
__ RecordWriteField(scratch1, index.offset(), name_reg, receiver_reg,
kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
}
// Return the value (register eax).

View File

@ -1474,6 +1474,11 @@ Handle<Code> StoreIC::CompileStoreHandler(LookupResult* lookup,
} else {
switch (lookup->type()) {
case FIELD:
if (!lookup->representation().IsHeapObject()) {
StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
lookup->representation());
return stub.GetCode();
}
return compiler.CompileStoreField(lookup, name);
case NORMAL:
if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) {

View File

@ -528,85 +528,44 @@ void NamedStoreHandlerCompiler::GenerateStoreField(
FieldIndex index = lookup->GetFieldIndex();
Representation representation = lookup->representation();
DCHECK(!representation.IsNone());
if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
Label do_store;
while (true) {
__ CompareMap(value_reg, it.Current());
it.Advance();
if (it.Done()) {
__ j(not_equal, miss_label);
break;
}
__ j(equal, &do_store, Label::kNear);
DCHECK(lookup->representation().IsHeapObject());
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
Label do_store;
while (true) {
__ CompareMap(value_reg, it.Current());
it.Advance();
if (it.Done()) {
__ j(not_equal, miss_label);
break;
}
__ bind(&do_store);
__ j(equal, &do_store, Label::kNear);
}
} else if (representation.IsDouble()) {
// Load the double storage.
if (index.is_inobject()) {
__ movp(scratch1, FieldOperand(receiver_reg, index.offset()));
} else {
__ movp(scratch1,
FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
__ movp(scratch1, FieldOperand(scratch1, index.offset()));
}
// Store the value into the storage.
Label do_store, heap_number;
__ JumpIfNotSmi(value_reg, &heap_number);
__ SmiToInteger32(scratch2, value_reg);
__ Cvtlsi2sd(xmm0, scratch2);
__ jmp(&do_store);
__ bind(&heap_number);
__ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label,
DONT_DO_SMI_CHECK);
__ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
__ bind(&do_store);
__ movsd(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0);
// Return the value (register rax).
DCHECK(value_reg.is(rax));
__ ret(0);
return;
}
// TODO(verwaest): Share this code as a code stub.
SmiCheck smi_check = representation.IsTagged()
? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
if (index.is_inobject()) {
// Set the property straight into the object.
__ movp(FieldOperand(receiver_reg, index.offset()), value_reg);
if (!representation.IsSmi()) {
// Update the write barrier for the array address.
// Pass the value being stored in the now unused name_reg.
__ movp(name_reg, value_reg);
__ RecordWriteField(
receiver_reg, index.offset(), name_reg, scratch1, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, smi_check);
}
// Update the write barrier for the array address.
// Pass the value being stored in the now unused name_reg.
__ movp(name_reg, value_reg);
__ RecordWriteField(receiver_reg, index.offset(), name_reg, scratch1,
kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
} else {
// Write to the properties array.
// Get the properties array (optimistically).
__ movp(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
__ movp(FieldOperand(scratch1, index.offset()), value_reg);
if (!representation.IsSmi()) {
// Update the write barrier for the array address.
// Pass the value being stored in the now unused name_reg.
__ movp(name_reg, value_reg);
__ RecordWriteField(
scratch1, index.offset(), name_reg, receiver_reg, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, smi_check);
}
// Update the write barrier for the array address.
// Pass the value being stored in the now unused name_reg.
__ movp(name_reg, value_reg);
__ RecordWriteField(scratch1, index.offset(), name_reg, receiver_reg,
kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
}
// Return the value (register rax).