Fix remaining issues in the custom snapshot.
authoryangguo <yangguo@chromium.org>
Thu, 15 Jan 2015 11:22:04 +0000 (03:22 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 15 Jan 2015 11:22:17 +0000 (11:22 +0000)
Math functions:
Some Math functions require typed arrays for their implementation. The embedded
script may call those Math functions. The serializer needs to deal with this.
Added assertion to make sure no other typed array is created when snapshotting.

Number-string cache:
We assume that the initial snapshot does not expand the number-string cache.
This is no longer true for custom heap snapshots.

Bound functions:
Bound functions store the bound arguments in a COW fixed array, including the
bindee function. COW arrays are serialized into the startup snapshot and
referenced in the partial snapshot via partial snapshot cache. However, the
bindee function is context-dependent and must not be part of the startup
snapshot. There is no need for bound functions to use a COW array though.

R=jochen@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#26072}

src/bootstrapper.cc
src/factory.cc
src/heap/heap.h
src/objects-inl.h
src/runtime/runtime-function.cc
src/runtime/runtime-typedarray.cc
src/serialize.cc
test/cctest/cctest.h
test/cctest/test-heap-profiler.cc
test/cctest/test-heap.cc
test/cctest/test-serialize.cc

index 41833ca..184bad7 100644 (file)
@@ -2791,10 +2791,9 @@ Genesis::Genesis(Isolate* isolate,
   if (!InstallExperimentalNatives()) return;
   InitializeExperimentalGlobal();
 
-  // We can't (de-)serialize typed arrays currently, but we are lucky: The state
-  // of the random number generator needs no initialization during snapshot
-  // creation time and we don't need trigonometric functions then.
-  if (!isolate->serializer_enabled()) {
+  // The serializer cannot serialize typed arrays. Reset those typed arrays
+  // for each new context.
+  {
     // Initially seed the per-context random number generator using the
     // per-isolate random number generator.
     const int num_elems = 2;
index 2852674..9688305 100644 (file)
@@ -2149,12 +2149,6 @@ void Factory::SetNumberStringCache(Handle<Object> number,
   if (number_string_cache()->get(hash * 2) != *undefined_value()) {
     int full_size = isolate()->heap()->FullSizeNumberStringCacheLength();
     if (number_string_cache()->length() != full_size) {
-      // The first time we have a hash collision, we move to the full sized
-      // number string cache.  The idea is to have a small number string
-      // cache in the snapshot to keep  boot-time memory usage down.
-      // If we expand the number string cache already while creating
-      // the snapshot then that didn't work out.
-      DCHECK(!isolate()->serializer_enabled());
       Handle<FixedArray> new_cache = NewFixedArray(full_size, TENURED);
       isolate()->heap()->set_number_string_cache(*new_cache);
       return;
index 6aeaff8..5fc3f07 100644 (file)
@@ -1486,6 +1486,10 @@ class Heap {
   MUST_USE_RESULT AllocationResult
       AllocateFixedArray(int length, PretenureFlag pretenure = NOT_TENURED);
 
+  static const int kInitialStringTableSize = 2048;
+  static const int kInitialEvalCacheSize = 64;
+  static const int kInitialNumberStringCacheSize = 256;
+
  private:
   Heap();
 
@@ -2043,10 +2047,6 @@ class Heap {
   inline void UpdateAllocationsHash(uint32_t value);
   inline void PrintAlloctionsHash();
 
-  static const int kInitialStringTableSize = 2048;
-  static const int kInitialEvalCacheSize = 64;
-  static const int kInitialNumberStringCacheSize = 256;
-
   // Object counts and used memory by InstanceType
   size_t object_counts_[OBJECT_STATS_COUNT];
   size_t object_counts_last_time_[OBJECT_STATS_COUNT];
index 7a00868..076df3d 100644 (file)
@@ -6186,7 +6186,7 @@ void JSFunction::set_function_bindings(FixedArray* bindings) {
   // Bound function literal may be initialized to the empty fixed array
   // before the bindings are set.
   DCHECK(bindings == GetHeap()->empty_fixed_array() ||
-         bindings->map() == GetHeap()->fixed_cow_array_map());
+         bindings->map() == GetHeap()->fixed_array_map());
   set_literals_or_bindings(bindings);
 }
 
index e25b659..608cc95 100644 (file)
@@ -435,8 +435,7 @@ RUNTIME_FUNCTION(Runtime_FunctionBindArguments) {
   for (int j = 0; j < argc; j++, i++) {
     new_bindings->set(i, *arguments[j + 1]);
   }
-  new_bindings->set_map_no_write_barrier(
-      isolate->heap()->fixed_cow_array_map());
+  new_bindings->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
   bound_function->set_function_bindings(*new_bindings);
 
   // Update length. Have to remove the prototype first so that map migration
@@ -462,8 +461,8 @@ RUNTIME_FUNCTION(Runtime_BoundFunctionGetBindings) {
   if (callable->IsJSFunction()) {
     Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
     if (function->shared()->bound()) {
+      RUNTIME_ASSERT(function->function_bindings()->IsFixedArray());
       Handle<FixedArray> bindings(function->function_bindings());
-      RUNTIME_ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
       return *isolate->factory()->NewJSArrayWithElements(bindings);
     }
   }
index cd2c0eb..82224bc 100644 (file)
@@ -63,6 +63,8 @@ bool Runtime::SetupArrayBufferAllocatingData(Isolate* isolate,
                                              bool initialize) {
   void* data;
   CHECK(V8::ArrayBufferAllocator() != NULL);
+  // Prevent creating array buffers when serializing.
+  DCHECK(!isolate->serializer_enabled());
   if (allocated_length != 0) {
     if (initialize) {
       data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
index febb87b..8d6d550 100644 (file)
@@ -1665,6 +1665,9 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
     DCHECK(Map::cast(obj)->code_cache() == obj->GetHeap()->empty_fixed_array());
   }
 
+  // Replace typed arrays by undefined.
+  if (obj->IsJSTypedArray()) obj = isolate_->heap()->undefined_value();
+
   int root_index = root_index_map_.Lookup(obj);
   if (root_index != RootIndexMap::kInvalidRootIndex) {
     PutRoot(root_index, obj, how_to_code, where_to_point, skip);
@@ -1832,6 +1835,9 @@ void Serializer::ObjectSerializer::Serialize() {
     PrintF("\n");
   }
 
+  // We cannot serialize typed array objects correctly.
+  DCHECK(!object_->IsJSTypedArray());
+
   if (object_->IsScript()) {
     // Clear cached line ends.
     Object* undefined = serializer_->isolate()->heap()->undefined_value();
index a8239d2..af0f666 100644 (file)
@@ -99,6 +99,7 @@ class TestHeap : public i::Heap {
   using i::Heap::AllocateJSObjectFromMap;
   using i::Heap::AllocateMap;
   using i::Heap::CopyCode;
+  using i::Heap::kInitialNumberStringCacheSize;
 };
 
 
index 94a5be4..13bcebc 100644 (file)
@@ -261,7 +261,7 @@ TEST(BoundFunctionInSnapshot) {
       GetProperty(f, v8::HeapGraphEdge::kInternal, "bindings");
   CHECK_NE(NULL, bindings);
   CHECK_EQ(v8::HeapGraphNode::kArray, bindings->GetType());
-  CHECK_EQ(4, bindings->GetChildrenCount());
+  CHECK_EQ(3, bindings->GetChildrenCount());
 
   const v8::HeapGraphNode* bound_this = GetProperty(
       f, v8::HeapGraphEdge::kShortcut, "bound_this");
index f8a7df2..11aee2e 100644 (file)
@@ -5089,6 +5089,16 @@ TEST(Regress442710) {
 }
 
 
+TEST(NumberStringCacheSize) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  // Test that the number-string cache has not been resized.
+  CHECK_EQ(TestHeap::kInitialNumberStringCacheSize * 2,
+           heap->number_string_cache()->length());
+}
+
+
 #ifdef DEBUG
 TEST(PathTracer) {
   CcTest::InitializeVM();
index a06cfbb..eb59779 100644 (file)
@@ -565,7 +565,9 @@ UNINITIALIZED_TEST(CustomContextSerialization) {
             "(function() {"
             "  e = function(s) { eval (s); }"
             "})();"
-            "var o = this;");
+            "var o = this;"
+            "var r = Math.random();"
+            "var f = (function(a, b) {}).bind(1, 2, 3);");
       }
       // Make sure all builtin scripts are cached.
       {