Snapshots: Add --extra-code flag to mksnapshot which lets you specify a file
authorerikcorry <erikcorry@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 19 Jun 2012 18:38:03 +0000 (18:38 +0000)
committererikcorry <erikcorry@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 19 Jun 2012 18:38:03 +0000 (18:38 +0000)
with more JS code that is loaded into the VM before writing the snapshot.  Get
rid of the hard coded limit on the partial snapshot cache size.  This change
disables most of the serializer tests for the snapshot build of the VM: It's
getting too complicated to support both booting from a snapshot and then
creating a new snapshot from the same VM or loading more code with another
snapshot in the same VM.
Review URL: http://codereview.chromium.org/10574013

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11871 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/flag-definitions.h
src/heap.cc
src/isolate.cc
src/isolate.h
src/mksnapshot.cc
src/serialize.cc
src/serialize.h
src/snapshot-common.cc
src/snapshot.h
test/cctest/test-serialize.cc

index e9d8d5d..125d151 100644 (file)
@@ -451,6 +451,10 @@ DEFINE_string(testing_serialization_file, "/tmp/serdes",
               "file in which to serialize heap")
 #endif
 
+// mksnapshot.cc
+DEFINE_string(extra_code, NULL, "A filename with extra code to be included in"
+                  " the snapshot (mksnapshot only)")
+
 //
 // Dev shell flags
 //
@@ -610,6 +614,7 @@ DEFINE_bool(sliding_state_window, false,
 DEFINE_string(logfile, "v8.log", "Specify the name of the log file.")
 DEFINE_bool(ll_prof, false, "Enable low-level linux profiler.")
 
+
 //
 // Disassembler only flags
 //
index 914e21a..df8dde6 100644 (file)
@@ -2822,7 +2822,7 @@ void Heap::AllocateFullSizeNumberStringCache() {
   // 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.
-  ASSERT(!Serializer::enabled());
+  ASSERT(!Serializer::enabled() || FLAG_extra_code != NULL);
   MaybeObject* maybe_obj =
       AllocateFixedArray(FullSizeNumberStringCacheLength(), TENURED);
   Object* new_cache;
index 54a72d3..dae2504 100644 (file)
@@ -1550,6 +1550,11 @@ void Isolate::TearDown() {
     thread_data_table_->RemoveAllThreads(this);
   }
 
+  if (serialize_partial_snapshot_cache_ != NULL) {
+    delete[] serialize_partial_snapshot_cache_;
+    serialize_partial_snapshot_cache_ = NULL;
+  }
+
   if (!IsDefaultIsolate()) {
     delete this;
   }
@@ -1598,6 +1603,26 @@ void Isolate::Deinit() {
 }
 
 
+void Isolate::PushToPartialSnapshotCache(Object* obj) {
+  int length = serialize_partial_snapshot_cache_length();
+  int capacity = serialize_partial_snapshot_cache_capacity();
+
+  if (length >= capacity) {
+    int new_capacity = (capacity + 10) * 1.2;
+    Object** new_array = new Object*[new_capacity];
+    for (int i = 0; i < length; i++) {
+      new_array[i] = serialize_partial_snapshot_cache()[i];
+    }
+    if (capacity != 0) delete[] serialize_partial_snapshot_cache();
+    set_serialize_partial_snapshot_cache(new_array);
+    set_serialize_partial_snapshot_cache_capacity(new_capacity);
+  }
+
+  serialize_partial_snapshot_cache()[length] = obj;
+  set_serialize_partial_snapshot_cache_length(length + 1);
+}
+
+
 void Isolate::SetIsolateThreadLocals(Isolate* isolate,
                                      PerIsolateThreadData* data) {
   Thread::SetThreadLocal(isolate_key_, isolate);
@@ -1815,6 +1840,11 @@ bool Isolate::Init(Deserializer* des) {
     return false;
   }
 
+  if (create_heap_objects) {
+    // Terminate the cache array with the sentinel so we can iterate.
+    PushToPartialSnapshotCache(heap_.undefined_value());
+  }
+
   InitializeThreadLocal();
 
   bootstrapper_->Initialize(create_heap_objects);
@@ -1841,7 +1871,7 @@ bool Isolate::Init(Deserializer* des) {
 #endif
 
   // If we are deserializing, read the state into the now-empty heap.
-  if (des != NULL) {
+  if (!create_heap_objects) {
     des->Deserialize();
   }
   stub_cache_->Initialize();
@@ -1856,7 +1886,7 @@ bool Isolate::Init(Deserializer* des) {
   heap_.SetStackLimits();
 
   // Quiet the heap NaN if needed on target platform.
-  if (des != NULL) Assembler::QuietNaN(heap_.nan_value());
+  if (create_heap_objects) Assembler::QuietNaN(heap_.nan_value());
 
   deoptimizer_data_ = new DeoptimizerData;
   runtime_profiler_ = new RuntimeProfiler(this);
@@ -1864,7 +1894,7 @@ bool Isolate::Init(Deserializer* des) {
 
   // If we are deserializing, log non-function code objects and compiled
   // functions found in the snapshot.
-  if (des != NULL && (FLAG_log_code || FLAG_ll_prof)) {
+  if (create_heap_objects && (FLAG_log_code || FLAG_ll_prof)) {
     HandleScope scope;
     LOG(this, LogCodeObjects());
     LOG(this, LogCompiledFunctions());
index 5ca2b87..8cd0745 100644 (file)
@@ -307,7 +307,6 @@ class ThreadLocalTop BASE_EMBEDDED {
 
 #define ISOLATE_INIT_ARRAY_LIST(V)                                             \
   /* SerializerDeserializer state. */                                          \
-  V(Object*, serialize_partial_snapshot_cache, kPartialSnapshotCacheCapacity)  \
   V(int, jsregexp_static_offsets_vector, kJSRegexpStaticOffsetsVectorSize)     \
   V(int, bad_char_shift_table, kUC16AlphabetSize)                              \
   V(int, good_suffix_shift_table, (kBMMaxShift + 1))                           \
@@ -320,6 +319,8 @@ typedef List<HeapObject*, PreallocatedStorageAllocationPolicy> DebugObjectCache;
 #define ISOLATE_INIT_LIST(V)                                                   \
   /* SerializerDeserializer state. */                                          \
   V(int, serialize_partial_snapshot_cache_length, 0)                           \
+  V(int, serialize_partial_snapshot_cache_capacity, 0)                         \
+  V(Object**, serialize_partial_snapshot_cache, NULL)                          \
   /* Assembler state. */                                                       \
   /* A previously allocated buffer of kMinimalBufferSize bytes, or NULL. */    \
   V(byte*, assembler_spare_buffer, NULL)                                       \
@@ -610,6 +611,9 @@ class Isolate {
         (exception != heap()->termination_exception());
   }
 
+  // Serializer.
+  void PushToPartialSnapshotCache(Object* obj);
+
   // JS execution stack (see frames.h).
   static Address c_entry_fp(ThreadLocalTop* thread) {
     return thread->c_entry_fp_;
index e426a58..7bdad84 100644 (file)
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#include <errno.h>
+#include <stdio.h>
 #ifdef COMPRESS_STARTUP_DATA_BZ2
 #include <bzlib.h>
 #endif
@@ -33,6 +35,7 @@
 #include "v8.h"
 
 #include "bootstrapper.h"
+#include "flags.h"
 #include "natives.h"
 #include "platform.h"
 #include "serialize.h"
@@ -308,6 +311,62 @@ int main(int argc, char** argv) {
             "\nException thrown while compiling natives - see above.\n\n");
     exit(1);
   }
+  if (i::FLAG_extra_code != NULL) {
+    context->Enter();
+    // Capture 100 frames if anything happens.
+    V8::SetCaptureStackTraceForUncaughtExceptions(true, 100);
+    HandleScope scope;
+    const char* name = i::FLAG_extra_code;
+    FILE* file = i::OS::FOpen(name, "rb");
+    if (file == NULL) {
+      fprintf(stderr, "Failed to open '%s': errno %d\n", name, errno);
+      exit(1);
+    }
+
+    fseek(file, 0, SEEK_END);
+    int size = ftell(file);
+    rewind(file);
+
+    char* chars = new char[size + 1];
+    chars[size] = '\0';
+    for (int i = 0; i < size;) {
+      int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
+      if (read < 0) {
+        fprintf(stderr, "Failed to read '%s': errno %d\n", name, errno);
+        exit(1);
+      }
+      i += read;
+    }
+    fclose(file);
+    Local<String> source = String::New(chars);
+    TryCatch try_catch;
+    Local<Script> script = Script::Compile(source);
+    if (try_catch.HasCaught()) {
+      fprintf(stderr, "Failure compiling '%s' (see above)\n", name);
+      exit(1);
+    }
+    Handle<Value> ret = script->Run();
+    if (try_catch.HasCaught()) {
+      fprintf(stderr, "Failure running '%s'\n", name);
+      Local<Message> message = try_catch.Message();
+      Local<String> message_string = message->Get();
+      Local<String> message_line = message->GetSourceLine();
+      int len = 2 + message_string->Utf8Length() + message_line->Utf8Length();
+      char* buf = new char(len);
+      message_string->WriteUtf8(buf);
+      fprintf(stderr, "%s at line %d\n", buf, message->GetLineNumber());
+      message_line->WriteUtf8(buf);
+      fprintf(stderr, "%s\n", buf);
+      int from = message->GetStartColumn();
+      int to = message->GetEndColumn();
+      int i;
+      for (i = 0; i < from; i++) fprintf(stderr, " ");
+      for ( ; i <= to; i++) fprintf(stderr, "^");
+      fprintf(stderr, "\n");
+      exit(1);
+    }
+    context->Exit();
+  }
   // Make sure all builtin scripts are cached.
   { HandleScope scope;
     for (int i = 0; i < i::Natives::GetBuiltinsCount(); i++) {
index cf8e5e1..e4a90f1 100644 (file)
@@ -37,6 +37,7 @@
 #include "platform.h"
 #include "runtime.h"
 #include "serialize.h"
+#include "snapshot.h"
 #include "stub-cache.h"
 #include "v8threads.h"
 
@@ -674,10 +675,6 @@ void Deserializer::Deserialize() {
   ASSERT_EQ(NULL, isolate_->thread_manager()->FirstThreadStateInUse());
   // No active handles.
   ASSERT(isolate_->handle_scope_implementer()->blocks()->is_empty());
-  // Make sure the entire partial snapshot cache is traversed, filling it with
-  // valid object pointers.
-  isolate_->set_serialize_partial_snapshot_cache_length(
-      Isolate::kPartialSnapshotCacheCapacity);
   ASSERT_EQ(NULL, external_reference_decoder_);
   external_reference_decoder_ = new ExternalReferenceDecoder();
   isolate_->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG);
@@ -1149,22 +1146,6 @@ void StartupSerializer::SerializeStrongReferences() {
 
 void PartialSerializer::Serialize(Object** object) {
   this->VisitPointer(object);
-  Isolate* isolate = Isolate::Current();
-
-  // After we have done the partial serialization the partial snapshot cache
-  // will contain some references needed to decode the partial snapshot.  We
-  // fill it up with undefineds so it has a predictable length so the
-  // deserialization code doesn't need to know the length.
-  for (int index = isolate->serialize_partial_snapshot_cache_length();
-       index < Isolate::kPartialSnapshotCacheCapacity;
-       index++) {
-    isolate->serialize_partial_snapshot_cache()[index] =
-        isolate->heap()->undefined_value();
-    startup_serializer_->VisitPointer(
-        &isolate->serialize_partial_snapshot_cache()[index]);
-  }
-  isolate->set_serialize_partial_snapshot_cache_length(
-      Isolate::kPartialSnapshotCacheCapacity);
 }
 
 
@@ -1194,26 +1175,29 @@ void Serializer::VisitPointers(Object** start, Object** end) {
 
 // This ensures that the partial snapshot cache keeps things alive during GC and
 // tracks their movement.  When it is called during serialization of the startup
-// snapshot the partial snapshot is empty, so nothing happens.  When the partial
-// (context) snapshot is created, this array is populated with the pointers that
-// the partial snapshot will need. As that happens we emit serialized objects to
-// the startup snapshot that correspond to the elements of this cache array.  On
-// deserialization we therefore need to visit the cache array.  This fills it up
-// with pointers to deserialized objects.
+// snapshot nothing happens.  When the partial (context) snapshot is created,
+// this array is populated with the pointers that the partial snapshot will
+// need. As that happens we emit serialized objects to the startup snapshot
+// that correspond to the elements of this cache array.  On deserialization we
+// therefore need to visit the cache array.  This fills it up with pointers to
+// deserialized objects.
 void SerializerDeserializer::Iterate(ObjectVisitor* visitor) {
+  if (Serializer::enabled()) return;
   Isolate* isolate = Isolate::Current();
-  visitor->VisitPointers(
-      isolate->serialize_partial_snapshot_cache(),
-      &isolate->serialize_partial_snapshot_cache()[
-          isolate->serialize_partial_snapshot_cache_length()]);
-}
-
-
-// When deserializing we need to set the size of the snapshot cache.  This means
-// the root iteration code (above) will iterate over array elements, writing the
-// references to deserialized objects in them.
-void SerializerDeserializer::SetSnapshotCacheSize(int size) {
-  Isolate::Current()->set_serialize_partial_snapshot_cache_length(size);
+  for (int i = 0; ; i++) {
+    if (isolate->serialize_partial_snapshot_cache_length() <= i) {
+      // Extend the array ready to get a value from the visitor when
+      // deserializing.
+      isolate->PushToPartialSnapshotCache(Smi::FromInt(0));
+    }
+    Object** cache = isolate->serialize_partial_snapshot_cache();
+    visitor->VisitPointers(&cache[i], &cache[i + 1]);
+    // Sentinel is the undefined object, which is a root so it will not normally
+    // be found in the cache.
+    if (cache[i] == isolate->heap()->undefined_value()) {
+      break;
+    }
+  }
 }
 
 
@@ -1231,14 +1215,11 @@ int PartialSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) {
   // then visit the pointer so that it becomes part of the startup snapshot
   // and we can refer to it from the partial snapshot.
   int length = isolate->serialize_partial_snapshot_cache_length();
-  CHECK(length < Isolate::kPartialSnapshotCacheCapacity);
-  isolate->serialize_partial_snapshot_cache()[length] = heap_object;
-  startup_serializer_->VisitPointer(
-      &isolate->serialize_partial_snapshot_cache()[length]);
+  isolate->PushToPartialSnapshotCache(heap_object);
+  startup_serializer_->VisitPointer(reinterpret_cast<Object**>(&heap_object));
   // We don't recurse from the startup snapshot generator into the partial
   // snapshot generator.
-  ASSERT(length == isolate->serialize_partial_snapshot_cache_length());
-  isolate->set_serialize_partial_snapshot_cache_length(length + 1);
+  ASSERT(length == isolate->serialize_partial_snapshot_cache_length() - 1);
   return length;
 }
 
@@ -1337,12 +1318,14 @@ void StartupSerializer::SerializeObject(
 
 
 void StartupSerializer::SerializeWeakReferences() {
-  for (int i = Isolate::Current()->serialize_partial_snapshot_cache_length();
-       i < Isolate::kPartialSnapshotCacheCapacity;
-       i++) {
-    sink_->Put(kRootArray + kPlain + kStartOfObject, "RootSerialization");
-    sink_->PutInt(Heap::kUndefinedValueRootIndex, "root_index");
-  }
+  // This phase comes right after the partial 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
+  // uses to know it is done deserializing the array.
+  Isolate* isolate = Isolate::Current();
+  Object* undefined = isolate->heap()->undefined_value();
+  VisitPointer(&undefined);
   HEAP->IterateWeakRoots(this, VISIT_ALL);
 }
 
index f50e23e..d42231a 100644 (file)
@@ -210,7 +210,6 @@ class SnapshotByteSource {
 class SerializerDeserializer: public ObjectVisitor {
  public:
   static void Iterate(ObjectVisitor* visitor);
-  static void SetSnapshotCacheSize(int size);
 
  protected:
   // Where the pointed-to object can be found:
index ef89a5e..3a4ac70 100644 (file)
@@ -60,6 +60,11 @@ bool Snapshot::Initialize(const char* snapshot_file) {
 }
 
 
+bool Snapshot::HaveASnapshotToStartFrom() {
+  return size_ != 0;
+}
+
+
 Handle<Context> Snapshot::NewContextFromSnapshot() {
   if (context_size_ == 0) {
     return Handle<Context>();
index 4f01a2d..ab4529e 100644 (file)
@@ -40,6 +40,8 @@ class Snapshot {
   // could be found.
   static bool Initialize(const char* snapshot_file = NULL);
 
+  static bool HaveASnapshotToStartFrom();
+
   // Create a new context using the internal partial snapshot.
   static Handle<Context> NewContextFromSnapshot();
 
index e426e7b..e8ba2b4 100644 (file)
@@ -250,18 +250,22 @@ static void Serialize() {
 
 // Test that the whole heap can be serialized.
 TEST(Serialize) {
-  Serializer::Enable();
-  v8::V8::Initialize();
-  Serialize();
+  if (!Snapshot::HaveASnapshotToStartFrom()) {
+    Serializer::Enable();
+    v8::V8::Initialize();
+    Serialize();
+  }
 }
 
 
 // Test that heap serialization is non-destructive.
 TEST(SerializeTwice) {
-  Serializer::Enable();
-  v8::V8::Initialize();
-  Serialize();
-  Serialize();
+  if (!Snapshot::HaveASnapshotToStartFrom()) {
+    Serializer::Enable();
+    v8::V8::Initialize();
+    Serialize();
+    Serialize();
+  }
 }
 
 
@@ -289,7 +293,7 @@ DEPENDENT_TEST(Deserialize, Serialize) {
   // The serialize-deserialize tests only work if the VM is built without
   // serialization.  That doesn't matter.  We don't need to be able to
   // serialize a snapshot in a VM that is booted from a snapshot.
-  if (!Snapshot::IsEnabled()) {
+  if (!Snapshot::HaveASnapshotToStartFrom()) {
     v8::HandleScope scope;
     Deserialize();
 
@@ -302,7 +306,7 @@ DEPENDENT_TEST(Deserialize, Serialize) {
 
 
 DEPENDENT_TEST(DeserializeFromSecondSerialization, SerializeTwice) {
-  if (!Snapshot::IsEnabled()) {
+  if (!Snapshot::HaveASnapshotToStartFrom()) {
     v8::HandleScope scope;
     Deserialize();
 
@@ -315,7 +319,7 @@ DEPENDENT_TEST(DeserializeFromSecondSerialization, SerializeTwice) {
 
 
 DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
-  if (!Snapshot::IsEnabled()) {
+  if (!Snapshot::HaveASnapshotToStartFrom()) {
     v8::HandleScope scope;
     Deserialize();
 
@@ -332,7 +336,7 @@ DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
 
 DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
                SerializeTwice) {
-  if (!Snapshot::IsEnabled()) {
+  if (!Snapshot::HaveASnapshotToStartFrom()) {
     v8::HandleScope scope;
     Deserialize();
 
@@ -348,52 +352,55 @@ DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
 
 
 TEST(PartialSerialization) {
-  Serializer::Enable();
-  v8::V8::Initialize();
+  if (!Snapshot::HaveASnapshotToStartFrom()) {
+    Serializer::Enable();
+    v8::V8::Initialize();
 
-  v8::Persistent<v8::Context> env = v8::Context::New();
-  ASSERT(!env.IsEmpty());
-  env->Enter();
-  // Make sure all builtin scripts are cached.
-  { HandleScope scope;
-    for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
-      Isolate::Current()->bootstrapper()->NativesSourceLookup(i);
+    v8::Persistent<v8::Context> env = v8::Context::New();
+    ASSERT(!env.IsEmpty());
+    env->Enter();
+    // Make sure all builtin scripts are cached.
+    { HandleScope scope;
+      for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
+        Isolate::Current()->bootstrapper()->NativesSourceLookup(i);
+      }
     }
-  }
-  HEAP->CollectAllGarbage(Heap::kNoGCFlags);
-  HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+    HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+    HEAP->CollectAllGarbage(Heap::kNoGCFlags);
 
-  Object* raw_foo;
-  {
-    v8::HandleScope handle_scope;
-    v8::Local<v8::String> foo = v8::String::New("foo");
-    ASSERT(!foo.IsEmpty());
-    raw_foo = *(v8::Utils::OpenHandle(*foo));
-  }
+    Object* raw_foo;
+    {
+      v8::HandleScope handle_scope;
+      v8::Local<v8::String> foo = v8::String::New("foo");
+      ASSERT(!foo.IsEmpty());
+      raw_foo = *(v8::Utils::OpenHandle(*foo));
+    }
 
-  int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
-  Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
-  OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+    int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
+    Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
+    OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
 
-  env->Exit();
-  env.Dispose();
+    env->Exit();
+    env.Dispose();
 
-  FileByteSink startup_sink(startup_name.start());
-  startup_name.Dispose();
-  StartupSerializer startup_serializer(&startup_sink);
-  startup_serializer.SerializeStrongReferences();
-
-  FileByteSink partial_sink(FLAG_testing_serialization_file);
-  PartialSerializer p_ser(&startup_serializer, &partial_sink);
-  p_ser.Serialize(&raw_foo);
-  startup_serializer.SerializeWeakReferences();
-  partial_sink.WriteSpaceUsed(p_ser.CurrentAllocationAddress(NEW_SPACE),
-                              p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
-                              p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
-                              p_ser.CurrentAllocationAddress(CODE_SPACE),
-                              p_ser.CurrentAllocationAddress(MAP_SPACE),
-                              p_ser.CurrentAllocationAddress(CELL_SPACE),
-                              p_ser.CurrentAllocationAddress(LO_SPACE));
+    FileByteSink startup_sink(startup_name.start());
+    startup_name.Dispose();
+    StartupSerializer startup_serializer(&startup_sink);
+    startup_serializer.SerializeStrongReferences();
+
+    FileByteSink partial_sink(FLAG_testing_serialization_file);
+    PartialSerializer p_ser(&startup_serializer, &partial_sink);
+    p_ser.Serialize(&raw_foo);
+    startup_serializer.SerializeWeakReferences();
+    partial_sink.WriteSpaceUsed(
+        p_ser.CurrentAllocationAddress(NEW_SPACE),
+        p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
+        p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
+        p_ser.CurrentAllocationAddress(CODE_SPACE),
+        p_ser.CurrentAllocationAddress(MAP_SPACE),
+        p_ser.CurrentAllocationAddress(CELL_SPACE),
+        p_ser.CurrentAllocationAddress(LO_SPACE));
+  }
 }
 
 
@@ -471,53 +478,56 @@ DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
 
 
 TEST(ContextSerialization) {
-  Serializer::Enable();
-  v8::V8::Initialize();
+  if (!Snapshot::HaveASnapshotToStartFrom()) {
+    Serializer::Enable();
+    v8::V8::Initialize();
 
-  v8::Persistent<v8::Context> env = v8::Context::New();
-  ASSERT(!env.IsEmpty());
-  env->Enter();
-  // Make sure all builtin scripts are cached.
-  { HandleScope scope;
-    for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
-      Isolate::Current()->bootstrapper()->NativesSourceLookup(i);
+    v8::Persistent<v8::Context> env = v8::Context::New();
+    ASSERT(!env.IsEmpty());
+    env->Enter();
+    // Make sure all builtin scripts are cached.
+    { HandleScope scope;
+      for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
+        Isolate::Current()->bootstrapper()->NativesSourceLookup(i);
+      }
     }
-  }
-  // If we don't do this then we end up with a stray root pointing at the
-  // context even after we have disposed of env.
-  HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+    // If we don't do this then we end up with a stray root pointing at the
+    // context even after we have disposed of env.
+    HEAP->CollectAllGarbage(Heap::kNoGCFlags);
 
-  int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
-  Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
-  OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+    int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
+    Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
+    OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
 
-  env->Exit();
+    env->Exit();
 
-  Object* raw_context = *(v8::Utils::OpenHandle(*env));
+    Object* raw_context = *(v8::Utils::OpenHandle(*env));
 
-  env.Dispose();
+    env.Dispose();
 
-  FileByteSink startup_sink(startup_name.start());
-  startup_name.Dispose();
-  StartupSerializer startup_serializer(&startup_sink);
-  startup_serializer.SerializeStrongReferences();
-
-  FileByteSink partial_sink(FLAG_testing_serialization_file);
-  PartialSerializer p_ser(&startup_serializer, &partial_sink);
-  p_ser.Serialize(&raw_context);
-  startup_serializer.SerializeWeakReferences();
-  partial_sink.WriteSpaceUsed(p_ser.CurrentAllocationAddress(NEW_SPACE),
-                              p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
-                              p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
-                              p_ser.CurrentAllocationAddress(CODE_SPACE),
-                              p_ser.CurrentAllocationAddress(MAP_SPACE),
-                              p_ser.CurrentAllocationAddress(CELL_SPACE),
-                              p_ser.CurrentAllocationAddress(LO_SPACE));
+    FileByteSink startup_sink(startup_name.start());
+    startup_name.Dispose();
+    StartupSerializer startup_serializer(&startup_sink);
+    startup_serializer.SerializeStrongReferences();
+
+    FileByteSink partial_sink(FLAG_testing_serialization_file);
+    PartialSerializer p_ser(&startup_serializer, &partial_sink);
+    p_ser.Serialize(&raw_context);
+    startup_serializer.SerializeWeakReferences();
+    partial_sink.WriteSpaceUsed(
+        p_ser.CurrentAllocationAddress(NEW_SPACE),
+        p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
+        p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
+        p_ser.CurrentAllocationAddress(CODE_SPACE),
+        p_ser.CurrentAllocationAddress(MAP_SPACE),
+        p_ser.CurrentAllocationAddress(CELL_SPACE),
+        p_ser.CurrentAllocationAddress(LO_SPACE));
+  }
 }
 
 
 DEPENDENT_TEST(ContextDeserialization, ContextSerialization) {
-  if (!Snapshot::IsEnabled()) {
+  if (!Snapshot::HaveASnapshotToStartFrom()) {
     int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
     Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
     OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);