Version 5.0.71.54 (cherry-pick)

Merged 9fa206e1f4a36280672a4fb144cd7f78484b3c11
Merged 3e0be8d7fca5b28bcb18ae413be6392325d0b54c

[runtime] Ensure that all elements kind transitions are chained to the root map.

[runtime] Don't use ElementsTransitionAndStoreStub for transitions that involve instance rewriting.

BUG=chromium:617524,v8:5009,v8:5009
LOG=N
R=verwaest@chromium.org

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

Cr-Commit-Position: refs/branch-heads/5.0@{#65}
Cr-Branched-From: ad16e6c2cbd2c6b0f2e8ff944ac245561c682ac2-refs/heads/5.0.71@{#1}
Cr-Branched-From: bd9df50d75125ee2ad37b3d92c8f50f0a8b5f030-refs/heads/master@{#34215}
diff --git a/include/v8-version.h b/include/v8-version.h
index d201761..39a537d 100644
--- a/include/v8-version.h
+++ b/include/v8-version.h
@@ -11,7 +11,7 @@
 #define V8_MAJOR_VERSION 5
 #define V8_MINOR_VERSION 0
 #define V8_BUILD_NUMBER 71
-#define V8_PATCH_LEVEL 53
+#define V8_PATCH_LEVEL 54
 
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/compiler/access-info.cc b/src/compiler/access-info.cc
index 4a2a857..e38f629 100644
--- a/src/compiler/access-info.cc
+++ b/src/compiler/access-info.cc
@@ -192,12 +192,12 @@
   MapTransitionList transitions(maps.length());
   for (Handle<Map> map : maps) {
     if (Map::TryUpdate(map).ToHandle(&map)) {
-      Handle<Map> transition_target =
-          Map::FindTransitionedMap(map, &possible_transition_targets);
-      if (transition_target.is_null()) {
+      Map* transition_target =
+          map->FindElementsKindTransitionedMap(&possible_transition_targets);
+      if (transition_target == nullptr) {
         receiver_maps.Add(map);
       } else {
-        transitions.push_back(std::make_pair(map, transition_target));
+        transitions.push_back(std::make_pair(map, handle(transition_target)));
       }
     }
   }
diff --git a/src/crankshaft/hydrogen.cc b/src/crankshaft/hydrogen.cc
index b6fdd3a..4e34d17 100644
--- a/src/crankshaft/hydrogen.cc
+++ b/src/crankshaft/hydrogen.cc
@@ -7600,9 +7600,13 @@
   // Get transition target for each map (NULL == no transition).
   for (int i = 0; i < maps->length(); ++i) {
     Handle<Map> map = maps->at(i);
-    Handle<Map> transitioned_map =
-        Map::FindTransitionedMap(map, &possible_transitioned_maps);
-    transition_target.Add(transitioned_map);
+    Map* transitioned_map =
+        map->FindElementsKindTransitionedMap(&possible_transitioned_maps);
+    if (transitioned_map != nullptr) {
+      transition_target.Add(handle(transitioned_map));
+    } else {
+      transition_target.Add(Handle<Map>());
+    }
   }
 
   MapHandleList untransitionable_maps(maps->length());
diff --git a/src/ic/ic-compiler.cc b/src/ic/ic-compiler.cc
index f74c69e..bc8a493 100644
--- a/src/ic/ic-compiler.cc
+++ b/src/ic/ic-compiler.cc
@@ -235,8 +235,11 @@
   for (int i = 0; i < receiver_maps->length(); ++i) {
     Handle<Map> receiver_map(receiver_maps->at(i));
     Handle<Code> cached_stub;
-    Handle<Map> transitioned_map =
-        Map::FindTransitionedMap(receiver_map, receiver_maps);
+    Handle<Map> transitioned_map;
+    {
+      Map* tmap = receiver_map->FindElementsKindTransitionedMap(receiver_maps);
+      if (tmap != nullptr) transitioned_map = handle(tmap);
+    }
 
     // TODO(mvstanton): The code below is doing pessimistic elements
     // transitions. I would like to stop doing that and rely on Allocation Site
diff --git a/src/ic/ic.cc b/src/ic/ic.cc
index c0b3e49..62669ca 100644
--- a/src/ic/ic.cc
+++ b/src/ic/ic.cc
@@ -836,11 +836,12 @@
   ElementsKind target_elements_kind = target_map->elements_kind();
   bool more_general_transition = IsMoreGeneralElementsKindTransition(
       source_map->elements_kind(), target_elements_kind);
-  Map* transitioned_map =
-      more_general_transition
-          ? source_map->LookupElementsTransitionMap(target_elements_kind)
-          : NULL;
-
+  Map* transitioned_map = nullptr;
+  if (more_general_transition) {
+    MapHandleList map_list;
+    map_list.Add(handle(target_map));
+    transitioned_map = source_map->FindElementsKindTransitionedMap(&map_list);
+  }
   return transitioned_map == target_map;
 }
 
diff --git a/src/objects-inl.h b/src/objects-inl.h
index e00478a..3b139f8 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -18,6 +18,7 @@
 #include "src/conversions-inl.h"
 #include "src/factory.h"
 #include "src/field-index-inl.h"
+#include "src/field-type.h"
 #include "src/handles-inl.h"
 #include "src/heap/heap-inl.h"
 #include "src/heap/heap.h"
@@ -2724,6 +2725,25 @@
   return NULL;
 }
 
+// static
+Handle<Map> Map::ReconfigureProperty(Handle<Map> map, int modify_index,
+                                     PropertyKind new_kind,
+                                     PropertyAttributes new_attributes,
+                                     Representation new_representation,
+                                     Handle<FieldType> new_field_type,
+                                     StoreMode store_mode) {
+  return Reconfigure(map, map->elements_kind(), modify_index, new_kind,
+                     new_attributes, new_representation, new_field_type,
+                     store_mode);
+}
+
+// static
+Handle<Map> Map::ReconfigureElementsKind(Handle<Map> map,
+                                         ElementsKind new_elements_kind) {
+  return Reconfigure(map, new_elements_kind, -1, kData, NONE,
+                     Representation::None(), FieldType::None(map->GetIsolate()),
+                     ALLOW_IN_DESCRIPTOR);
+}
 
 Object** DescriptorArray::GetKeySlot(int descriptor_number) {
   DCHECK(descriptor_number < number_of_descriptors());
diff --git a/src/objects.cc b/src/objects.cc
index cc0712a..bb15b9a 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2681,6 +2681,16 @@
   }
 }
 
+bool Map::InstancesNeedRewriting(Map* target) {
+  int target_number_of_fields = target->NumberOfFields();
+  int target_inobject = target->GetInObjectProperties();
+  int target_unused = target->unused_property_fields();
+  int old_number_of_fields;
+
+  return InstancesNeedRewriting(target, target_number_of_fields,
+                                target_inobject, target_unused,
+                                &old_number_of_fields);
+}
 
 bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
                                  int target_inobject, int target_unused,
@@ -3141,10 +3151,10 @@
   return result;
 }
 
-
 Handle<Map> Map::CopyGeneralizeAllRepresentations(
-    Handle<Map> map, int modify_index, StoreMode store_mode, PropertyKind kind,
-    PropertyAttributes attributes, const char* reason) {
+    Handle<Map> map, ElementsKind elements_kind, int modify_index,
+    StoreMode store_mode, PropertyKind kind, PropertyAttributes attributes,
+    const char* reason) {
   Isolate* isolate = map->GetIsolate();
   Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
@@ -3200,6 +3210,7 @@
           MaybeHandle<Object>());
     }
   }
+  new_map->set_elements_kind(elements_kind);
   return new_map;
 }
 
@@ -3437,9 +3448,9 @@
   }
 }
 
-
-// Reconfigures property at |modify_index| with |new_kind|, |new_attributes|,
-// |store_mode| and/or |new_representation|/|new_field_type|.
+// Reconfigures elements kind to |new_elements_kind| and/or property at
+// |modify_index| with |new_kind|, |new_attributes|, |store_mode| and/or
+// |new_representation|/|new_field_type|.
 // If |modify_index| is negative then no properties are reconfigured but the
 // map is migrated to the up-to-date non-deprecated state.
 //
@@ -3449,6 +3460,7 @@
 // any potential new (partial) version of the type in the transition tree.
 // To do this, on each rewrite:
 // - Search the root of the transition tree using FindRootMap.
+// - Find/create a |root_map| with requested |new_elements_kind|.
 // - Find |target_map|, the newest matching version of this map using the
 //   virtually "enhanced" |old_map|'s descriptor array (i.e. whose entry at
 //   |modify_index| is considered to be of |new_kind| and having
@@ -3464,12 +3476,13 @@
 //   Return it.
 // - Otherwise, invalidate the outdated transition target from |target_map|, and
 //   replace its transition tree with a new branch for the updated descriptors.
-Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
-                                     PropertyKind new_kind,
-                                     PropertyAttributes new_attributes,
-                                     Representation new_representation,
-                                     Handle<FieldType> new_field_type,
-                                     StoreMode store_mode) {
+Handle<Map> Map::Reconfigure(Handle<Map> old_map,
+                             ElementsKind new_elements_kind, int modify_index,
+                             PropertyKind new_kind,
+                             PropertyAttributes new_attributes,
+                             Representation new_representation,
+                             Handle<FieldType> new_field_type,
+                             StoreMode store_mode) {
   DCHECK_NE(kAccessor, new_kind);  // TODO(ishell): not supported yet.
   DCHECK(store_mode != FORCE_FIELD || modify_index >= 0);
   Isolate* isolate = old_map->GetIsolate();
@@ -3484,7 +3497,8 @@
   // uninitialized value for representation None can be overwritten by both
   // smi and tagged values. Doubles, however, would require a box allocation.
   if (modify_index >= 0 && !new_representation.IsNone() &&
-      !new_representation.IsDouble()) {
+      !new_representation.IsDouble() &&
+      old_map->elements_kind() == new_elements_kind) {
     PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
     Representation old_representation = old_details.representation();
 
@@ -3517,38 +3531,39 @@
   // Check the state of the root map.
   Handle<Map> root_map(old_map->FindRootMap(), isolate);
   if (!old_map->EquivalentToForTransition(*root_map)) {
-    return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
-                                            new_kind, new_attributes,
-                                            "GenAll_NotEquivalent");
+    return CopyGeneralizeAllRepresentations(
+        old_map, new_elements_kind, modify_index, store_mode, new_kind,
+        new_attributes, "GenAll_NotEquivalent");
   }
 
   ElementsKind from_kind = root_map->elements_kind();
-  ElementsKind to_kind = old_map->elements_kind();
+  ElementsKind to_kind = new_elements_kind;
   // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
   if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
+      to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
       to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
       !(IsTransitionableFastElementsKind(from_kind) &&
         IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
-    return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
-                                            new_kind, new_attributes,
-                                            "GenAll_InvalidElementsTransition");
+    return CopyGeneralizeAllRepresentations(
+        old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
+        "GenAll_InvalidElementsTransition");
   }
   int root_nof = root_map->NumberOfOwnDescriptors();
   if (modify_index >= 0 && modify_index < root_nof) {
     PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
     if (old_details.kind() != new_kind ||
         old_details.attributes() != new_attributes) {
-      return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
-                                              new_kind, new_attributes,
-                                              "GenAll_RootModification1");
+      return CopyGeneralizeAllRepresentations(
+          old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
+          "GenAll_RootModification1");
     }
     if ((old_details.type() != DATA && store_mode == FORCE_FIELD) ||
         (old_details.type() == DATA &&
          (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
           !new_representation.fits_into(old_details.representation())))) {
-      return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
-                                              new_kind, new_attributes,
-                                              "GenAll_RootModification2");
+      return CopyGeneralizeAllRepresentations(
+          old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
+          "GenAll_RootModification2");
     }
   }
 
@@ -3602,9 +3617,9 @@
     if (next_kind == kAccessor &&
         !EqualImmutableValues(old_descriptors->GetValue(i),
                               tmp_descriptors->GetValue(i))) {
-      return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
-                                              new_kind, new_attributes,
-                                              "GenAll_Incompatible");
+      return CopyGeneralizeAllRepresentations(
+          old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
+          "GenAll_Incompatible");
     }
     if (next_location == kField && tmp_details.location() == kDescriptor) break;
 
@@ -3697,9 +3712,9 @@
     if (next_kind == kAccessor &&
         !EqualImmutableValues(old_descriptors->GetValue(i),
                               tmp_descriptors->GetValue(i))) {
-      return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
-                                              new_kind, new_attributes,
-                                              "GenAll_Incompatible");
+      return CopyGeneralizeAllRepresentations(
+          old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
+          "GenAll_Incompatible");
     }
     DCHECK(!tmp_map->is_deprecated());
     target_map = tmp_map;
@@ -3930,9 +3945,9 @@
   // could be inserted regardless of whether transitions array is full or not.
   if (maybe_transition == NULL &&
       !TransitionArray::CanHaveMoreTransitions(split_map)) {
-    return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
-                                            new_kind, new_attributes,
-                                            "GenAll_CantHaveMoreTransitions");
+    return CopyGeneralizeAllRepresentations(
+        old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
+        "GenAll_CantHaveMoreTransitions");
   }
 
   old_map->NotifyLeafMapLayoutChange();
@@ -4013,18 +4028,27 @@
     if (root_map == NULL) return MaybeHandle<Map>();
     // From here on, use the map with correct elements kind as root map.
   }
-  int root_nof = root_map->NumberOfOwnDescriptors();
+  Map* new_map = root_map->TryReplayPropertyTransitions(*old_map);
+  if (new_map == nullptr) return MaybeHandle<Map>();
+  return handle(new_map);
+}
+
+Map* Map::TryReplayPropertyTransitions(Map* old_map) {
+  DisallowHeapAllocation no_allocation;
+  DisallowDeoptimization no_deoptimization(GetIsolate());
+
+  int root_nof = NumberOfOwnDescriptors();
 
   int old_nof = old_map->NumberOfOwnDescriptors();
   DescriptorArray* old_descriptors = old_map->instance_descriptors();
 
-  Map* new_map = root_map;
+  Map* new_map = this;
   for (int i = root_nof; i < old_nof; ++i) {
     PropertyDetails old_details = old_descriptors->GetDetails(i);
     Map* transition = TransitionArray::SearchTransition(
         new_map, old_details.kind(), old_descriptors->GetKey(i),
         old_details.attributes());
-    if (transition == NULL) return MaybeHandle<Map>();
+    if (transition == NULL) return nullptr;
     new_map = transition;
     DescriptorArray* new_descriptors = new_map->instance_descriptors();
 
@@ -4032,7 +4056,7 @@
     DCHECK_EQ(old_details.kind(), new_details.kind());
     DCHECK_EQ(old_details.attributes(), new_details.attributes());
     if (!old_details.representation().fits_into(new_details.representation())) {
-      return MaybeHandle<Map>();
+      return nullptr;
     }
     switch (new_details.type()) {
       case DATA: {
@@ -4040,20 +4064,20 @@
         // Cleared field types need special treatment. They represent lost
         // knowledge, so we must first generalize the new_type to "Any".
         if (FieldTypeIsCleared(new_details.representation(), new_type)) {
-          return MaybeHandle<Map>();
+          return nullptr;
         }
         PropertyType old_property_type = old_details.type();
         if (old_property_type == DATA) {
           FieldType* old_type = old_descriptors->GetFieldType(i);
           if (FieldTypeIsCleared(old_details.representation(), old_type) ||
               !old_type->NowIs(new_type)) {
-            return MaybeHandle<Map>();
+            return nullptr;
           }
         } else {
           DCHECK(old_property_type == DATA_CONSTANT);
           Object* old_value = old_descriptors->GetValue(i);
           if (!new_type->NowContains(old_value)) {
-            return MaybeHandle<Map>();
+            return nullptr;
           }
         }
         break;
@@ -4071,14 +4095,14 @@
         Object* old_value = old_descriptors->GetValue(i);
         Object* new_value = new_descriptors->GetValue(i);
         if (old_details.location() == kField || old_value != new_value) {
-          return MaybeHandle<Map>();
+          return nullptr;
         }
         break;
       }
     }
   }
-  if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>();
-  return handle(new_map);
+  if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
+  return new_map;
 }
 
 
@@ -4736,17 +4760,30 @@
   return false;
 }
 
+Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) {
+  DisallowHeapAllocation no_allocation;
+  DisallowDeoptimization no_deoptimization(GetIsolate());
 
-Handle<Map> Map::FindTransitionedMap(Handle<Map> map,
-                                     MapHandleList* candidates) {
-  ElementsKind kind = map->elements_kind();
+  ElementsKind kind = elements_kind();
   bool packed = IsFastPackedElementsKind(kind);
 
   Map* transition = nullptr;
   if (IsTransitionableFastElementsKind(kind)) {
-    for (Map* current = map->ElementsTransitionMap();
-         current != nullptr && current->has_fast_elements();
-         current = current->ElementsTransitionMap()) {
+    // Check the state of the root map.
+    Map* root_map = FindRootMap();
+    if (!EquivalentToForTransition(root_map)) return nullptr;
+    root_map = root_map->LookupElementsTransitionMap(kind);
+    DCHECK_NOT_NULL(root_map);
+    // Starting from the next existing elements kind transition try to
+    // replay the property transitions that does not involve instance rewriting
+    // (ElementsTransitionAndStoreStub does not support that).
+    for (root_map = root_map->ElementsTransitionMap();
+         root_map != nullptr && root_map->has_fast_elements();
+         root_map = root_map->ElementsTransitionMap()) {
+      Map* current = root_map->TryReplayPropertyTransitions(this);
+      if (current == nullptr) continue;
+      if (InstancesNeedRewriting(current)) continue;
+
       if (ContainsMap(candidates, current) &&
           (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
         transition = current;
@@ -4754,11 +4791,14 @@
       }
     }
   }
-  return transition == nullptr ? Handle<Map>() : handle(transition);
+  return transition;
 }
 
 
 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
+  // Ensure we are requested to search elements kind transition "near the root".
+  DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
+            map->NumberOfOwnDescriptors());
   Map* current_map = map;
 
   ElementsKind kind = map->elements_kind();
@@ -4889,7 +4929,7 @@
     return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
   }
 
-  return Map::AsElementsKind(map, to_kind);
+  return Map::ReconfigureElementsKind(map, to_kind);
 }
 
 
@@ -5215,7 +5255,7 @@
     } else {
       TransitionElementsKind(object, to_kind);
     }
-    map = Map::AsElementsKind(map, to_kind);
+    map = Map::ReconfigureElementsKind(map, to_kind);
   }
   JSObject::MigrateToMap(object, map);
 }
@@ -9563,6 +9603,10 @@
                                     TransitionFlag flag) {
   Map* maybe_elements_transition_map = NULL;
   if (flag == INSERT_TRANSITION) {
+    // Ensure we are requested to add elements kind transition "near the root".
+    DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
+              map->NumberOfOwnDescriptors());
+
     maybe_elements_transition_map = map->ElementsTransitionMap();
     DCHECK(maybe_elements_transition_map == NULL ||
            (maybe_elements_transition_map->elements_kind() ==
@@ -9890,7 +9934,7 @@
     // There is no benefit from reconstructing transition tree for maps without
     // back pointers.
     return CopyGeneralizeAllRepresentations(
-        map, descriptor, FORCE_FIELD, kind, attributes,
+        map, map->elements_kind(), descriptor, FORCE_FIELD, kind, attributes,
         "GenAll_AttributesMismatchProtoMap");
   }
 
diff --git a/src/objects.h b/src/objects.h
index f5e35c3..4a8a557 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -5773,6 +5773,7 @@
   int NumberOfFields();
 
   // TODO(ishell): candidate with JSObject::MigrateToMap().
+  bool InstancesNeedRewriting(Map* target);
   bool InstancesNeedRewriting(Map* target, int target_number_of_fields,
                               int target_inobject, int target_unused,
                               int* old_number_of_fields);
@@ -5784,15 +5785,14 @@
   static void GeneralizeFieldType(Handle<Map> map, int modify_index,
                                   Representation new_representation,
                                   Handle<FieldType> new_field_type);
-  static Handle<Map> ReconfigureProperty(Handle<Map> map, int modify_index,
-                                         PropertyKind new_kind,
-                                         PropertyAttributes new_attributes,
-                                         Representation new_representation,
-                                         Handle<FieldType> new_field_type,
-                                         StoreMode store_mode);
-  static Handle<Map> CopyGeneralizeAllRepresentations(
-      Handle<Map> map, int modify_index, StoreMode store_mode,
-      PropertyKind kind, PropertyAttributes attributes, const char* reason);
+
+  static inline Handle<Map> ReconfigureProperty(
+      Handle<Map> map, int modify_index, PropertyKind new_kind,
+      PropertyAttributes new_attributes, Representation new_representation,
+      Handle<FieldType> new_field_type, StoreMode store_mode);
+
+  static inline Handle<Map> ReconfigureElementsKind(
+      Handle<Map> map, ElementsKind new_elements_kind);
 
   static Handle<Map> PrepareForDataProperty(Handle<Map> old_map,
                                             int descriptor_number,
@@ -6022,17 +6022,10 @@
   // Computes a hash value for this map, to be used in HashTables and such.
   int Hash();
 
-  // Returns the map that this map transitions to if its elements_kind
-  // is changed to |elements_kind|, or NULL if no such map is cached yet.
-  // |safe_to_add_transitions| is set to false if adding transitions is not
-  // allowed.
-  Map* LookupElementsTransitionMap(ElementsKind elements_kind);
-
   // Returns the transitioned map for this map with the most generic
-  // elements_kind that's found in |candidates|, or null handle if no match is
+  // elements_kind that's found in |candidates|, or |nullptr| if no match is
   // found at all.
-  static Handle<Map> FindTransitionedMap(Handle<Map> map,
-                                         MapHandleList* candidates);
+  Map* FindElementsKindTransitionedMap(MapHandleList* candidates);
 
   inline bool CanTransition();
 
@@ -6191,6 +6184,17 @@
       Handle<LayoutDescriptor> full_layout_descriptor);
 
  private:
+  // Returns the map that this (root) map transitions to if its elements_kind
+  // is changed to |elements_kind|, or |nullptr| if no such map is cached yet.
+  Map* LookupElementsTransitionMap(ElementsKind elements_kind);
+
+  // Tries to replay property transitions starting from this (root) map using
+  // the descriptor array of the |map|. The |root_map| is expected to have
+  // proper elements kind and therefore elements kinds transitions are not
+  // taken by this function. Returns |nullptr| if matching transition map is
+  // not found.
+  Map* TryReplayPropertyTransitions(Map* map);
+
   static void ConnectTransition(Handle<Map> parent, Handle<Map> child,
                                 Handle<Name> name, SimpleTransitionFlag flag);
 
@@ -6227,6 +6231,19 @@
   static Handle<Map> CopyNormalized(Handle<Map> map,
                                     PropertyNormalizationMode mode);
 
+  static Handle<Map> Reconfigure(Handle<Map> map,
+                                 ElementsKind new_elements_kind,
+                                 int modify_index, PropertyKind new_kind,
+                                 PropertyAttributes new_attributes,
+                                 Representation new_representation,
+                                 Handle<FieldType> new_field_type,
+                                 StoreMode store_mode);
+
+  static Handle<Map> CopyGeneralizeAllRepresentations(
+      Handle<Map> map, ElementsKind elements_kind, int modify_index,
+      StoreMode store_mode, PropertyKind kind, PropertyAttributes attributes,
+      const char* reason);
+
   // Fires when the layout of an object with a leaf map changes.
   // This includes adding transitions to the leaf map or changing
   // the descriptor array.
diff --git a/test/cctest/test-field-type-tracking.cc b/test/cctest/test-field-type-tracking.cc
index cee3600..f05e0951 100644
--- a/test/cctest/test-field-type-tracking.cc
+++ b/test/cctest/test-field-type-tracking.cc
@@ -86,6 +86,7 @@
 class Expectations {
   static const int MAX_PROPERTIES = 10;
   Isolate* isolate_;
+  ElementsKind elements_kind_;
   PropertyType types_[MAX_PROPERTIES];
   PropertyAttributes attributes_[MAX_PROPERTIES];
   Representation representations_[MAX_PROPERTIES];
@@ -97,8 +98,15 @@
   int number_of_properties_;
 
  public:
+  explicit Expectations(Isolate* isolate, ElementsKind elements_kind)
+      : isolate_(isolate),
+        elements_kind_(elements_kind),
+        number_of_properties_(0) {}
+
   explicit Expectations(Isolate* isolate)
-      : isolate_(isolate), number_of_properties_(0) {}
+      : Expectations(
+            isolate,
+            isolate->object_function()->initial_map()->elements_kind()) {}
 
   void Init(int index, PropertyType type, PropertyAttributes attributes,
             Representation representation, Handle<Object> value) {
@@ -143,6 +151,10 @@
     os << "\n";
   }
 
+  void SetElementsKind(ElementsKind elements_kind) {
+    elements_kind_ = elements_kind;
+  }
+
   Handle<FieldType> GetFieldType(int index) {
     CHECK(index < MAX_PROPERTIES);
     CHECK(types_[index] == DATA || types_[index] == ACCESSOR);
@@ -252,6 +264,7 @@
   }
 
   bool Check(Map* map, int expected_nof) const {
+    CHECK_EQ(elements_kind_, map->elements_kind());
     CHECK(number_of_properties_ <= MAX_PROPERTIES);
     CHECK_EQ(expected_nof, map->NumberOfOwnDescriptors());
     CHECK(!map->is_dictionary_map());
@@ -279,6 +292,13 @@
   // given |map|.
   //
 
+  Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind elements_kind) {
+    elements_kind_ = elements_kind;
+    map = Map::AsElementsKind(map, elements_kind);
+    CHECK_EQ(elements_kind_, map->elements_kind());
+    return map;
+  }
+
   Handle<Map> AddDataField(Handle<Map> map, PropertyAttributes attributes,
                            Representation representation,
                            Handle<FieldType> heap_type) {
@@ -1525,6 +1545,271 @@
 
 
 ////////////////////////////////////////////////////////////////////////////////
+// A set of tests for elements kind reconfiguration case.
+//
+
+// This test ensures that representation/field type generalization is correctly
+// propagated from one branch of transition tree (|map2) to another (|map|).
+//
+//   + - p0 - p1 - p2A - p3 - p4: |map|
+//   |
+//  ek
+//   |
+//  {} - p0 - p1 - p2B - p3 - p4: |map2|
+//
+// where "p2A" and "p2B" differ only in the representation/field type.
+//
+static void TestReconfigureElementsKind_GeneralizeRepresentation(
+    Representation from_representation, Handle<FieldType> from_type,
+    Representation to_representation, Handle<FieldType> to_type,
+    Representation expected_representation, Handle<FieldType> expected_type) {
+  Isolate* isolate = CcTest::i_isolate();
+
+  Expectations expectations(isolate, FAST_SMI_ELEMENTS);
+
+  // Create a map, add required properties to it and initialize expectations.
+  Handle<Map> initial_map = Map::Create(isolate, 0);
+  initial_map->set_elements_kind(FAST_SMI_ELEMENTS);
+
+  Handle<Map> map = initial_map;
+  map = expectations.AsElementsKind(map, FAST_ELEMENTS);
+  for (int i = 0; i < kPropCount; i++) {
+    map = expectations.AddDataField(map, NONE, from_representation, from_type);
+  }
+  CHECK(!map->is_deprecated());
+  CHECK(map->is_stable());
+  CHECK(expectations.Check(*map));
+
+  // Create another branch in transition tree (property at index |kDiffProp|
+  // has different representatio/field type), initialize expectations.
+  const int kDiffProp = kPropCount / 2;
+  Expectations expectations2(isolate, FAST_SMI_ELEMENTS);
+
+  Handle<Map> map2 = initial_map;
+  for (int i = 0; i < kPropCount; i++) {
+    if (i == kDiffProp) {
+      map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type);
+    } else {
+      map2 = expectations2.AddDataField(map2, NONE, from_representation,
+                                        from_type);
+    }
+  }
+  CHECK(!map2->is_deprecated());
+  CHECK(map2->is_stable());
+  CHECK(expectations2.Check(*map2));
+
+  Zone zone;
+  Handle<Map> field_owner(map->FindFieldOwner(kDiffProp), isolate);
+  CompilationInfo info("testing", isolate, &zone);
+  CHECK(!info.dependencies()->HasAborted());
+  info.dependencies()->AssumeFieldType(field_owner);
+
+  // Reconfigure elements kinds of |map2|, which should generalize
+  // representations in |map|.
+  Handle<Map> new_map = Map::ReconfigureElementsKind(map2, FAST_ELEMENTS);
+
+  // |map2| should be left unchanged but marked unstable.
+  CHECK(!map2->is_stable());
+  CHECK(!map2->is_deprecated());
+  CHECK_NE(*map2, *new_map);
+  CHECK(expectations2.Check(*map2));
+
+  // |map| should be deprecated and |new_map| should match new expectations.
+  expectations.SetDataField(kDiffProp, expected_representation, expected_type);
+
+  CHECK(map->is_deprecated());
+  CHECK(!info.dependencies()->HasAborted());
+  info.dependencies()->Rollback();  // Properly cleanup compilation info.
+  CHECK_NE(*map, *new_map);
+
+  CHECK(!new_map->is_deprecated());
+  CHECK(expectations.Check(*new_map));
+
+  // Update deprecated |map|, it should become |new_map|.
+  Handle<Map> updated_map = Map::Update(map);
+  CHECK_EQ(*new_map, *updated_map);
+
+  // Ensure Map::FindElementsKindTransitionedMap() is able to find the
+  // transitioned map.
+  {
+    MapHandleList map_list;
+    map_list.Add(updated_map);
+    Map* transitioned_map = map2->FindElementsKindTransitionedMap(&map_list);
+    CHECK_EQ(*updated_map, transitioned_map);
+  }
+}
+
+// This test ensures that trivial representation/field type generalization
+// (from HeapObject to HeapObject) is correctly propagated from one branch of
+// transition tree (|map2|) to another (|map|).
+//
+//   + - p0 - p1 - p2A - p3 - p4: |map|
+//   |
+//  ek
+//   |
+//  {} - p0 - p1 - p2B - p3 - p4: |map2|
+//
+// where "p2A" and "p2B" differ only in the representation/field type.
+//
+static void TestReconfigureElementsKind_GeneralizeRepresentationTrivial(
+    Representation from_representation, Handle<FieldType> from_type,
+    Representation to_representation, Handle<FieldType> to_type,
+    Representation expected_representation, Handle<FieldType> expected_type,
+    bool expected_field_type_dependency = true) {
+  Isolate* isolate = CcTest::i_isolate();
+
+  Expectations expectations(isolate, FAST_SMI_ELEMENTS);
+
+  // Create a map, add required properties to it and initialize expectations.
+  Handle<Map> initial_map = Map::Create(isolate, 0);
+  initial_map->set_elements_kind(FAST_SMI_ELEMENTS);
+
+  Handle<Map> map = initial_map;
+  map = expectations.AsElementsKind(map, FAST_ELEMENTS);
+  for (int i = 0; i < kPropCount; i++) {
+    map = expectations.AddDataField(map, NONE, from_representation, from_type);
+  }
+  CHECK(!map->is_deprecated());
+  CHECK(map->is_stable());
+  CHECK(expectations.Check(*map));
+
+  // Create another branch in transition tree (property at index |kDiffProp|
+  // has different attributes), initialize expectations.
+  const int kDiffProp = kPropCount / 2;
+  Expectations expectations2(isolate, FAST_SMI_ELEMENTS);
+
+  Handle<Map> map2 = initial_map;
+  for (int i = 0; i < kPropCount; i++) {
+    if (i == kDiffProp) {
+      map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type);
+    } else {
+      map2 = expectations2.AddDataField(map2, NONE, from_representation,
+                                        from_type);
+    }
+  }
+  CHECK(!map2->is_deprecated());
+  CHECK(map2->is_stable());
+  CHECK(expectations2.Check(*map2));
+
+  Zone zone;
+  Handle<Map> field_owner(map->FindFieldOwner(kDiffProp), isolate);
+  CompilationInfo info("testing", isolate, &zone);
+  CHECK(!info.dependencies()->HasAborted());
+  info.dependencies()->AssumeFieldType(field_owner);
+
+  // Reconfigure elements kinds of |map2|, which should generalize
+  // representations in |map|.
+  Handle<Map> new_map = Map::ReconfigureElementsKind(map2, FAST_ELEMENTS);
+
+  // |map2| should be left unchanged but marked unstable.
+  CHECK(!map2->is_stable());
+  CHECK(!map2->is_deprecated());
+  CHECK_NE(*map2, *new_map);
+  CHECK(expectations2.Check(*map2));
+
+  // In trivial case |map| should be returned as a result of the elements
+  // kind reconfiguration, respective field types should be generalized and
+  // respective code dependencies should be invalidated. |map| should be NOT
+  // deprecated and it should match new expectations.
+  expectations.SetDataField(kDiffProp, expected_representation, expected_type);
+  CHECK(!map->is_deprecated());
+  CHECK_EQ(*map, *new_map);
+  CHECK_EQ(expected_field_type_dependency, info.dependencies()->HasAborted());
+  info.dependencies()->Rollback();  // Properly cleanup compilation info.
+
+  CHECK(!new_map->is_deprecated());
+  CHECK(expectations.Check(*new_map));
+
+  Handle<Map> updated_map = Map::Update(map);
+  CHECK_EQ(*new_map, *updated_map);
+
+  // Ensure Map::FindElementsKindTransitionedMap() is able to find the
+  // transitioned map.
+  {
+    MapHandleList map_list;
+    map_list.Add(updated_map);
+    Map* transitioned_map = map2->FindElementsKindTransitionedMap(&map_list);
+    CHECK_EQ(*updated_map, transitioned_map);
+  }
+}
+
+TEST(ReconfigureElementsKind_GeneralizeRepresentationSmiToDouble) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Handle<FieldType> any_type = FieldType::Any(isolate);
+
+  TestReconfigureElementsKind_GeneralizeRepresentation(
+      Representation::Smi(), any_type, Representation::Double(), any_type,
+      Representation::Double(), any_type);
+}
+
+TEST(ReconfigureElementsKind_GeneralizeRepresentationSmiToTagged) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Handle<FieldType> any_type = FieldType::Any(isolate);
+  Handle<FieldType> value_type =
+      FieldType::Class(Map::Create(isolate, 0), isolate);
+
+  TestReconfigureElementsKind_GeneralizeRepresentation(
+      Representation::Smi(), any_type, Representation::HeapObject(), value_type,
+      Representation::Tagged(), any_type);
+}
+
+TEST(ReconfigureElementsKind_GeneralizeRepresentationDoubleToTagged) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Handle<FieldType> any_type = FieldType::Any(isolate);
+  Handle<FieldType> value_type =
+      FieldType::Class(Map::Create(isolate, 0), isolate);
+
+  TestReconfigureElementsKind_GeneralizeRepresentation(
+      Representation::Double(), any_type, Representation::HeapObject(),
+      value_type, Representation::Tagged(), any_type);
+}
+
+TEST(ReconfigureElementsKind_GeneralizeRepresentationHeapObjToHeapObj) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Handle<FieldType> any_type = FieldType::Any(isolate);
+
+  Handle<FieldType> current_type =
+      FieldType::Class(Map::Create(isolate, 0), isolate);
+
+  Handle<FieldType> new_type =
+      FieldType::Class(Map::Create(isolate, 0), isolate);
+
+  Handle<FieldType> expected_type = any_type;
+
+  TestReconfigureElementsKind_GeneralizeRepresentationTrivial(
+      Representation::HeapObject(), current_type, Representation::HeapObject(),
+      new_type, Representation::HeapObject(), expected_type);
+  current_type = expected_type;
+
+  new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
+
+  TestReconfigureElementsKind_GeneralizeRepresentationTrivial(
+      Representation::HeapObject(), any_type, Representation::HeapObject(),
+      new_type, Representation::HeapObject(), any_type, false);
+}
+
+TEST(ReconfigureElementsKind_GeneralizeRepresentationHeapObjectToTagged) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Handle<FieldType> any_type = FieldType::Any(isolate);
+  Handle<FieldType> value_type =
+      FieldType::Class(Map::Create(isolate, 0), isolate);
+
+  TestReconfigureElementsKind_GeneralizeRepresentation(
+      Representation::HeapObject(), value_type, Representation::Smi(), any_type,
+      Representation::Tagged(), any_type);
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // A set of tests checking split map deprecation.
 //
 
@@ -1640,15 +1925,16 @@
   CHECK(map->is_stable());
   CHECK(expectations.Check(*map));
 
+  Expectations expectations2 = expectations;
+
   // Apply some special transition to |map|.
   CHECK(map->owns_descriptors());
-  Handle<Map> map2 = config.Transition(map);
+  Handle<Map> map2 = config.Transition(map, expectations2);
 
   // |map| should still match expectations.
   CHECK(!map->is_deprecated());
   CHECK(expectations.Check(*map));
 
-  Expectations expectations2 = expectations;
   if (config.generalizes_representations()) {
     for (int i = 0; i < kPropCount; i++) {
       expectations2.GeneralizeRepresentation(i);
@@ -1720,13 +2006,15 @@
       FieldType::Class(Map::Create(isolate, 0), isolate);
 
   struct TestConfig {
-    Handle<Map> Transition(Handle<Map> map) {
-      return Map::CopyAsElementsKind(map, DICTIONARY_ELEMENTS,
-                                     INSERT_TRANSITION);
+    Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
+      Handle<Symbol> frozen_symbol(map->GetHeap()->frozen_symbol());
+      expectations.SetElementsKind(DICTIONARY_ELEMENTS);
+      return Map::CopyForPreventExtensions(map, NONE, frozen_symbol,
+                                           "CopyForPreventExtensions");
     }
     // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
     bool generalizes_representations() const { return false; }
-    bool is_non_equevalent_transition() const { return false; }
+    bool is_non_equevalent_transition() const { return true; }
   };
   TestConfig config;
   TestGeneralizeRepresentationWithSpecialTransition(
@@ -1744,7 +2032,7 @@
       FieldType::Class(Map::Create(isolate, 0), isolate);
 
   struct TestConfig {
-    Handle<Map> Transition(Handle<Map> map) {
+    Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
       Isolate* isolate = CcTest::i_isolate();
       Handle<FieldType> any_type = FieldType::Any(isolate);
 
@@ -1756,12 +2044,14 @@
           .ToHandleChecked();
       CHECK(!map->owns_descriptors());
 
-      return Map::CopyAsElementsKind(map, DICTIONARY_ELEMENTS,
-                                     INSERT_TRANSITION);
+      Handle<Symbol> frozen_symbol(map->GetHeap()->frozen_symbol());
+      expectations.SetElementsKind(DICTIONARY_ELEMENTS);
+      return Map::CopyForPreventExtensions(map, NONE, frozen_symbol,
+                                           "CopyForPreventExtensions");
     }
     // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
     bool generalizes_representations() const { return false; }
-    bool is_non_equevalent_transition() const { return false; }
+    bool is_non_equevalent_transition() const { return true; }
   };
   TestConfig config;
   TestGeneralizeRepresentationWithSpecialTransition(
@@ -1779,7 +2069,7 @@
       FieldType::Class(Map::Create(isolate, 0), isolate);
 
   struct TestConfig {
-    Handle<Map> Transition(Handle<Map> map) {
+    Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
       return Map::CopyForObserved(map);
     }
     // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
@@ -1802,7 +2092,7 @@
       FieldType::Class(Map::Create(isolate, 0), isolate);
 
   struct TestConfig {
-    Handle<Map> Transition(Handle<Map> map) {
+    Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
       Isolate* isolate = CcTest::i_isolate();
       Handle<FieldType> any_type = FieldType::Any(isolate);
 
@@ -1845,7 +2135,7 @@
       prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0));
     }
 
-    Handle<Map> Transition(Handle<Map> map) {
+    Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
       return Map::TransitionToPrototype(map, prototype_, REGULAR_PROTOTYPE);
     }
     // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
@@ -1879,7 +2169,7 @@
       prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0));
     }
 
-    Handle<Map> Transition(Handle<Map> map) {
+    Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
       Isolate* isolate = CcTest::i_isolate();
       Handle<FieldType> any_type = FieldType::Any(isolate);
 
diff --git a/test/mjsunit/regress/regress-crbug-617524.js b/test/mjsunit/regress/regress-crbug-617524.js
new file mode 100644
index 0000000..b32eeef
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-617524.js
@@ -0,0 +1,18 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-gc --always-opt
+
+function f(a,b,c) {
+  a.a = b;
+  a[1] = c;
+  return a;
+}
+
+f(new Array(5),.5,0);
+var o1 = f(new Array(5),0,.5);
+gc();
+var o2 = f(new Array(5),0,0);
+var o3 = f(new Array(5),0);
+assertEquals(0, o3.a);
diff --git a/test/mjsunit/regress/regress-v8-5009.js b/test/mjsunit/regress/regress-v8-5009.js
new file mode 100644
index 0000000..f499548
--- /dev/null
+++ b/test/mjsunit/regress/regress-v8-5009.js
@@ -0,0 +1,61 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function fn1() {
+}
+
+function fn2() {
+}
+
+function fn3() {
+}
+
+function create(id) {
+  // Just some `FunctionTemplate` to hang on
+  var o = new version();
+
+  o.id = id;
+  o[0] = null;
+
+  return o;
+}
+
+function setM1(o) {
+  o.m1 = fn1;
+}
+
+function setM2(o) {
+  o.m2 = fn2;
+}
+
+function setAltM2(o) {
+  // Failing StoreIC happens here
+  o.m2 = fn3;
+}
+
+function setAltM1(o) {
+  o.m1 = null;
+}
+
+function test(o) {
+  o.m2();
+  o.m1();
+}
+
+var p0 = create(0);
+var p1 = create(1);
+var p2 = create(2);
+
+setM1(p0);
+setM1(p1);
+setM1(p2);
+
+setM2(p0);
+setAltM2(p0);
+setAltM1(p0);
+
+setAltM2(p1);
+
+setAltM2(p2);
+test(p2);