commit a49ac519c8df83c52ed67e3860c51ccad80e037a
Author: yangguo@chromium.org <yangguo@chromium.org>
Date:   Wed Sep 17 12:50:17 2014 +0000

    Serialize code stubs using stub key.
    
    Also add some tracing to the code serializer.
    
    R=mvstanton@chromium.org
    
    Review URL: https://codereview.chromium.org/556243005
    
    git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24002 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 4208e62..792fda9 100644
--- node/deps/v8/src/flag-definitions.h
+++ node/deps/v8/src/flag-definitions.h
@@ -428,6 +428,7 @@ DEFINE_BOOL(trace_stub_failures, false,
             "trace deoptimization of generated code stubs")
 
 DEFINE_BOOL(serialize_toplevel, false, "enable caching of toplevel scripts")
+DEFINE_BOOL(trace_code_serializer, false, "trace code serializer")
 
 // compiler.cc
 DEFINE_INT(min_preparse_length, 1024,
diff --git a/src/serialize.cc b/src/serialize.cc
index 1a19ab0..9447fc8 100644
--- node/deps/v8/src/serialize.cc
+++ node/deps/v8/src/serialize.cc
@@ -8,6 +8,7 @@
 #include "src/api.h"
 #include "src/base/platform/platform.h"
 #include "src/bootstrapper.h"
+#include "src/code-stubs.h"
 #include "src/deoptimizer.h"
 #include "src/execution.h"
 #include "src/global-handles.h"
@@ -872,7 +873,7 @@ void Deserializer::ReadChunk(Object** current,
       } else if (where == kAttachedReference) {                                \
         DCHECK(deserializing_user_code());                                     \
         int index = source_->GetInt();                                         \
-        new_object = attached_objects_->at(index);                             \
+        new_object = *attached_objects_->at(index);                            \
         emit_write_barrier = isolate->heap()->InNewSpace(new_object);          \
       } else {                                                                 \
         DCHECK(where == kBackrefWithSkip);                                     \
@@ -1125,6 +1126,10 @@ void Deserializer::ReadChunk(Object** current,
       // the current object.
       CASE_STATEMENT(kAttachedReference, kPlain, kStartOfObject, 0)
       CASE_BODY(kAttachedReference, kPlain, kStartOfObject, 0)
+      CASE_STATEMENT(kAttachedReference, kPlain, kInnerPointer, 0)
+      CASE_BODY(kAttachedReference, kPlain, kInnerPointer, 0)
+      CASE_STATEMENT(kAttachedReference, kFromCode, kInnerPointer, 0)
+      CASE_BODY(kAttachedReference, kFromCode, kInnerPointer, 0)
 
 #undef CASE_STATEMENT
 #undef CASE_BODY
@@ -1311,12 +1316,12 @@ int Serializer::RootIndex(HeapObject* heap_object, HowToCode from) {
 // 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::SerializeReferenceToPreviousObject(
-    int space,
-    int address,
-    HowToCode how_to_code,
-    WhereToPoint where_to_point,
-    int skip) {
+void Serializer::SerializeReferenceToPreviousObject(HeapObject* heap_object,
+                                                    HowToCode how_to_code,
+                                                    WhereToPoint where_to_point,
+                                                    int skip) {
+  int space = SpaceOfObject(heap_object);
+  int address = address_mapper_.MappedTo(heap_object);
   int offset = CurrentAllocationAddress(space) - address;
   // Shift out the bits that are always 0.
   offset >>= kObjectAlignmentBits;
@@ -1347,12 +1352,7 @@ void StartupSerializer::SerializeObject(
   }
 
   if (address_mapper_.IsMapped(heap_object)) {
-    int space = SpaceOfObject(heap_object);
-    int address = address_mapper_.MappedTo(heap_object);
-    SerializeReferenceToPreviousObject(space,
-                                       address,
-                                       how_to_code,
-                                       where_to_point,
+    SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
                                        skip);
   } else {
     if (skip != 0) {
@@ -1455,12 +1455,7 @@ void PartialSerializer::SerializeObject(
   DCHECK(!heap_object->IsInternalizedString());
 
   if (address_mapper_.IsMapped(heap_object)) {
-    int space = SpaceOfObject(heap_object);
-    int address = address_mapper_.MappedTo(heap_object);
-    SerializeReferenceToPreviousObject(space,
-                                       address,
-                                       how_to_code,
-                                       where_to_point,
+    SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
                                        skip);
   } else {
     if (skip != 0) {
@@ -1782,17 +1777,32 @@ void Serializer::InitializeCodeAddressMap() {
 ScriptData* CodeSerializer::Serialize(Isolate* isolate,
                                       Handle<SharedFunctionInfo> info,
                                       Handle<String> source) {
+  base::ElapsedTimer timer;
+  if (FLAG_profile_deserialization) timer.Start();
+
   // Serialize code object.
   List<byte> payload;
   ListSnapshotSink list_sink(&payload);
-  CodeSerializer cs(isolate, &list_sink, *source);
+  DebugSnapshotSink debug_sink(&list_sink);
+  SnapshotByteSink* sink = FLAG_trace_code_serializer
+                               ? static_cast<SnapshotByteSink*>(&debug_sink)
+                               : static_cast<SnapshotByteSink*>(&list_sink);
+  CodeSerializer cs(isolate, sink, *source);
   DisallowHeapAllocation no_gc;
   Object** location = Handle<Object>::cast(info).location();
   cs.VisitPointer(location);
   cs.Pad();
 
   SerializedCodeData data(&payload, &cs);
-  return data.GetScriptData();
+  ScriptData* script_data = data.GetScriptData();
+
+  if (FLAG_profile_deserialization) {
+    double ms = timer.Elapsed().InMillisecondsF();
+    int length = script_data->length();
+    PrintF("[Serializing to %d bytes took %0.3f ms]\n", length, ms);
+  }
+
+  return script_data;
 }
 
 
@@ -1813,16 +1823,13 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
     return;
   }
 
-  // TODO(yangguo) wire up stubs from stub cache.
   // TODO(yangguo) wire up global object.
   // TODO(yangguo) We cannot deal with different hash seeds yet.
   DCHECK(!heap_object->IsHashTable());
 
   if (address_mapper_.IsMapped(heap_object)) {
-    int space = SpaceOfObject(heap_object);
-    int address = address_mapper_.MappedTo(heap_object);
-    SerializeReferenceToPreviousObject(space, address, how_to_code,
-                                       where_to_point, skip);
+    SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
+                                       skip);
     return;
   }
 
@@ -1832,7 +1839,11 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
       SerializeBuiltin(code_object, how_to_code, where_to_point, skip);
       return;
     }
-    // TODO(yangguo) figure out whether other code kinds can be handled smarter.
+    if (code_object->IsCodeStubOrIC()) {
+      SerializeCodeStub(code_object, how_to_code, where_to_point, skip);
+      return;
+    }
+    code_object->ClearInlineCaches();
   }
 
   if (heap_object == source_) {
@@ -1840,6 +1851,14 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
     return;
   }
 
+  SerializeHeapObject(heap_object, how_to_code, where_to_point, skip);
+}
+
+
+void CodeSerializer::SerializeHeapObject(HeapObject* heap_object,
+                                         HowToCode how_to_code,
+                                         WhereToPoint where_to_point,
+                                         int skip) {
   if (heap_object->IsScript()) {
     // The wrapper cache uses a Foreign object to point to a global handle.
     // However, the object visitor expects foreign objects to point to external
@@ -1851,6 +1870,13 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
     sink_->Put(kSkip, "SkipFromSerializeObject");
     sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
   }
+
+  if (FLAG_trace_code_serializer) {
+    PrintF("Encoding heap object: ");
+    heap_object->ShortPrint();
+    PrintF("\n");
+  }
+
   // Object has not yet been serialized.  Serialize it here.
   ObjectSerializer serializer(this, heap_object, sink_, how_to_code,
                               where_to_point);
@@ -1870,11 +1896,62 @@ void CodeSerializer::SerializeBuiltin(Code* builtin, HowToCode how_to_code,
   int builtin_index = builtin->builtin_index();
   DCHECK_LT(builtin_index, Builtins::builtin_count);
   DCHECK_LE(0, builtin_index);
+
+  if (FLAG_trace_code_serializer) {
+    PrintF("Encoding builtin: %s\n",
+           isolate()->builtins()->name(builtin_index));
+  }
+
   sink_->Put(kBuiltin + how_to_code + where_to_point, "Builtin");
   sink_->PutInt(builtin_index, "builtin_index");
 }
 
 
+void CodeSerializer::SerializeCodeStub(Code* code, HowToCode how_to_code,
+                                       WhereToPoint where_to_point, int skip) {
+  DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) ||
+         (how_to_code == kPlain && where_to_point == kInnerPointer) ||
+         (how_to_code == kFromCode && where_to_point == kInnerPointer));
+  uint32_t stub_key = code->stub_key();
+
+  if (CodeStub::MajorKeyFromKey(stub_key) == CodeStub::NoCacheKey()) {
+    if (FLAG_trace_code_serializer) {
+      PrintF("Encoding uncacheable code stub as heap object\n");
+    }
+    SerializeHeapObject(code, how_to_code, where_to_point, skip);
+    return;
+  }
+
+  if (skip != 0) {
+    sink_->Put(kSkip, "SkipFromSerializeCodeStub");
+    sink_->PutInt(skip, "SkipDistanceFromSerializeCodeStub");
+  }
+
+  int index = AddCodeStubKey(stub_key) + kCodeStubsBaseIndex;
+
+  if (FLAG_trace_code_serializer) {
+    PrintF("Encoding code stub %s as %d\n",
+           CodeStub::MajorName(CodeStub::MajorKeyFromKey(stub_key), false),
+           index);
+  }
+
+  sink_->Put(kAttachedReference + how_to_code + where_to_point, "CodeStub");
+  sink_->PutInt(index, "CodeStub key");
+}
+
+
+int CodeSerializer::AddCodeStubKey(uint32_t stub_key) {
+  // TODO(yangguo) Maybe we need a hash table for a faster lookup than O(n^2).
+  int index = 0;
+  while (index < stub_keys_.length()) {
+    if (stub_keys_[index] == stub_key) return index;
+    index++;
+  }
+  stub_keys_.Add(stub_key);
+  return index;
+}
+
+
 void CodeSerializer::SerializeSourceObject(HowToCode how_to_code,
                                            WhereToPoint where_to_point,
                                            int skip) {
@@ -1883,6 +1960,10 @@ void CodeSerializer::SerializeSourceObject(HowToCode how_to_code,
     sink_->PutInt(skip, "SkipDistanceFromSerializeSourceObject");
   }
 
+  if (FLAG_trace_code_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(kSourceObjectIndex, "kSourceObjectIndex");
@@ -1894,22 +1975,36 @@ Handle<SharedFunctionInfo> CodeSerializer::Deserialize(Isolate* isolate,
                                                        Handle<String> source) {
   base::ElapsedTimer timer;
   if (FLAG_profile_deserialization) timer.Start();
-  SerializedCodeData scd(data, *source);
-  SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
-  Deserializer deserializer(&payload);
-  STATIC_ASSERT(NEW_SPACE == 0);
-  for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
-    deserializer.set_reservation(i, scd.GetReservation(i));
-  }
-
-  // Prepare and register list of attached objects.
-  Vector<Object*> attached_objects = Vector<Object*>::New(1);
-  attached_objects[kSourceObjectIndex] = *source;
-  deserializer.SetAttachedObjects(&attached_objects);
 
   Object* root;
-  deserializer.DeserializePartial(isolate, &root);
-  deserializer.FlushICacheForNewCodeObjects();
+
+  {
+    HandleScope scope(isolate);
+
+    SerializedCodeData scd(data, *source);
+    SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
+    Deserializer deserializer(&payload);
+    STATIC_ASSERT(NEW_SPACE == 0);
+    for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
+      deserializer.set_reservation(i, scd.GetReservation(i));
+    }
+
+    // Prepare and register list of attached objects.
+    Vector<const uint32_t> code_stub_keys = scd.CodeStubKeys();
+    Vector<Handle<Object> > attached_objects = Vector<Handle<Object> >::New(
+        code_stub_keys.length() + kCodeStubsBaseIndex);
+    attached_objects[kSourceObjectIndex] = source;
+    for (int i = 0; i < code_stub_keys.length(); i++) {
+      attached_objects[i + kCodeStubsBaseIndex] =
+          CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked();
+    }
+    deserializer.SetAttachedObjects(&attached_objects);
+
+    // Deserialize.
+    deserializer.DeserializePartial(isolate, &root);
+    deserializer.FlushICacheForNewCodeObjects();
+  }
+
   if (FLAG_profile_deserialization) {
     double ms = timer.Elapsed().InMillisecondsF();
     int length = data->length();
@@ -1922,18 +2017,35 @@ Handle<SharedFunctionInfo> CodeSerializer::Deserialize(Isolate* isolate,
 SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
     : owns_script_data_(true) {
   DisallowHeapAllocation no_gc;
-  int data_length = payload->length() + kHeaderEntries * kIntSize;
+  List<uint32_t>* stub_keys = cs->stub_keys();
+
+  // Calculate sizes.
+  int num_stub_keys = stub_keys->length();
+  int stub_keys_size = stub_keys->length() * kInt32Size;
+  int data_length = kHeaderSize + stub_keys_size + payload->length();
+
+  // Allocate backing store and create result data.
   byte* data = NewArray<byte>(data_length);
   DCHECK(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
-  CopyBytes(data + kHeaderEntries * kIntSize, payload->begin(),
-            static_cast<size_t>(payload->length()));
   script_data_ = new ScriptData(data, data_length);
   script_data_->AcquireDataOwnership();
+
+  // Set header values.
   SetHeaderValue(kCheckSumOffset, CheckSum(cs->source()));
+  SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
+  SetHeaderValue(kPayloadLengthOffset, payload->length());
   STATIC_ASSERT(NEW_SPACE == 0);
   for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
     SetHeaderValue(kReservationsOffset + i, cs->CurrentAllocationAddress(i));
   }
+
+  // Copy code stub keys.
+  CopyBytes(data + kHeaderSize, reinterpret_cast<byte*>(stub_keys->begin()),
+            stub_keys_size);
+
+  // Copy serialized data.
+  CopyBytes(data + kHeaderSize + stub_keys_size, payload->begin(),
+            static_cast<size_t>(payload->length()));
 }
 
 
diff --git a/src/serialize.h b/src/serialize.h
index 066d75f..71b274b 100644
--- node/deps/v8/src/serialize.h
+++ node/deps/v8/src/serialize.h
@@ -257,7 +257,7 @@ class Deserializer: public SerializerDeserializer {
 
   // Serialized user code reference certain objects that are provided in a list
   // By calling this method, we assume that we are deserializing user code.
-  void SetAttachedObjects(Vector<Object*>* attached_objects) {
+  void SetAttachedObjects(Vector<Handle<Object> >* attached_objects) {
     attached_objects_ = attached_objects;
   }
 
@@ -308,7 +308,7 @@ class Deserializer: public SerializerDeserializer {
   Isolate* isolate_;
 
   // Objects from the attached object descriptions in the serialized user code.
-  Vector<Object*>* attached_objects_;
+  Vector<Handle<Object> >* attached_objects_;
 
   SnapshotByteSource* source_;
   // This is the address of the next object that will be allocated in each
@@ -459,12 +459,10 @@ class Serializer : public SerializerDeserializer {
                                HowToCode how_to_code,
                                WhereToPoint where_to_point,
                                int skip) = 0;
-  void SerializeReferenceToPreviousObject(
-      int space,
-      int address,
-      HowToCode how_to_code,
-      WhereToPoint where_to_point,
-      int skip);
+  void SerializeReferenceToPreviousObject(HeapObject* heap_object,
+                                          HowToCode how_to_code,
+                                          WhereToPoint where_to_point,
+                                          int skip);
   void InitializeAllocators();
   // This will return the space for an object.
   static int SpaceOfObject(HeapObject* object);
@@ -594,20 +592,29 @@ class CodeSerializer : public Serializer {
                                                 Handle<String> source);
 
   static const int kSourceObjectIndex = 0;
+  static const int kCodeStubsBaseIndex = 1;
 
   String* source() {
     DCHECK(!AllowHeapAllocation::IsAllowed());
     return source_;
   }
 
+  List<uint32_t>* stub_keys() { return &stub_keys_; }
+
  private:
   void SerializeBuiltin(Code* builtin, HowToCode how_to_code,
                         WhereToPoint where_to_point, int skip);
+  void SerializeCodeStub(Code* code, HowToCode how_to_code,
+                         WhereToPoint where_to_point, int skip);
   void SerializeSourceObject(HowToCode how_to_code, WhereToPoint where_to_point,
                              int skip);
+  void SerializeHeapObject(HeapObject* heap_object, HowToCode how_to_code,
+                           WhereToPoint where_to_point, int skip);
+  int AddCodeStubKey(uint32_t stub_key);
 
   DisallowHeapAllocation no_gc_;
   String* source_;
+  List<uint32_t> stub_keys_;
   DISALLOW_COPY_AND_ASSIGN(CodeSerializer);
 };
 
@@ -638,12 +645,22 @@ class SerializedCodeData {
     return result;
   }
 
+  Vector<const uint32_t> CodeStubKeys() const {
+    return Vector<const uint32_t>(
+        reinterpret_cast<const uint32_t*>(script_data_->data() + kHeaderSize),
+        GetHeaderValue(kNumCodeStubKeysOffset));
+  }
+
   const byte* Payload() const {
-    return script_data_->data() + kHeaderEntries * kIntSize;
+    int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size;
+    return script_data_->data() + kHeaderSize + code_stubs_size;
   }
 
   int PayloadLength() const {
-    return script_data_->length() - kHeaderEntries * kIntSize;
+    int payload_length = GetHeaderValue(kPayloadLengthOffset);
+    DCHECK_EQ(script_data_->data() + script_data_->length(),
+              Payload() + payload_length);
+    return payload_length;
   }
 
   int GetReservation(int space) const {
@@ -666,10 +683,21 @@ class SerializedCodeData {
 
   // The data header consists of int-sized entries:
   // [0] version hash
-  // [1..7] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE.
+  // [1] number of code stub keys
+  // [2] payload length
+  // [3..9] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE.
   static const int kCheckSumOffset = 0;
-  static const int kReservationsOffset = 1;
-  static const int kHeaderEntries = 8;
+  static const int kNumCodeStubKeysOffset = 1;
+  static const int kPayloadLengthOffset = 2;
+  static const int kReservationsOffset = 3;
+
+  static const int kNumSpaces = PROPERTY_CELL_SPACE - NEW_SPACE + 1;
+  static const int kHeaderEntries = kReservationsOffset + kNumSpaces;
+  static const int kHeaderSize = kHeaderEntries * kIntSize;
+
+  // Following the header, we store, in sequential order
+  // - code stub keys
+  // - serialization payload
 
   ScriptData* script_data_;
   bool owns_script_data_;
