| 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); | 
|  |