Version 3.31.39 (based on 7ec1c3616e6d67efa7bef3124596f321d2800b76)

Performance and stability improvements on all platforms.

Cr-Commit-Position: refs/heads/candidates@{#25314}
diff --git a/ChangeLog b/ChangeLog
index 37c0069..5b45ea6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2014-12-03: Version 3.31.39
+
+        Performance and stability improvements on all platforms.
+
+
 2014-12-03: Version 3.31.38
 
         Stage ES6 classes and object literal extensions (issue 3330).
diff --git a/src/compiler/machine-operator-reducer.cc b/src/compiler/machine-operator-reducer.cc
index 00c998d..f8555da 100644
--- a/src/compiler/machine-operator-reducer.cc
+++ b/src/compiler/machine-operator-reducer.cc
@@ -779,13 +779,37 @@
     Int32BinopMatcher mleft(m.left().node());
     if (mleft.right().HasValue() &&
         (mleft.right().Value() & m.right().Value()) == mleft.right().Value()) {
-      // (x + K) & K => (x & K) + K
+      // (x + (K << L)) & (-1 << L) => (x & (-1 << L)) + (K << L)
       return Replace(graph()->NewNode(
           machine()->Int32Add(),
           graph()->NewNode(machine()->Word32And(), mleft.left().node(),
                            m.right().node()),
           mleft.right().node()));
     }
+    if (mleft.left().IsWord32Shl()) {
+      Int32BinopMatcher mleftleft(mleft.left().node());
+      if (mleftleft.right().Is(
+              base::bits::CountTrailingZeros32(m.right().Value()))) {
+        // (y << L + x) & (-1 << L) => (x & (-1 << L)) + y << L
+        return Replace(graph()->NewNode(
+            machine()->Int32Add(),
+            graph()->NewNode(machine()->Word32And(), mleft.right().node(),
+                             m.right().node()),
+            mleftleft.node()));
+      }
+    }
+    if (mleft.right().IsWord32Shl()) {
+      Int32BinopMatcher mleftright(mleft.right().node());
+      if (mleftright.right().Is(
+              base::bits::CountTrailingZeros32(m.right().Value()))) {
+        // (x + y << L) & (-1 << L) => (x & (-1 << L)) + y << L
+        return Replace(graph()->NewNode(
+            machine()->Int32Add(),
+            graph()->NewNode(machine()->Word32And(), mleft.left().node(),
+                             m.right().node()),
+            mleftright.node()));
+      }
+    }
   }
   return NoChange();
 }
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index c16d56c..4d9b2b2 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -488,7 +488,7 @@
 
 DEFINE_BOOL(serialize_toplevel, true, "enable caching of toplevel scripts")
 DEFINE_BOOL(serialize_inner, false, "enable caching of inner functions")
-DEFINE_BOOL(trace_code_serializer, false, "print code serializer trace")
+DEFINE_BOOL(trace_serializer, false, "print code serializer trace")
 
 // compiler.cc
 DEFINE_INT(min_preparse_length, 1024,
diff --git a/src/heap/heap.cc b/src/heap/heap.cc
index fa32764..8c489bd 100644
--- a/src/heap/heap.cc
+++ b/src/heap/heap.cc
@@ -120,6 +120,7 @@
       min_in_mutator_(kMaxInt),
       marking_time_(0.0),
       sweeping_time_(0.0),
+      last_idle_notification_time_(0.0),
       mark_compact_collector_(this),
       store_buffer_(this),
       marking_(this),
@@ -4530,6 +4531,7 @@
   }
 
   double current_time = MonotonicallyIncreasingTimeInMs();
+  last_idle_notification_time_ = current_time;
   double deadline_difference = deadline_in_ms - current_time;
 
   if (deadline_difference >= 0) {
@@ -4564,6 +4566,13 @@
 }
 
 
+bool Heap::RecentIdleNotifcationHappened() {
+  return (last_idle_notification_time_ +
+          GCIdleTimeHandler::kMaxFrameRenderingIdleTime) >
+         MonotonicallyIncreasingTimeInMs();
+}
+
+
 #ifdef DEBUG
 
 void Heap::Print() {
diff --git a/src/heap/heap.h b/src/heap/heap.h
index 09a0678..9fa9497 100644
--- a/src/heap/heap.h
+++ b/src/heap/heap.h
@@ -1295,6 +1295,8 @@
 
   int gc_count() const { return gc_count_; }
 
+  bool RecentIdleNotifcationHappened();
+
   // Completely clear the Instanceof cache (to stop it keeping objects alive
   // around a GC).
   inline void CompletelyClearInstanceofCache();
@@ -2057,6 +2059,9 @@
   // Cumulative GC time spent in sweeping
   double sweeping_time_;
 
+  // Last time an idle notification happened
+  double last_idle_notification_time_;
+
   MarkCompactCollector mark_compact_collector_;
 
   StoreBuffer store_buffer_;
diff --git a/src/heap/incremental-marking.cc b/src/heap/incremental-marking.cc
index 7ab3bf8..08f11c6 100644
--- a/src/heap/incremental-marking.cc
+++ b/src/heap/incremental-marking.cc
@@ -880,6 +880,12 @@
     return 0;
   }
 
+  // If an idle notification happened recently, we delay marking steps.
+  if (marking == DO_NOT_FORCE_MARKING &&
+      heap_->RecentIdleNotifcationHappened()) {
+    return 0;
+  }
+
   if (state_ == MARKING && no_marking_scope_depth_ > 0) return 0;
 
   intptr_t bytes_processed = 0;
diff --git a/src/serialize.cc b/src/serialize.cc
index fab9775..e6aae7f 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -794,10 +794,24 @@
 }
 
 
-Object* Deserializer::ProcessBackRefInSerializedCode(Object* obj) {
-  if (obj->IsInternalizedString()) {
-    return String::cast(obj)->GetForwardedInternalizedString();
+HeapObject* Deserializer::GetBackReferencedObject(int space) {
+  HeapObject* obj;
+  if (space == LO_SPACE) {
+    uint32_t index = source_->GetInt();
+    obj = deserialized_large_objects_[index];
+  } else {
+    BackReference back_reference(source_->GetInt());
+    DCHECK(space < kNumberOfPreallocatedSpaces);
+    uint32_t chunk_index = back_reference.chunk_index();
+    DCHECK_LE(chunk_index, current_chunk_[space]);
+    uint32_t chunk_offset = back_reference.chunk_offset();
+    obj = HeapObject::FromAddress(reservations_[space][chunk_index].start +
+                                  chunk_offset);
   }
+  if (deserializing_user_code() && obj->IsInternalizedString()) {
+    obj = String::cast(obj)->GetForwardedInternalizedString();
+  }
+  hot_objects_.Add(obj);
   return obj;
 }
 
@@ -904,7 +918,7 @@
                                source_space != CODE_SPACE &&
                                source_space != OLD_DATA_SPACE);
   while (current < limit) {
-    int data = source_->Get();
+    byte data = source_->Get();
     switch (data) {
 #define CASE_STATEMENT(where, how, within, space_number) \
   case where + how + within + space_number:              \
@@ -945,9 +959,6 @@
       } else if (where == kBackref) {                                          \
         emit_write_barrier = (space_number == NEW_SPACE);                      \
         new_object = GetBackReferencedObject(data & kSpaceMask);               \
-        if (deserializing_user_code()) {                                       \
-          new_object = ProcessBackRefInSerializedCode(new_object);             \
-        }                                                                      \
       } else if (where == kBuiltin) {                                          \
         DCHECK(deserializing_user_code());                                     \
         int builtin_id = source_->GetInt();                                    \
@@ -968,9 +979,6 @@
             reinterpret_cast<Address>(current) + skip);                        \
         emit_write_barrier = (space_number == NEW_SPACE);                      \
         new_object = GetBackReferencedObject(data & kSpaceMask);               \
-        if (deserializing_user_code()) {                                       \
-          new_object = ProcessBackRefInSerializedCode(new_object);             \
-        }                                                                      \
       }                                                                        \
       if (within == kInnerPointer) {                                           \
         if (space_number != CODE_SPACE || new_object->IsCode()) {              \
@@ -1111,7 +1119,7 @@
         break;
       }
 
-      case kRepeat: {
+      case kVariableRepeat: {
         int repeats = source_->GetInt();
         Object* object = current[-1];
         DCHECK(!isolate->heap()->InNewSpace(object));
@@ -1122,11 +1130,13 @@
 
       STATIC_ASSERT(kRootArrayNumberOfConstantEncodings ==
                     Heap::kOldSpaceRoots);
-      STATIC_ASSERT(kMaxRepeats == 13);
-      case kConstantRepeat:
-      FOUR_CASES(kConstantRepeat + 1)
-      FOUR_CASES(kConstantRepeat + 5)
-      FOUR_CASES(kConstantRepeat + 9) {
+      STATIC_ASSERT(kMaxFixedRepeats == 15);
+      FOUR_CASES(kFixedRepeat)
+      FOUR_CASES(kFixedRepeat + 4)
+      FOUR_CASES(kFixedRepeat + 8)
+      case kFixedRepeat + 12:
+      case kFixedRepeat + 13:
+      case kFixedRepeat + 14: {
         int repeats = RepeatsForCode(data);
         Object* object = current[-1];
         DCHECK(!isolate->heap()->InNewSpace(object));
@@ -1261,6 +1271,27 @@
         break;
       }
 
+      FOUR_CASES(kHotObjectWithSkip)
+      FOUR_CASES(kHotObjectWithSkip + 4) {
+        int skip = source_->GetInt();
+        current = reinterpret_cast<Object**>(
+            reinterpret_cast<Address>(current) + skip);
+        // Fall through.
+      }
+      FOUR_CASES(kHotObject)
+      FOUR_CASES(kHotObject + 4) {
+        int index = data & kHotObjectIndexMask;
+        *current = hot_objects_.Get(index);
+        if (write_barrier_needed && isolate->heap()->InNewSpace(*current)) {
+          Address current_address = reinterpret_cast<Address>(current);
+          isolate->heap()->RecordWrite(
+              current_object_address,
+              static_cast<int>(current_address - current_object_address));
+        }
+        current++;
+        break;
+      }
+
       case kSynchronize: {
         // If we get here then that indicates that you have a mismatch between
         // the number of GC roots when serializing and deserializing.
@@ -1324,7 +1355,7 @@
       sink_->Put(kSkip, "Skip");
       sink_->PutInt(kPointerSize, "SkipOneWord");
     } else if ((*current)->IsSmi()) {
-      sink_->Put(kRawData + 1, "Smi");
+      sink_->Put(kOnePointerRawData, "Smi");
       for (int i = 0; i < kPointerSize; i++) {
         sink_->Put(reinterpret_cast<byte*>(current)[i], "Byte");
       }
@@ -1352,7 +1383,7 @@
 void Serializer::VisitPointers(Object** start, Object** end) {
   for (Object** current = start; current < end; current++) {
     if ((*current)->IsSmi()) {
-      sink_->Put(kRawData + 1, "Smi");
+      sink_->Put(kOnePointerRawData, "Smi");
       for (int i = 0; i < kPointerSize; i++) {
         sink_->Put(reinterpret_cast<byte*>(current)[i], "Byte");
       }
@@ -1426,24 +1457,61 @@
 }
 
 
-// Encode the location of an already deserialized object in order to write its
-// location into a later object.  We can encode the location as an offset from
-// the start of the deserialized objects or as an offset backwards from the
-// current allocation pointer.
-void Serializer::SerializeBackReference(BackReference back_reference,
-                                        HowToCode how_to_code,
-                                        WhereToPoint where_to_point, int skip) {
-  AllocationSpace space = back_reference.space();
-  if (skip == 0) {
-    sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRefSer");
-  } else {
-    sink_->Put(kBackrefWithSkip + how_to_code + where_to_point + space,
-               "BackRefSerWithSkip");
-    sink_->PutInt(skip, "BackRefSkipDistance");
+bool Serializer::SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
+                                      WhereToPoint where_to_point, int skip) {
+  if (how_to_code == kPlain && where_to_point == kStartOfObject) {
+    // Encode a reference to a hot object by its index in the working set.
+    int index = hot_objects_.Find(obj);
+    if (index != HotObjectsList::kNotFound) {
+      DCHECK(index >= 0 && index <= kMaxHotObjectIndex);
+      if (FLAG_trace_serializer) {
+        PrintF(" Encoding hot object %d:", index);
+        obj->ShortPrint();
+        PrintF("\n");
+      }
+      if (skip != 0) {
+        sink_->Put(kHotObjectWithSkip + index, "HotObjectWithSkip");
+        sink_->PutInt(skip, "HotObjectSkipDistance");
+      } else {
+        sink_->Put(kHotObject + index, "HotObject");
+      }
+      return true;
+    }
   }
+  BackReference back_reference = back_reference_map_.Lookup(obj);
+  if (back_reference.is_valid()) {
+    // Encode the location of an already deserialized object in order to write
+    // its location into a later object.  We can encode the location as an
+    // offset fromthe start of the deserialized objects or as an offset
+    // backwards from thecurrent allocation pointer.
+    if (back_reference.is_source()) {
+      FlushSkip(skip);
+      if (FLAG_trace_serializer) PrintF(" Encoding source object\n");
+      DCHECK(how_to_code == kPlain && where_to_point == kStartOfObject);
+      sink_->Put(kAttachedReference + how_to_code + where_to_point, "Source");
+      sink_->PutInt(kSourceObjectReference, "kSourceObjectIndex");
+    } else {
+      if (FLAG_trace_serializer) {
+        PrintF(" Encoding back reference to: ");
+        obj->ShortPrint();
+        PrintF("\n");
+      }
 
-  sink_->PutInt(back_reference.reference(),
-                (space == LO_SPACE) ? "large object index" : "allocation");
+      AllocationSpace space = back_reference.space();
+      if (skip == 0) {
+        sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRef");
+      } else {
+        sink_->Put(kBackrefWithSkip + how_to_code + where_to_point + space,
+                   "BackRefWithSkip");
+        sink_->PutInt(skip, "BackRefSkipDistance");
+      }
+      sink_->PutInt(back_reference.reference(), "BackRefValue");
+
+      hot_objects_.Add(obj);
+    }
+    return true;
+  }
+  return false;
 }
 
 
@@ -1460,16 +1528,9 @@
     return;
   }
 
-  BackReference back_reference = back_reference_map_.Lookup(obj);
-  if (back_reference.is_valid()) {
-    SerializeBackReference(back_reference, how_to_code, where_to_point, skip);
-    return;
-  }
+  if (SerializeKnownObject(obj, how_to_code, where_to_point, skip)) return;
 
-  if (skip != 0) {
-    sink_->Put(kSkip, "FlushPendingSkip");
-    sink_->PutInt(skip, "SkipDistance");
-  }
+  FlushSkip(skip);
 
   // Object has not yet been serialized.  Serialize it here.
   ObjectSerializer object_serializer(this, obj, sink_, how_to_code,
@@ -1479,7 +1540,7 @@
 
 
 void StartupSerializer::SerializeWeakReferences() {
-  // This phase comes right after the partial serialization (of the snapshot).
+  // This phase comes right after the serialization (of the snapshot).
   // After we have done the partial serialization the partial snapshot cache
   // will contain some references needed to decode the partial snapshot.  We
   // add one entry with 'undefined' which is the sentinel that the deserializer
@@ -1496,6 +1557,12 @@
                          SerializerDeserializer::HowToCode how_to_code,
                          SerializerDeserializer::WhereToPoint where_to_point,
                          int skip) {
+  if (FLAG_trace_serializer) {
+    PrintF(" Encoding root %d:", root_index);
+    object->ShortPrint();
+    PrintF("\n");
+  }
+
   if (how_to_code == kPlain &&
       where_to_point == kStartOfObject &&
       root_index < kRootArrayNumberOfConstantEncodings &&
@@ -1509,10 +1576,7 @@
       sink_->PutInt(skip, "SkipInPutRoot");
     }
   } else {
-    if (skip != 0) {
-      sink_->Put(kSkip, "SkipFromPutRoot");
-      sink_->PutInt(skip, "SkipFromPutRootDistance");
-    }
+    FlushSkip(skip);
     sink_->Put(kRootArray + how_to_code + where_to_point, "RootSerialization");
     sink_->PutInt(root_index, "root_index");
   }
@@ -1534,10 +1598,7 @@
   }
 
   if (ShouldBeInThePartialSnapshotCache(obj)) {
-    if (skip != 0) {
-      sink_->Put(kSkip, "SkipFromSerializeObject");
-      sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
-    }
+    FlushSkip(skip);
 
     int cache_index = PartialSnapshotCacheIndex(obj);
     sink_->Put(kPartialSnapshotCache + how_to_code + where_to_point,
@@ -1554,16 +1615,10 @@
   // either in the root table or in the partial snapshot cache.
   DCHECK(!obj->IsInternalizedString());
 
-  BackReference back_reference = back_reference_map_.Lookup(obj);
-  if (back_reference.is_valid()) {
-    SerializeBackReference(back_reference, how_to_code, where_to_point, skip);
-    return;
-  }
+  if (SerializeKnownObject(obj, how_to_code, where_to_point, skip)) return;
 
-  if (skip != 0) {
-    sink_->Put(kSkip, "SkipFromSerializeObject");
-    sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
-  }
+  FlushSkip(skip);
+
   // Object has not yet been serialized.  Serialize it here.
   ObjectSerializer serializer(this, obj, sink_, how_to_code, where_to_point);
   serializer.Serialize();
@@ -1584,8 +1639,8 @@
   BackReference back_reference;
   if (space == LO_SPACE) {
     sink_->Put(kNewObject + reference_representation_ + space,
-               "new large object");
-    sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
+               "NewLargeObject");
+    sink_->PutInt(size >> kObjectAlignmentBits, "ObjectSizeInWords");
     if (object_->IsCode()) {
       sink_->Put(EXECUTABLE, "executable large object");
     } else {
@@ -1596,14 +1651,14 @@
     if (object_->NeedsToEnsureDoubleAlignment()) {
       // Add wriggle room for double alignment padding.
       back_reference = serializer_->Allocate(space, size + kPointerSize);
-      sink_->PutInt(kDoubleAlignmentSentinel, "double align");
+      sink_->PutInt(kDoubleAlignmentSentinel, "DoubleAlignSentinel");
     } else {
       back_reference = serializer_->Allocate(space, size);
     }
-    sink_->Put(kNewObject + reference_representation_ + space, "new object");
+    sink_->Put(kNewObject + reference_representation_ + space, "NewObject");
     int encoded_size = size >> kObjectAlignmentBits;
     DCHECK_NE(kDoubleAlignmentSentinel, encoded_size);
-    sink_->PutInt(encoded_size, "Size in words");
+    sink_->PutInt(encoded_size, "ObjectSizeInWords");
   }
 
   // Mark this object as already serialized.
@@ -1677,6 +1732,12 @@
 
 
 void Serializer::ObjectSerializer::Serialize() {
+  if (FLAG_trace_serializer) {
+    PrintF(" Encoding heap object: ");
+    object_->ShortPrint();
+    PrintF("\n");
+  }
+
   if (object_->IsExternalString()) {
     Heap* heap = serializer_->isolate()->heap();
     if (object_->map() != heap->native_source_string_map()) {
@@ -1727,8 +1788,8 @@
         }
         current += repeat_count;
         bytes_processed_so_far_ += repeat_count * kPointerSize;
-        if (repeat_count > kMaxRepeats) {
-          sink_->Put(kRepeat, "SerializeRepeats");
+        if (repeat_count > kMaxFixedRepeats) {
+          sink_->Put(kVariableRepeat, "SerializeRepeats");
           sink_->PutInt(repeat_count, "SerializeRepeats");
         } else {
           sink_->Put(CodeForRepeats(repeat_count), "SerializeRepeats");
@@ -1957,8 +2018,8 @@
   if (new_chunk_size > max_chunk_size(space)) {
     // The new chunk size would not fit onto a single page. Complete the
     // current chunk and start a new one.
-    sink_->Put(kNextChunk, "move to next chunk");
-    sink_->Put(space, "space of next chunk");
+    sink_->Put(kNextChunk, "NextChunk");
+    sink_->Put(space, "NextChunkSpace");
     completed_chunks_[space].Add(pending_chunk_[space]);
     pending_chunk_[space] = 0;
     new_chunk_size = size;
@@ -1990,7 +2051,7 @@
                                       Handle<String> source) {
   base::ElapsedTimer timer;
   if (FLAG_profile_deserialization) timer.Start();
-  if (FLAG_trace_code_serializer) {
+  if (FLAG_trace_serializer) {
     PrintF("[Serializing from");
     Object* script = info->script();
     if (script->IsScript()) Script::cast(script)->name()->ShortPrint();
@@ -2030,33 +2091,13 @@
                                      WhereToPoint where_to_point, int skip) {
   int root_index = root_index_map_.Lookup(obj);
   if (root_index != RootIndexMap::kInvalidRootIndex) {
-    if (FLAG_trace_code_serializer) {
-      PrintF(" Encoding root: %d\n", root_index);
-    }
     PutRoot(root_index, obj, how_to_code, where_to_point, skip);
     return;
   }
 
-  BackReference back_reference = back_reference_map_.Lookup(obj);
-  if (back_reference.is_valid()) {
-    if (back_reference.is_source()) {
-      DCHECK_EQ(source_, obj);
-      SerializeSourceObject(how_to_code, where_to_point);
-    } else {
-      if (FLAG_trace_code_serializer) {
-        PrintF(" Encoding back reference to: ");
-        obj->ShortPrint();
-        PrintF("\n");
-      }
-      SerializeBackReference(back_reference, how_to_code, where_to_point, skip);
-    }
-    return;
-  }
+  if (SerializeKnownObject(obj, how_to_code, where_to_point, skip)) return;
 
-  if (skip != 0) {
-    sink_->Put(kSkip, "SkipFromSerializeObject");
-    sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
-  }
+  FlushSkip(skip);
 
   if (obj->IsCode()) {
     Code* code_object = Code::cast(obj);
@@ -2109,12 +2150,6 @@
 void CodeSerializer::SerializeGeneric(HeapObject* heap_object,
                                       HowToCode how_to_code,
                                       WhereToPoint where_to_point) {
-  if (FLAG_trace_code_serializer) {
-    PrintF(" Encoding heap object: ");
-    heap_object->ShortPrint();
-    PrintF("\n");
-  }
-
   if (heap_object->IsInternalizedString()) num_internalized_strings_++;
 
   // Object has not yet been serialized.  Serialize it here.
@@ -2132,7 +2167,7 @@
   DCHECK_LT(builtin_index, Builtins::builtin_count);
   DCHECK_LE(0, builtin_index);
 
-  if (FLAG_trace_code_serializer) {
+  if (FLAG_trace_serializer) {
     PrintF(" Encoding builtin: %s\n",
            isolate()->builtins()->name(builtin_index));
   }
@@ -2152,7 +2187,7 @@
 
   int index = AddCodeStubKey(stub_key) + kCodeStubsBaseIndex;
 
-  if (FLAG_trace_code_serializer) {
+  if (FLAG_trace_serializer) {
     PrintF(" Encoding code stub %s as %d\n",
            CodeStub::MajorName(CodeStub::MajorKeyFromKey(stub_key), false),
            index);
@@ -2168,7 +2203,7 @@
   // The IC may be implemented as a stub.
   uint32_t stub_key = ic->stub_key();
   if (stub_key != CodeStub::NoCacheKey()) {
-    if (FLAG_trace_code_serializer) {
+    if (FLAG_trace_serializer) {
       PrintF(" %s is a code stub\n", Code::Kind2String(ic->kind()));
     }
     SerializeCodeStub(stub_key, how_to_code, where_to_point);
@@ -2182,7 +2217,7 @@
     Builtins::Name name = static_cast<Builtins::Name>(builtin_index);
     Code* builtin = isolate()->builtins()->builtin(name);
     if (builtin == ic) {
-      if (FLAG_trace_code_serializer) {
+      if (FLAG_trace_serializer) {
         PrintF(" %s is a builtin\n", Code::Kind2String(ic->kind()));
       }
       DCHECK(ic->kind() == Code::KEYED_LOAD_IC ||
@@ -2193,7 +2228,7 @@
   }
   // The IC may also just be a piece of code kept in the non_monomorphic_cache.
   // In that case, just serialize as a normal code object.
-  if (FLAG_trace_code_serializer) {
+  if (FLAG_trace_serializer) {
     PrintF(" %s has no special handling\n", Code::Kind2String(ic->kind()));
   }
   DCHECK(ic->kind() == Code::LOAD_IC || ic->kind() == Code::STORE_IC);
@@ -2215,7 +2250,7 @@
 
 void CodeSerializer::SerializeSourceObject(HowToCode how_to_code,
                                            WhereToPoint where_to_point) {
-  if (FLAG_trace_code_serializer) PrintF(" Encoding source object\n");
+  if (FLAG_trace_serializer) PrintF(" Encoding source object\n");
 
   DCHECK(how_to_code == kPlain && where_to_point == kStartOfObject);
   sink_->Put(kAttachedReference + how_to_code + where_to_point, "Source");
diff --git a/src/serialize.h b/src/serialize.h
index 3bb0e1a..43a01e4 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -285,6 +285,43 @@
 };
 
 
+class HotObjectsList {
+ public:
+  HotObjectsList() : index_(0) {
+    for (int i = 0; i < kSize; i++) circular_queue_[i] = NULL;
+  }
+
+  void Add(HeapObject* object) {
+    circular_queue_[index_] = object;
+    index_ = (index_ + 1) & kSizeMask;
+  }
+
+  HeapObject* Get(int index) {
+    DCHECK_NE(NULL, circular_queue_[index]);
+    return circular_queue_[index];
+  }
+
+  static const int kNotFound = -1;
+
+  int Find(HeapObject* object) {
+    for (int i = 0; i < kSize; i++) {
+      if (circular_queue_[i] == object) return i;
+    }
+    return kNotFound;
+  }
+
+  static const int kSize = 8;
+
+ private:
+  STATIC_ASSERT(IS_POWER_OF_TWO(kSize));
+  static const int kSizeMask = kSize - 1;
+  HeapObject* circular_queue_[kSize];
+  int index_;
+
+  DISALLOW_COPY_AND_ASSIGN(HotObjectsList);
+};
+
+
 // The Serializer/Deserializer class is a common superclass for Serializer and
 // Deserializer which is used to store common constants and methods used by
 // both.
@@ -303,6 +340,7 @@
   enum Where {
     kNewObject = 0,  //              Object is next in snapshot.
     // 1-7                           One per space.
+    // 0x8                           Unused.
     kRootArray = 0x9,             // Object is found in root array.
     kPartialSnapshotCache = 0xa,  // Object is in the cache.
     kExternalReference = 0xb,     // Pointer to an external reference.
@@ -346,38 +384,58 @@
   // entire code in one memcpy, then fix up stuff with kSkip and other byte
   // codes that overwrite data.
   static const int kRawData = 0x20;
-  // Some common raw lengths: 0x21-0x3f.  These autoadvance the current pointer.
-  // A tag emitted at strategic points in the snapshot to delineate sections.
-  // If the deserializer does not find these at the expected moments then it
-  // is an indication that the snapshot and the VM do not fit together.
-  // Examine the build process for architecture, version or configuration
-  // mismatches.
-  static const int kSynchronize = 0x70;
-  // Used for the source code of the natives, which is in the executable, but
-  // is referred to from external strings in the snapshot.
-  static const int kNativesStringResource = 0x71;
-  static const int kRepeat = 0x72;
-  static const int kConstantRepeat = 0x73;
-  // 0x73-0x7f            Repeat last word (subtract 0x72 to get the count).
-  static const int kMaxRepeats = 0x7f - 0x72;
+  // Some common raw lengths: 0x21-0x3f.
+  // These autoadvance the current pointer.
+  static const int kOnePointerRawData = 0x21;
+
+  static const int kVariableRepeat = 0x60;
+  // 0x61-0x6f   Repeat last word
+  static const int kFixedRepeat = 0x61;
+  static const int kFixedRepeatBase = kFixedRepeat - 1;
+  static const int kLastFixedRepeat = 0x6f;
+  static const int kMaxFixedRepeats = kLastFixedRepeat - kFixedRepeatBase;
   static int CodeForRepeats(int repeats) {
-    DCHECK(repeats >= 1 && repeats <= kMaxRepeats);
-    return 0x72 + repeats;
+    DCHECK(repeats >= 1 && repeats <= kMaxFixedRepeats);
+    return kFixedRepeatBase + repeats;
   }
   static int RepeatsForCode(int byte_code) {
-    DCHECK(byte_code >= kConstantRepeat && byte_code <= 0x7f);
-    return byte_code - 0x72;
+    DCHECK(byte_code > kFixedRepeatBase && byte_code <= kLastFixedRepeat);
+    return byte_code - kFixedRepeatBase;
   }
+
+  // Hot objects are a small set of recently seen or back-referenced objects.
+  // They are represented by a single opcode to save space.
+  // We use 0x70..0x77 for 8 hot objects, and 0x78..0x7f to add skip.
+  static const int kHotObject = 0x70;
+  static const int kMaxHotObjectIndex = 0x77 - kHotObject;
+  static const int kHotObjectWithSkip = 0x78;
+  STATIC_ASSERT(HotObjectsList::kSize == kMaxHotObjectIndex + 1);
+  STATIC_ASSERT(0x7f - kHotObjectWithSkip == kMaxHotObjectIndex);
+  static const int kHotObjectIndexMask = 0x7;
+
   static const int kRootArrayConstants = 0xa0;
-  // 0xa0-0xbf            Things from the first 32 elements of the root array.
+  // 0xa0-0xbf  Things from the first 32 elements of the root array.
   static const int kRootArrayNumberOfConstantEncodings = 0x20;
   static int RootArrayConstantFromByteCode(int byte_code) {
     return byte_code & 0x1f;
   }
 
-  static const int kNop = 0xf;  // Do nothing, used for padding.
+  // Do nothing, used for padding.
+  static const int kNop = 0xf;
 
-  static const int kNextChunk = 0x4f;  // Move to next reserved chunk.
+  // Move to next reserved chunk.
+  static const int kNextChunk = 0x4f;
+
+  // A tag emitted at strategic points in the snapshot to delineate sections.
+  // If the deserializer does not find these at the expected moments then it
+  // is an indication that the snapshot and the VM do not fit together.
+  // Examine the build process for architecture, version or configuration
+  // mismatches.
+  static const int kSynchronize = 0x8f;
+
+  // Used for the source code of the natives, which is in the executable, but
+  // is referred to from external strings in the snapshot.
+  static const int kNativesStringResource = 0xcf;
 
   static const int kAnyOldSpace = -1;
 
@@ -387,6 +445,11 @@
 
   // Sentinel after a new object to indicate that double alignment is needed.
   static const int kDoubleAlignmentSentinel = 0;
+
+  // Used as index for the attached reference representing the source object.
+  static const int kSourceObjectReference = 0;
+
+  HotObjectsList hot_objects_;
 };
 
 
@@ -449,24 +512,10 @@
 
   // Special handling for serialized code like hooking up internalized strings.
   HeapObject* ProcessNewObjectFromSerializedCode(HeapObject* obj);
-  Object* ProcessBackRefInSerializedCode(Object* obj);
 
   // This returns the address of an object that has been described in the
   // snapshot by chunk index and offset.
-  HeapObject* GetBackReferencedObject(int space) {
-    if (space == LO_SPACE) {
-      uint32_t index = source_->GetInt();
-      return deserialized_large_objects_[index];
-    } else {
-      BackReference back_reference(source_->GetInt());
-      DCHECK(space < kNumberOfPreallocatedSpaces);
-      uint32_t chunk_index = back_reference.chunk_index();
-      DCHECK_LE(chunk_index, current_chunk_[space]);
-      uint32_t chunk_offset = back_reference.chunk_offset();
-      return HeapObject::FromAddress(reservations_[space][chunk_index].start +
-                                     chunk_offset);
-    }
-  }
+  HeapObject* GetBackReferencedObject(int space);
 
   // Cached current isolate.
   Isolate* isolate_;
@@ -576,9 +625,17 @@
   void PutRoot(int index, HeapObject* object, HowToCode how, WhereToPoint where,
                int skip);
 
-  void SerializeBackReference(BackReference back_reference,
-                              HowToCode how_to_code,
-                              WhereToPoint where_to_point, int skip);
+  // Returns true if the object was successfully serialized.
+  bool SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
+                            WhereToPoint where_to_point, int skip);
+
+  inline void FlushSkip(int skip) {
+    if (skip != 0) {
+      sink_->Put(kSkip, "SkipFromSerializeObject");
+      sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
+    }
+  }
+
   void InitializeAllocators();
   // This will return the space for an object.
   static AllocationSpace SpaceOfObject(HeapObject* object);
@@ -716,6 +773,8 @@
       Isolate* isolate, ScriptData* cached_data, Handle<String> source);
 
   static const int kSourceObjectIndex = 0;
+  STATIC_ASSERT(kSourceObjectReference == kSourceObjectIndex);
+
   static const int kCodeStubsBaseIndex = 1;
 
   String* source() const {
diff --git a/src/snapshot-source-sink.h b/src/snapshot-source-sink.h
index 68901a1..398276f 100644
--- a/src/snapshot-source-sink.h
+++ b/src/snapshot-source-sink.h
@@ -24,7 +24,7 @@
 
   bool HasMore() { return position_ < length_; }
 
-  int Get() {
+  byte Get() {
     DCHECK(position_ < length_);
     return data_[position_++];
   }
diff --git a/src/version.cc b/src/version.cc
index 67ba712..7fdf033 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
 // system so their names cannot be changed without changing the scripts.
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     31
-#define BUILD_NUMBER      38
+#define BUILD_NUMBER      39
 #define PATCH_LEVEL       0
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 0939e08..2aa4eaf 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -1673,16 +1673,9 @@
   CcTest::i_isolate()->stack_guard()->SetStackLimit(
       i::GetCurrentStackPosition() - 128 * 1024);
 
+  // Experimental feature flags should not go here; pass the flags as
+  // always_true_flags if the test needs them.
   static const ParserFlag default_flags[] = {
-    kAllowHarmonyArrowFunctions,
-    kAllowHarmonyClasses,
-    kAllowHarmonyNumericLiterals,
-    kAllowHarmonyObjectLiterals,
-    kAllowHarmonyScoping,
-    kAllowHarmonyModules,
-    kAllowHarmonyTemplates,
-    kAllowHarmonySloppy,
-    kAllowHarmonyUnicode,
     kAllowLazy,
     kAllowNatives,
   };
@@ -1691,13 +1684,10 @@
     flags = default_flags;
     flags_len = arraysize(default_flags);
     if (always_true_flags != NULL || always_false_flags != NULL) {
-      // Remove always_true/false_flags from default_flags.
+      // Remove always_true/false_flags from default_flags (if present).
       CHECK((always_true_flags != NULL) == (always_true_len > 0));
       CHECK((always_false_flags != NULL) == (always_false_len > 0));
-      CHECK(always_true_flags == NULL || always_true_len < flags_len);
-      CHECK(always_false_flags == NULL || always_false_len < flags_len);
-      generated_flags =
-          new ParserFlag[flags_len - always_true_len - always_false_len];
+      generated_flags = new ParserFlag[flags_len + always_true_len];
       int flag_index = 0;
       for (int i = 0; i < flags_len; ++i) {
         bool use_flag = true;
@@ -1709,7 +1699,6 @@
         }
         if (use_flag) generated_flags[flag_index++] = flags[i];
       }
-      CHECK(flag_index == flags_len - always_true_len - always_false_len);
       flags_len = flag_index;
       flags = generated_flags;
     }
@@ -1899,14 +1888,8 @@
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
-  RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
-                    arraysize(always_flags));
-
-  static const ParserFlag classes_flags[] = {
-      kAllowHarmonyArrowFunctions, kAllowHarmonyClasses, kAllowHarmonyScoping};
-  RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
-                    classes_flags, arraysize(classes_flags));
+  RunParserSyncTest(context_data, statement_data, kError);
+  RunParserSyncTest(context_data, statement_data, kError);
 }
 
 
diff --git a/test/unittests/compiler/machine-operator-reducer-unittest.cc b/test/unittests/compiler/machine-operator-reducer-unittest.cc
index 5f9f113..3e47ce8 100644
--- a/test/unittests/compiler/machine-operator-reducer-unittest.cc
+++ b/test/unittests/compiler/machine-operator-reducer-unittest.cc
@@ -532,9 +532,10 @@
 
 TEST_F(MachineOperatorReducerTest, Word32AndWithInt32AddAndConstant) {
   Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
 
-  TRACED_FOREACH(int32_t, k, kInt32Values) {
-    TRACED_FORRANGE(int32_t, l, 1, 31) {
+  TRACED_FORRANGE(int32_t, l, 1, 31) {
+    TRACED_FOREACH(int32_t, k, kInt32Values) {
       // (x + (K << L)) & (-1 << L) => (x & (-1 << L)) + (K << L)
       Reduction const r = Reduce(graph()->NewNode(
           machine()->Word32And(),
@@ -545,6 +546,24 @@
                   IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)),
                              IsInt32Constant(k << l)));
     }
+
+    Node* s1 = graph()->NewNode(machine()->Word32Shl(), p1, Int32Constant(l));
+
+    // (y << L + x) & (-1 << L) => (x & (-1 << L)) + y << L
+    Reduction const r1 = Reduce(graph()->NewNode(
+        machine()->Word32And(), graph()->NewNode(machine()->Int32Add(), s1, p0),
+        Int32Constant(-1 << l)));
+    ASSERT_TRUE(r1.Changed());
+    EXPECT_THAT(r1.replacement(),
+                IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)), s1));
+
+    // (x + y << L) & (-1 << L) => (x & (-1 << L)) + y << L
+    Reduction const r2 = Reduce(graph()->NewNode(
+        machine()->Word32And(), graph()->NewNode(machine()->Int32Add(), p0, s1),
+        Int32Constant(-1 << l)));
+    ASSERT_TRUE(r2.Changed());
+    EXPECT_THAT(r2.replacement(),
+                IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)), s1));
   }
 }