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
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).
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);
- }
- } 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()));
+ __ B(eq, &do_store);
}
-
- // 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
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);
HLoadNamedField* BuildLoadNamedField(HValue* object,
FieldIndex index);
+ void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index,
+ Representation representation);
enum ArgumentClass {
NONE,
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),
V(CallApiGetter) \
/* IC Handler stubs */ \
V(LoadField) \
+ V(StoreField) \
V(LoadConstant) \
V(StringLength)
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);
};
+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)
int GetKeyedLookupCacheIndex() const;
- int GetLoadFieldStubKey() const {
+ int GetFieldAccessStubKey() const {
return bit_field_ &
(IsInObjectBits::kMask | IsDoubleBits::kMask | IndexBits::kMask);
}
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).
} 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()) {
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).