Index: src/ic/keyed-store-generic.cc |
diff --git a/src/ic/keyed-store-generic.cc b/src/ic/keyed-store-generic.cc |
index 00d2d48a6fd550dd75788d37037207d98ef39b7d..212b4f8429be1f8ce4a241b42d658c033981229f 100644 |
--- a/src/ic/keyed-store-generic.cc |
+++ b/src/ic/keyed-store-generic.cc |
@@ -72,6 +72,13 @@ class KeyedStoreGenericAssembler : public AccessorAssembler { |
Variable* var_accessor_pair, |
Variable* var_accessor_holder, |
Label* readonly, Label* bailout); |
+ |
+ void CheckFieldType(Node* descriptors, Node* name_index, Node* representation, |
+ Node* value, Label* bailout); |
+ void OverwriteExistingFastProperty(Node* object, Node* object_map, |
+ Node* properties, Node* descriptors, |
+ Node* descriptor_name_index, Node* details, |
+ Node* value, Label* slow); |
}; |
void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state, |
@@ -544,6 +551,7 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( |
JumpIfDataProperty(details, &ok_to_write, readonly); |
// Accessor case. |
+ // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject. |
Variable var_details(this, MachineRepresentation::kWord32); |
LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index, |
&var_details, var_accessor_pair); |
@@ -599,6 +607,146 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( |
Bind(&ok_to_write); |
} |
+void KeyedStoreGenericAssembler::CheckFieldType(Node* descriptors, |
+ Node* name_index, |
+ Node* representation, |
+ Node* value, Label* bailout) { |
+ Label r_smi(this), r_double(this), r_heapobject(this), all_fine(this); |
+ // Ignore FLAG_track_fields etc. and always emit code for all checks, |
+ // because this builtin is part of the snapshot and therefore should |
+ // be flag independent. |
+ GotoIf(Word32Equal(representation, Int32Constant(Representation::kSmi)), |
+ &r_smi); |
+ GotoIf(Word32Equal(representation, Int32Constant(Representation::kDouble)), |
+ &r_double); |
+ GotoIf( |
+ Word32Equal(representation, Int32Constant(Representation::kHeapObject)), |
+ &r_heapobject); |
+ GotoIf(Word32Equal(representation, Int32Constant(Representation::kNone)), |
+ bailout); |
+ CSA_ASSERT(this, Word32Equal(representation, |
+ Int32Constant(Representation::kTagged))); |
+ Goto(&all_fine); |
+ |
+ Bind(&r_smi); |
+ { Branch(TaggedIsSmi(value), &all_fine, bailout); } |
+ |
+ Bind(&r_double); |
+ { |
+ GotoIf(TaggedIsSmi(value), &all_fine); |
+ Node* value_map = LoadMap(value); |
+ // While supporting mutable HeapNumbers would be straightforward, such |
+ // objects should not end up here anyway. |
+ CSA_ASSERT(this, |
+ WordNotEqual(value_map, |
+ LoadRoot(Heap::kMutableHeapNumberMapRootIndex))); |
+ Branch(IsHeapNumberMap(value_map), &all_fine, bailout); |
+ } |
+ |
+ Bind(&r_heapobject); |
+ { |
+ GotoIf(TaggedIsSmi(value), bailout); |
+ Node* field_type = |
+ LoadValueByKeyIndex<DescriptorArray>(descriptors, name_index); |
+ intptr_t kNoneType = reinterpret_cast<intptr_t>(FieldType::None()); |
+ intptr_t kAnyType = reinterpret_cast<intptr_t>(FieldType::Any()); |
+ // FieldType::None can't hold any value. |
+ GotoIf(WordEqual(field_type, IntPtrConstant(kNoneType)), bailout); |
+ // FieldType::Any can hold any value. |
+ GotoIf(WordEqual(field_type, IntPtrConstant(kAnyType)), &all_fine); |
+ CSA_ASSERT(this, IsWeakCell(field_type)); |
+ // Cleared WeakCells count as FieldType::None, which can't hold any value. |
+ field_type = LoadWeakCellValue(field_type, bailout); |
+ // FieldType::Class(...) performs a map check. |
+ CSA_ASSERT(this, IsMap(field_type)); |
+ Branch(WordEqual(LoadMap(value), field_type), &all_fine, bailout); |
+ } |
+ |
+ Bind(&all_fine); |
+} |
+ |
+void KeyedStoreGenericAssembler::OverwriteExistingFastProperty( |
+ Node* object, Node* object_map, Node* properties, Node* descriptors, |
+ Node* descriptor_name_index, Node* details, Node* value, Label* slow) { |
+ // Properties in descriptors can't be overwritten without map transition. |
+ GotoIf(Word32NotEqual(DecodeWord32<PropertyDetails::LocationField>(details), |
+ Int32Constant(kField)), |
+ slow); |
+ |
+ if (FLAG_track_constant_fields) { |
+ // TODO(ishell): Taking the slow path is not necessary if new and old |
+ // values are identical. |
+ GotoIf(Word32Equal(DecodeWord32<PropertyDetails::ConstnessField>(details), |
+ Int32Constant(kConst)), |
+ slow); |
+ } |
+ |
+ Label done(this); |
+ Node* representation = |
+ DecodeWord32<PropertyDetails::RepresentationField>(details); |
+ |
+ CheckFieldType(descriptors, descriptor_name_index, representation, value, |
+ slow); |
+ Node* field_index = |
+ DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details); |
+ Node* inobject_properties = LoadMapInobjectProperties(object_map); |
+ |
+ Label inobject(this), backing_store(this); |
+ Branch(UintPtrLessThan(field_index, inobject_properties), &inobject, |
+ &backing_store); |
+ |
+ Bind(&inobject); |
+ { |
+ Node* field_offset = |
+ IntPtrMul(IntPtrSub(LoadMapInstanceSize(object_map), |
+ IntPtrSub(inobject_properties, field_index)), |
+ IntPtrConstant(kPointerSize)); |
+ Label tagged_rep(this), double_rep(this); |
+ Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)), |
+ &double_rep, &tagged_rep); |
+ Bind(&double_rep); |
+ { |
+ Node* double_value = ChangeNumberToFloat64(value); |
+ if (FLAG_unbox_double_fields) { |
+ StoreObjectFieldNoWriteBarrier(object, field_offset, double_value, |
+ MachineRepresentation::kFloat64); |
+ } else { |
+ Node* mutable_heap_number = LoadObjectField(object, field_offset); |
+ StoreHeapNumberValue(mutable_heap_number, double_value); |
+ } |
+ Goto(&done); |
+ } |
+ |
+ Bind(&tagged_rep); |
+ { |
+ StoreObjectField(object, field_offset, value); |
+ Goto(&done); |
+ } |
+ } |
+ |
+ Bind(&backing_store); |
+ { |
+ Node* backing_store_index = IntPtrSub(field_index, inobject_properties); |
+ Label tagged_rep(this), double_rep(this); |
+ Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)), |
+ &double_rep, &tagged_rep); |
+ Bind(&double_rep); |
+ { |
+ Node* double_value = ChangeNumberToFloat64(value); |
+ Node* mutable_heap_number = |
+ LoadFixedArrayElement(properties, backing_store_index); |
+ StoreHeapNumberValue(mutable_heap_number, double_value); |
+ Goto(&done); |
+ } |
+ Bind(&tagged_rep); |
+ { |
+ StoreFixedArrayElement(properties, backing_store_index, value); |
+ Goto(&done); |
+ } |
+ } |
+ Bind(&done); |
+} |
+ |
void KeyedStoreGenericAssembler::EmitGenericPropertyStore( |
Node* receiver, Node* receiver_map, const StoreICParameters* p, Label* slow, |
LanguageMode language_mode) { |
@@ -613,10 +761,40 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( |
Bind(&fast_properties); |
{ |
- // TODO(jkummerow): Does it make sense to support some cases here inline? |
- // Maybe overwrite existing writable properties? |
- // Maybe support map transitions? |
- Goto(&stub_cache); |
+ Comment("fast property store"); |
+ Node* bitfield3 = LoadMapBitField3(receiver_map); |
+ Node* descriptors = LoadMapDescriptors(receiver_map); |
+ Label descriptor_found(this); |
+ Variable var_name_index(this, MachineType::PointerRepresentation()); |
+ // TODO(jkummerow): Maybe look for existing map transitions? |
+ Label* notfound = &stub_cache; |
+ DescriptorLookup(p->name, descriptors, bitfield3, &descriptor_found, |
+ &var_name_index, notfound); |
+ |
+ Bind(&descriptor_found); |
+ { |
+ Node* name_index = var_name_index.value(); |
+ Node* details = |
+ LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index); |
+ Label data_property(this); |
+ JumpIfDataProperty(details, &data_property, &readonly); |
+ |
+ // Accessor case. |
+ // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject. |
+ Variable var_details(this, MachineRepresentation::kWord32); |
+ LoadPropertyFromFastObject(receiver, receiver_map, descriptors, |
+ name_index, &var_details, &var_accessor_pair); |
+ var_accessor_holder.Bind(receiver); |
+ Goto(&accessor); |
+ |
+ Bind(&data_property); |
+ { |
+ OverwriteExistingFastProperty(receiver, receiver_map, properties, |
+ descriptors, name_index, details, |
+ p->value, slow); |
+ Return(p->value); |
+ } |
+ } |
} |
Bind(&dictionary_properties); |