Version 4.2.77.8 (cherry-pick)

Merged 0902b5f4dfdea599bf3d96fb9fb258904aff84ec

Incorrect handling of HTransitionElementsKind in hydrogen check elimination phase fixed.

BUG=chromium:460917
LOG=N
R=jkummerow@chromium.org

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

Cr-Commit-Position: refs/branch-heads/4.2@{#9}
Cr-Branched-From: 3dfd929ea07487f2295553df397720d8d75d227c-refs/heads/4.2.77@{#2}
Cr-Branched-From: e0110920d6f98f0ba2ac0d680f635ae3f094a04e-refs/heads/master@{#26757}
diff --git a/include/v8-version.h b/include/v8-version.h
index bfb02f0..1aa052e 100644
--- a/include/v8-version.h
+++ b/include/v8-version.h
@@ -11,7 +11,7 @@
 #define V8_MAJOR_VERSION 4
 #define V8_MINOR_VERSION 2
 #define V8_BUILD_NUMBER 77
-#define V8_PATCH_LEVEL 7
+#define V8_PATCH_LEVEL 8
 
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/hydrogen-check-elimination.cc b/src/hydrogen-check-elimination.cc
index 3542fa6..cdfedb4 100644
--- a/src/hydrogen-check-elimination.cc
+++ b/src/hydrogen-check-elimination.cc
@@ -628,14 +628,23 @@
     HValue* object = instr->object()->ActualValue();
     HCheckTableEntry* entry = Find(object);
     // Can only learn more about an object that already has a known set of maps.
-    if (entry == NULL) return;
+    if (entry == NULL) {
+      Kill(object);
+      return;
+    }
     EnsureChecked(entry, object, instr);
     if (entry->maps_->Contains(instr->original_map())) {
       // If the object has the original map, it will be transitioned.
       UniqueSet<Map>* maps = entry->maps_->Copy(zone());
       maps->Remove(instr->original_map());
       maps->Add(instr->transitioned_map(), zone());
-      entry->maps_ = maps;
+      HCheckTableEntry::State state =
+          (entry->state_ == HCheckTableEntry::CHECKED_STABLE &&
+           instr->map_is_stable())
+              ? HCheckTableEntry::CHECKED_STABLE
+              : HCheckTableEntry::CHECKED;
+      Kill(object);
+      Insert(object, NULL, maps, state);
     } else {
       // Object does not have the given map, thus the transition is redundant.
       instr->DeleteAndReplaceWith(object);
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index e85600a..8fd2aed 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -7270,8 +7270,13 @@
   HValue* context() const { return OperandAt(1); }
   Unique<Map> original_map() const { return original_map_; }
   Unique<Map> transitioned_map() const { return transitioned_map_; }
-  ElementsKind from_kind() const { return from_kind_; }
-  ElementsKind to_kind() const { return to_kind_; }
+  ElementsKind from_kind() const {
+    return FromElementsKindField::decode(bit_field_);
+  }
+  ElementsKind to_kind() const {
+    return ToElementsKindField::decode(bit_field_);
+  }
+  bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
 
   std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
@@ -7287,29 +7292,33 @@
   int RedefinedOperandIndex() OVERRIDE { return 0; }
 
  private:
-  HTransitionElementsKind(HValue* context,
-                          HValue* object,
+  HTransitionElementsKind(HValue* context, HValue* object,
                           Handle<Map> original_map,
                           Handle<Map> transitioned_map)
       : original_map_(Unique<Map>(original_map)),
         transitioned_map_(Unique<Map>(transitioned_map)),
-        from_kind_(original_map->elements_kind()),
-        to_kind_(transitioned_map->elements_kind()) {
+        bit_field_(
+            FromElementsKindField::encode(original_map->elements_kind()) |
+            ToElementsKindField::encode(transitioned_map->elements_kind()) |
+            MapIsStableField::encode(transitioned_map->is_stable())) {
     SetOperandAt(0, object);
     SetOperandAt(1, context);
     SetFlag(kUseGVN);
     SetChangesFlag(kElementsKind);
-    if (!IsSimpleMapChangeTransition(from_kind_, to_kind_)) {
+    if (!IsSimpleMapChangeTransition(from_kind(), to_kind())) {
       SetChangesFlag(kElementsPointer);
       SetChangesFlag(kNewSpacePromotion);
     }
     set_representation(Representation::Tagged());
   }
 
+  class FromElementsKindField : public BitField<ElementsKind, 0, 5> {};
+  class ToElementsKindField : public BitField<ElementsKind, 5, 5> {};
+  class MapIsStableField : public BitField<bool, 10, 1> {};
+
   Unique<Map> original_map_;
   Unique<Map> transitioned_map_;
-  ElementsKind from_kind_;
-  ElementsKind to_kind_;
+  uint32_t bit_field_;
 };
 
 
diff --git a/test/mjsunit/regress/regress-460917.js b/test/mjsunit/regress/regress-460917.js
new file mode 100644
index 0000000..68e1b63
--- /dev/null
+++ b/test/mjsunit/regress/regress-460917.js
@@ -0,0 +1,35 @@
+// Copyright 2015 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: --allow-natives-syntax
+
+function boom(a1, a2) {
+  // Do something with a2 that needs a map check (for DOUBLE_ELEMENTS).
+  var s = a2[0];
+  // Emit a load that transitions a1 to FAST_ELEMENTS.
+  var t = a1[0];
+  // Emit a store to a2 that assumes DOUBLE_ELEMENTS.
+  // The map check is considered redundant and will be eliminated.
+  a2[0] = 0.3;
+}
+
+// Prepare type feedback for the "t = a1[0]" load: fast elements.
+var fast_elem = new Array(1);
+fast_elem[0] = "tagged";
+boom(fast_elem, [1]);
+
+// Prepare type feedback for the "a2[0] = 0.3" store: double elements.
+var double_elem = new Array(1);
+double_elem[0] = 0.1;
+boom(double_elem, double_elem);
+
+// Reset |double_elem| and go have a party.
+double_elem = new Array(10);
+double_elem[0] = 0.1;
+
+%OptimizeFunctionOnNextCall(boom);
+boom(double_elem, double_elem);
+
+assertEquals(0.3, double_elem[0]);
+assertEquals(undefined, double_elem[1]);