Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / v8 / src / serialize.cc
index 4b28d23..dce62fe 100644 (file)
@@ -8,17 +8,18 @@
 #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"
-#include "src/ic-inl.h"
+#include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/natives.h"
 #include "src/objects.h"
 #include "src/runtime.h"
 #include "src/serialize.h"
 #include "src/snapshot.h"
 #include "src/snapshot-source-sink.h"
-#include "src/stub-cache.h"
 #include "src/v8threads.h"
 #include "src/version.h"
 
@@ -314,7 +315,7 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
 #undef IC_ENTRY
   };  // end of ref_table[].
 
-  for (size_t i = 0; i < ARRAY_SIZE(ref_table); ++i) {
+  for (size_t i = 0; i < arraysize(ref_table); ++i) {
     AddFromId(ref_table[i].type,
               ref_table[i].id,
               ref_table[i].name,
@@ -340,7 +341,7 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
   };  // end of stats_ref_table[].
 
   Counters* counters = isolate->counters();
-  for (size_t i = 0; i < ARRAY_SIZE(stats_ref_table); ++i) {
+  for (size_t i = 0; i < arraysize(stats_ref_table); ++i) {
     Add(reinterpret_cast<Address>(GetInternalPointer(
             (counters->*(stats_ref_table[i].counter))())),
         STATS_COUNTER,
@@ -644,7 +645,7 @@ void Deserializer::Deserialize(Isolate* isolate) {
   for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
     Object* source = isolate_->heap()->natives_source_cache()->get(i);
     if (!source->IsUndefined()) {
-      ExternalAsciiString::cast(source)->update_data_cache();
+      ExternalOneByteString::cast(source)->update_data_cache();
     }
   }
 
@@ -727,14 +728,14 @@ class StringTableInsertionKey : public HashTableKey {
     return string_->SlowEquals(String::cast(string));
   }
 
-  virtual uint32_t Hash() V8_OVERRIDE { return hash_; }
+  virtual uint32_t Hash() OVERRIDE { return hash_; }
 
-  virtual uint32_t HashForObject(Object* key) V8_OVERRIDE {
+  virtual uint32_t HashForObject(Object* key) OVERRIDE {
     return String::cast(key)->Hash();
   }
 
   MUST_USE_RESULT virtual Handle<Object> AsHandle(Isolate* isolate)
-      V8_OVERRIDE {
+      OVERRIDE {
     return handle(string_, isolate);
   }
 
@@ -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);                                     \
@@ -1087,6 +1088,12 @@ void Deserializer::ReadChunk(Object** current,
       // current object.
       CASE_STATEMENT(kRootArray, kPlain, kStartOfObject, 0)
       CASE_BODY(kRootArray, kPlain, kStartOfObject, 0)
+#if defined(V8_TARGET_ARCH_MIPS) || V8_OOL_CONSTANT_POOL || \
+    defined(V8_TARGET_ARCH_MIPS64)
+      // Find an object in the roots array and write a pointer to it to in code.
+      CASE_STATEMENT(kRootArray, kFromCode, kStartOfObject, 0)
+      CASE_BODY(kRootArray, kFromCode, kStartOfObject, 0)
+#endif
       // Find an object in the partial snapshots cache and write a pointer to it
       // to the current object.
       CASE_STATEMENT(kPartialSnapshotCache, kPlain, kStartOfObject, 0)
@@ -1118,6 +1125,12 @@ void Deserializer::ReadChunk(Object** current,
       // Find a builtin and write a pointer to it to the current object.
       CASE_STATEMENT(kBuiltin, kPlain, kStartOfObject, 0)
       CASE_BODY(kBuiltin, kPlain, kStartOfObject, 0)
+#if V8_OOL_CONSTANT_POOL
+      // Find a builtin code entry and write a pointer to it to the current
+      // object.
+      CASE_STATEMENT(kBuiltin, kPlain, kInnerPointer, 0)
+      CASE_BODY(kBuiltin, kPlain, kInnerPointer, 0)
+#endif
       // Find a builtin and write a pointer to it in the current code object.
       CASE_STATEMENT(kBuiltin, kFromCode, kInnerPointer, 0)
       CASE_BODY(kBuiltin, kFromCode, kInnerPointer, 0)
@@ -1125,6 +1138,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
@@ -1291,15 +1308,6 @@ int Serializer::RootIndex(HeapObject* heap_object, HowToCode from) {
   for (int i = 0; i < root_index_wave_front_; i++) {
     Object* root = heap->roots_array_start()[i];
     if (!root->IsSmi() && root == heap_object) {
-#if defined(V8_TARGET_ARCH_MIPS) || V8_OOL_CONSTANT_POOL || \
-    defined(V8_TARGET_ARCH_MIPS64)
-      if (from == kFromCode) {
-        // In order to avoid code bloat in the deserializer we don't have
-        // support for the encoding that specifies a particular root should
-        // be written from within code.
-        return kInvalidRootIndex;
-      }
-#endif
       return i;
     }
   }
@@ -1311,12 +1319,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 +1355,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 +1458,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) {
@@ -1529,7 +1527,8 @@ void Serializer::ObjectSerializer::VisitPointers(Object** start,
           current_contents == current[-1]) {
         DCHECK(!serializer_->isolate()->heap()->InNewSpace(current_contents));
         int repeat_count = 1;
-        while (current < end - 1 && current[repeat_count] == current_contents) {
+        while (&current[repeat_count] < end - 1 &&
+               current[repeat_count] == current_contents) {
           repeat_count++;
         }
         current += repeat_count;
@@ -1626,19 +1625,20 @@ void Serializer::ObjectSerializer::VisitCell(RelocInfo* rinfo) {
   int skip = OutputRawData(rinfo->pc(), kCanReturnSkipInsteadOfSkipping);
   Cell* object = Cell::cast(rinfo->target_cell());
   serializer_->SerializeObject(object, kPlain, kInnerPointer, skip);
+  bytes_processed_so_far_ += kPointerSize;
 }
 
 
-void Serializer::ObjectSerializer::VisitExternalAsciiString(
-    v8::String::ExternalAsciiStringResource** resource_pointer) {
+void Serializer::ObjectSerializer::VisitExternalOneByteString(
+    v8::String::ExternalOneByteStringResource** resource_pointer) {
   Address references_start = reinterpret_cast<Address>(resource_pointer);
   OutputRawData(references_start);
   for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
     Object* source =
         serializer_->isolate()->heap()->natives_source_cache()->get(i);
     if (!source->IsUndefined()) {
-      ExternalAsciiString* string = ExternalAsciiString::cast(source);
-      typedef v8::String::ExternalAsciiStringResource Resource;
+      ExternalOneByteString* string = ExternalOneByteString::cast(source);
+      typedef v8::String::ExternalOneByteStringResource Resource;
       const Resource* resource = string->resource();
       if (resource == *resource_pointer) {
         sink_->Put(kNativesStringResource, "NativesStringResource");
@@ -1782,17 +1782,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 +1828,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 +1844,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 +1856,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 +1875,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);
@@ -1866,15 +1897,67 @@ void CodeSerializer::SerializeBuiltin(Code* builtin, HowToCode how_to_code,
   }
 
   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));
   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 (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 +1966,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 +1981,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 +2023,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()));
 }