Home | History | Annotate | Download | only in cctest
      1 // Copyright 2007-2010 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include <signal.h>
     29 
     30 #include <sys/stat.h>
     31 
     32 #include "src/v8.h"
     33 
     34 #include "src/bootstrapper.h"
     35 #include "src/compilation-cache.h"
     36 #include "src/debug.h"
     37 #include "src/heap/spaces.h"
     38 #include "src/natives.h"
     39 #include "src/objects.h"
     40 #include "src/runtime.h"
     41 #include "src/scopeinfo.h"
     42 #include "src/serialize.h"
     43 #include "src/snapshot.h"
     44 #include "test/cctest/cctest.h"
     45 
     46 using namespace v8::internal;
     47 
     48 
     49 template <class T>
     50 static Address AddressOf(T id) {
     51   return ExternalReference(id, CcTest::i_isolate()).address();
     52 }
     53 
     54 
     55 template <class T>
     56 static uint32_t Encode(const ExternalReferenceEncoder& encoder, T id) {
     57   return encoder.Encode(AddressOf(id));
     58 }
     59 
     60 
     61 static int make_code(TypeCode type, int id) {
     62   return static_cast<uint32_t>(type) << kReferenceTypeShift | id;
     63 }
     64 
     65 
     66 TEST(ExternalReferenceEncoder) {
     67   Isolate* isolate = CcTest::i_isolate();
     68   v8::V8::Initialize();
     69 
     70   ExternalReferenceEncoder encoder(isolate);
     71   CHECK_EQ(make_code(BUILTIN, Builtins::kArrayCode),
     72            Encode(encoder, Builtins::kArrayCode));
     73   CHECK_EQ(make_code(v8::internal::RUNTIME_FUNCTION, Runtime::kAbort),
     74            Encode(encoder, Runtime::kAbort));
     75   ExternalReference stack_limit_address =
     76       ExternalReference::address_of_stack_limit(isolate);
     77   CHECK_EQ(make_code(UNCLASSIFIED, 2),
     78            encoder.Encode(stack_limit_address.address()));
     79   ExternalReference real_stack_limit_address =
     80       ExternalReference::address_of_real_stack_limit(isolate);
     81   CHECK_EQ(make_code(UNCLASSIFIED, 3),
     82            encoder.Encode(real_stack_limit_address.address()));
     83   CHECK_EQ(make_code(UNCLASSIFIED, 8),
     84            encoder.Encode(ExternalReference::debug_break(isolate).address()));
     85   CHECK_EQ(
     86       make_code(UNCLASSIFIED, 4),
     87       encoder.Encode(ExternalReference::new_space_start(isolate).address()));
     88   CHECK_EQ(
     89       make_code(UNCLASSIFIED, 1),
     90       encoder.Encode(ExternalReference::roots_array_start(isolate).address()));
     91   CHECK_EQ(make_code(UNCLASSIFIED, 34),
     92            encoder.Encode(ExternalReference::cpu_features().address()));
     93 }
     94 
     95 
     96 TEST(ExternalReferenceDecoder) {
     97   Isolate* isolate = CcTest::i_isolate();
     98   v8::V8::Initialize();
     99 
    100   ExternalReferenceDecoder decoder(isolate);
    101   CHECK_EQ(AddressOf(Builtins::kArrayCode),
    102            decoder.Decode(make_code(BUILTIN, Builtins::kArrayCode)));
    103   CHECK_EQ(AddressOf(Runtime::kAbort),
    104            decoder.Decode(make_code(v8::internal::RUNTIME_FUNCTION,
    105                                     Runtime::kAbort)));
    106   CHECK_EQ(ExternalReference::address_of_stack_limit(isolate).address(),
    107            decoder.Decode(make_code(UNCLASSIFIED, 2)));
    108   CHECK_EQ(ExternalReference::address_of_real_stack_limit(isolate).address(),
    109            decoder.Decode(make_code(UNCLASSIFIED, 3)));
    110   CHECK_EQ(ExternalReference::debug_break(isolate).address(),
    111            decoder.Decode(make_code(UNCLASSIFIED, 8)));
    112   CHECK_EQ(ExternalReference::new_space_start(isolate).address(),
    113            decoder.Decode(make_code(UNCLASSIFIED, 4)));
    114 }
    115 
    116 
    117 class FileByteSink : public SnapshotByteSink {
    118  public:
    119   explicit FileByteSink(const char* snapshot_file) {
    120     fp_ = v8::base::OS::FOpen(snapshot_file, "wb");
    121     file_name_ = snapshot_file;
    122     if (fp_ == NULL) {
    123       PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file);
    124       exit(1);
    125     }
    126   }
    127   virtual ~FileByteSink() {
    128     if (fp_ != NULL) {
    129       fclose(fp_);
    130     }
    131   }
    132   virtual void Put(byte b, const char* description) {
    133     if (fp_ != NULL) {
    134       fputc(b, fp_);
    135     }
    136   }
    137   virtual int Position() {
    138     return ftell(fp_);
    139   }
    140   void WriteSpaceUsed(
    141       int new_space_used,
    142       int pointer_space_used,
    143       int data_space_used,
    144       int code_space_used,
    145       int map_space_used,
    146       int cell_space_used,
    147       int property_cell_space_used);
    148 
    149  private:
    150   FILE* fp_;
    151   const char* file_name_;
    152 };
    153 
    154 
    155 void FileByteSink::WriteSpaceUsed(
    156       int new_space_used,
    157       int pointer_space_used,
    158       int data_space_used,
    159       int code_space_used,
    160       int map_space_used,
    161       int cell_space_used,
    162       int property_cell_space_used) {
    163   int file_name_length = StrLength(file_name_) + 10;
    164   Vector<char> name = Vector<char>::New(file_name_length + 1);
    165   SNPrintF(name, "%s.size", file_name_);
    166   FILE* fp = v8::base::OS::FOpen(name.start(), "w");
    167   name.Dispose();
    168   fprintf(fp, "new %d\n", new_space_used);
    169   fprintf(fp, "pointer %d\n", pointer_space_used);
    170   fprintf(fp, "data %d\n", data_space_used);
    171   fprintf(fp, "code %d\n", code_space_used);
    172   fprintf(fp, "map %d\n", map_space_used);
    173   fprintf(fp, "cell %d\n", cell_space_used);
    174   fprintf(fp, "property cell %d\n", property_cell_space_used);
    175   fclose(fp);
    176 }
    177 
    178 
    179 static bool WriteToFile(Isolate* isolate, const char* snapshot_file) {
    180   FileByteSink file(snapshot_file);
    181   StartupSerializer ser(isolate, &file);
    182   ser.Serialize();
    183 
    184   file.WriteSpaceUsed(
    185       ser.CurrentAllocationAddress(NEW_SPACE),
    186       ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
    187       ser.CurrentAllocationAddress(OLD_DATA_SPACE),
    188       ser.CurrentAllocationAddress(CODE_SPACE),
    189       ser.CurrentAllocationAddress(MAP_SPACE),
    190       ser.CurrentAllocationAddress(CELL_SPACE),
    191       ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
    192 
    193   return true;
    194 }
    195 
    196 
    197 static void Serialize(v8::Isolate* isolate) {
    198   // We have to create one context.  One reason for this is so that the builtins
    199   // can be loaded from v8natives.js and their addresses can be processed.  This
    200   // will clear the pending fixups array, which would otherwise contain GC roots
    201   // that would confuse the serialization/deserialization process.
    202   v8::Isolate::Scope isolate_scope(isolate);
    203   {
    204     v8::HandleScope scope(isolate);
    205     v8::Context::New(isolate);
    206   }
    207 
    208   Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
    209   internal_isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "serialize");
    210   WriteToFile(internal_isolate, FLAG_testing_serialization_file);
    211 }
    212 
    213 
    214 // Test that the whole heap can be serialized.
    215 UNINITIALIZED_TEST(Serialize) {
    216   if (!Snapshot::HaveASnapshotToStartFrom()) {
    217     v8::Isolate::CreateParams params;
    218     params.enable_serializer = true;
    219     v8::Isolate* isolate = v8::Isolate::New(params);
    220     Serialize(isolate);
    221   }
    222 }
    223 
    224 
    225 // Test that heap serialization is non-destructive.
    226 UNINITIALIZED_TEST(SerializeTwice) {
    227   if (!Snapshot::HaveASnapshotToStartFrom()) {
    228     v8::Isolate::CreateParams params;
    229     params.enable_serializer = true;
    230     v8::Isolate* isolate = v8::Isolate::New(params);
    231     Serialize(isolate);
    232     Serialize(isolate);
    233   }
    234 }
    235 
    236 
    237 //----------------------------------------------------------------------------
    238 // Tests that the heap can be deserialized.
    239 
    240 
    241 static void ReserveSpaceForSnapshot(Deserializer* deserializer,
    242                                     const char* file_name) {
    243   int file_name_length = StrLength(file_name) + 10;
    244   Vector<char> name = Vector<char>::New(file_name_length + 1);
    245   SNPrintF(name, "%s.size", file_name);
    246   FILE* fp = v8::base::OS::FOpen(name.start(), "r");
    247   name.Dispose();
    248   int new_size, pointer_size, data_size, code_size, map_size, cell_size,
    249       property_cell_size;
    250 #ifdef _MSC_VER
    251   // Avoid warning about unsafe fscanf from MSVC.
    252   // Please note that this is only fine if %c and %s are not being used.
    253 #define fscanf fscanf_s
    254 #endif
    255   CHECK_EQ(1, fscanf(fp, "new %d\n", &new_size));
    256   CHECK_EQ(1, fscanf(fp, "pointer %d\n", &pointer_size));
    257   CHECK_EQ(1, fscanf(fp, "data %d\n", &data_size));
    258   CHECK_EQ(1, fscanf(fp, "code %d\n", &code_size));
    259   CHECK_EQ(1, fscanf(fp, "map %d\n", &map_size));
    260   CHECK_EQ(1, fscanf(fp, "cell %d\n", &cell_size));
    261   CHECK_EQ(1, fscanf(fp, "property cell %d\n", &property_cell_size));
    262 #ifdef _MSC_VER
    263 #undef fscanf
    264 #endif
    265   fclose(fp);
    266   deserializer->set_reservation(NEW_SPACE, new_size);
    267   deserializer->set_reservation(OLD_POINTER_SPACE, pointer_size);
    268   deserializer->set_reservation(OLD_DATA_SPACE, data_size);
    269   deserializer->set_reservation(CODE_SPACE, code_size);
    270   deserializer->set_reservation(MAP_SPACE, map_size);
    271   deserializer->set_reservation(CELL_SPACE, cell_size);
    272   deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_size);
    273 }
    274 
    275 
    276 v8::Isolate* InitializeFromFile(const char* snapshot_file) {
    277   int len;
    278   byte* str = ReadBytes(snapshot_file, &len);
    279   if (!str) return NULL;
    280   v8::Isolate* v8_isolate = NULL;
    281   {
    282     SnapshotByteSource source(str, len);
    283     Deserializer deserializer(&source);
    284     ReserveSpaceForSnapshot(&deserializer, snapshot_file);
    285     Isolate* isolate = Isolate::NewForTesting();
    286     v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
    287     v8::Isolate::Scope isolate_scope(v8_isolate);
    288     isolate->Init(&deserializer);
    289   }
    290   DeleteArray(str);
    291   return v8_isolate;
    292 }
    293 
    294 
    295 static v8::Isolate* Deserialize() {
    296   v8::Isolate* isolate = InitializeFromFile(FLAG_testing_serialization_file);
    297   CHECK(isolate);
    298   return isolate;
    299 }
    300 
    301 
    302 static void SanityCheck(v8::Isolate* v8_isolate) {
    303   Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
    304   v8::HandleScope scope(v8_isolate);
    305 #ifdef VERIFY_HEAP
    306   isolate->heap()->Verify();
    307 #endif
    308   CHECK(isolate->global_object()->IsJSObject());
    309   CHECK(isolate->native_context()->IsContext());
    310   CHECK(isolate->heap()->string_table()->IsStringTable());
    311   isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("Empty"));
    312 }
    313 
    314 
    315 UNINITIALIZED_DEPENDENT_TEST(Deserialize, Serialize) {
    316   // The serialize-deserialize tests only work if the VM is built without
    317   // serialization.  That doesn't matter.  We don't need to be able to
    318   // serialize a snapshot in a VM that is booted from a snapshot.
    319   if (!Snapshot::HaveASnapshotToStartFrom()) {
    320     v8::Isolate* isolate = Deserialize();
    321     {
    322       v8::HandleScope handle_scope(isolate);
    323       v8::Isolate::Scope isolate_scope(isolate);
    324 
    325       v8::Local<v8::Context> env = v8::Context::New(isolate);
    326       env->Enter();
    327 
    328       SanityCheck(isolate);
    329     }
    330     isolate->Dispose();
    331   }
    332 }
    333 
    334 
    335 UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerialization,
    336                              SerializeTwice) {
    337   if (!Snapshot::HaveASnapshotToStartFrom()) {
    338     v8::Isolate* isolate = Deserialize();
    339     {
    340       v8::Isolate::Scope isolate_scope(isolate);
    341       v8::HandleScope handle_scope(isolate);
    342 
    343       v8::Local<v8::Context> env = v8::Context::New(isolate);
    344       env->Enter();
    345 
    346       SanityCheck(isolate);
    347     }
    348     isolate->Dispose();
    349   }
    350 }
    351 
    352 
    353 UNINITIALIZED_DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
    354   if (!Snapshot::HaveASnapshotToStartFrom()) {
    355     v8::Isolate* isolate = Deserialize();
    356     {
    357       v8::Isolate::Scope isolate_scope(isolate);
    358       v8::HandleScope handle_scope(isolate);
    359 
    360 
    361       v8::Local<v8::Context> env = v8::Context::New(isolate);
    362       env->Enter();
    363 
    364       const char* c_source = "\"1234\".length";
    365       v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
    366       v8::Local<v8::Script> script = v8::Script::Compile(source);
    367       CHECK_EQ(4, script->Run()->Int32Value());
    368     }
    369     isolate->Dispose();
    370   }
    371 }
    372 
    373 
    374 UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
    375                              SerializeTwice) {
    376   if (!Snapshot::HaveASnapshotToStartFrom()) {
    377     v8::Isolate* isolate = Deserialize();
    378     {
    379       v8::Isolate::Scope isolate_scope(isolate);
    380       v8::HandleScope handle_scope(isolate);
    381 
    382       v8::Local<v8::Context> env = v8::Context::New(isolate);
    383       env->Enter();
    384 
    385       const char* c_source = "\"1234\".length";
    386       v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
    387       v8::Local<v8::Script> script = v8::Script::Compile(source);
    388       CHECK_EQ(4, script->Run()->Int32Value());
    389     }
    390     isolate->Dispose();
    391   }
    392 }
    393 
    394 
    395 UNINITIALIZED_TEST(PartialSerialization) {
    396   if (!Snapshot::HaveASnapshotToStartFrom()) {
    397     v8::Isolate::CreateParams params;
    398     params.enable_serializer = true;
    399     v8::Isolate* v8_isolate = v8::Isolate::New(params);
    400     Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
    401     v8_isolate->Enter();
    402     {
    403       Heap* heap = isolate->heap();
    404 
    405       v8::Persistent<v8::Context> env;
    406       {
    407         HandleScope scope(isolate);
    408         env.Reset(v8_isolate, v8::Context::New(v8_isolate));
    409       }
    410       DCHECK(!env.IsEmpty());
    411       {
    412         v8::HandleScope handle_scope(v8_isolate);
    413         v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
    414       }
    415       // Make sure all builtin scripts are cached.
    416       {
    417         HandleScope scope(isolate);
    418         for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
    419           isolate->bootstrapper()->NativesSourceLookup(i);
    420         }
    421       }
    422       heap->CollectAllGarbage(Heap::kNoGCFlags);
    423       heap->CollectAllGarbage(Heap::kNoGCFlags);
    424 
    425       Object* raw_foo;
    426       {
    427         v8::HandleScope handle_scope(v8_isolate);
    428         v8::Local<v8::String> foo = v8::String::NewFromUtf8(v8_isolate, "foo");
    429         DCHECK(!foo.IsEmpty());
    430         raw_foo = *(v8::Utils::OpenHandle(*foo));
    431       }
    432 
    433       int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
    434       Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
    435       SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
    436 
    437       {
    438         v8::HandleScope handle_scope(v8_isolate);
    439         v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
    440       }
    441       env.Reset();
    442 
    443       FileByteSink startup_sink(startup_name.start());
    444       StartupSerializer startup_serializer(isolate, &startup_sink);
    445       startup_serializer.SerializeStrongReferences();
    446 
    447       FileByteSink partial_sink(FLAG_testing_serialization_file);
    448       PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
    449       p_ser.Serialize(&raw_foo);
    450       startup_serializer.SerializeWeakReferences();
    451 
    452       partial_sink.WriteSpaceUsed(
    453           p_ser.CurrentAllocationAddress(NEW_SPACE),
    454           p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
    455           p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
    456           p_ser.CurrentAllocationAddress(CODE_SPACE),
    457           p_ser.CurrentAllocationAddress(MAP_SPACE),
    458           p_ser.CurrentAllocationAddress(CELL_SPACE),
    459           p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
    460 
    461       startup_sink.WriteSpaceUsed(
    462           startup_serializer.CurrentAllocationAddress(NEW_SPACE),
    463           startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
    464           startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
    465           startup_serializer.CurrentAllocationAddress(CODE_SPACE),
    466           startup_serializer.CurrentAllocationAddress(MAP_SPACE),
    467           startup_serializer.CurrentAllocationAddress(CELL_SPACE),
    468           startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
    469       startup_name.Dispose();
    470     }
    471     v8_isolate->Exit();
    472     v8_isolate->Dispose();
    473   }
    474 }
    475 
    476 
    477 UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
    478   if (!Snapshot::HaveASnapshotToStartFrom()) {
    479     int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
    480     Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
    481     SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
    482 
    483     v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
    484     CHECK(v8_isolate);
    485     startup_name.Dispose();
    486     {
    487       v8::Isolate::Scope isolate_scope(v8_isolate);
    488 
    489       const char* file_name = FLAG_testing_serialization_file;
    490 
    491       int snapshot_size = 0;
    492       byte* snapshot = ReadBytes(file_name, &snapshot_size);
    493 
    494       Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
    495       Object* root;
    496       {
    497         SnapshotByteSource source(snapshot, snapshot_size);
    498         Deserializer deserializer(&source);
    499         ReserveSpaceForSnapshot(&deserializer, file_name);
    500         deserializer.DeserializePartial(isolate, &root);
    501         CHECK(root->IsString());
    502       }
    503       HandleScope handle_scope(isolate);
    504       Handle<Object> root_handle(root, isolate);
    505 
    506 
    507       Object* root2;
    508       {
    509         SnapshotByteSource source(snapshot, snapshot_size);
    510         Deserializer deserializer(&source);
    511         ReserveSpaceForSnapshot(&deserializer, file_name);
    512         deserializer.DeserializePartial(isolate, &root2);
    513         CHECK(root2->IsString());
    514         CHECK(*root_handle == root2);
    515       }
    516     }
    517     v8_isolate->Dispose();
    518   }
    519 }
    520 
    521 
    522 UNINITIALIZED_TEST(ContextSerialization) {
    523   if (!Snapshot::HaveASnapshotToStartFrom()) {
    524     v8::Isolate::CreateParams params;
    525     params.enable_serializer = true;
    526     v8::Isolate* v8_isolate = v8::Isolate::New(params);
    527     Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
    528     Heap* heap = isolate->heap();
    529     {
    530       v8::Isolate::Scope isolate_scope(v8_isolate);
    531 
    532       v8::Persistent<v8::Context> env;
    533       {
    534         HandleScope scope(isolate);
    535         env.Reset(v8_isolate, v8::Context::New(v8_isolate));
    536       }
    537       DCHECK(!env.IsEmpty());
    538       {
    539         v8::HandleScope handle_scope(v8_isolate);
    540         v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
    541       }
    542       // Make sure all builtin scripts are cached.
    543       {
    544         HandleScope scope(isolate);
    545         for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
    546           isolate->bootstrapper()->NativesSourceLookup(i);
    547         }
    548       }
    549       // If we don't do this then we end up with a stray root pointing at the
    550       // context even after we have disposed of env.
    551       heap->CollectAllGarbage(Heap::kNoGCFlags);
    552 
    553       int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
    554       Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
    555       SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
    556 
    557       {
    558         v8::HandleScope handle_scope(v8_isolate);
    559         v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
    560       }
    561 
    562       i::Object* raw_context = *v8::Utils::OpenPersistent(env);
    563 
    564       env.Reset();
    565 
    566       FileByteSink startup_sink(startup_name.start());
    567       StartupSerializer startup_serializer(isolate, &startup_sink);
    568       startup_serializer.SerializeStrongReferences();
    569 
    570       FileByteSink partial_sink(FLAG_testing_serialization_file);
    571       PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
    572       p_ser.Serialize(&raw_context);
    573       startup_serializer.SerializeWeakReferences();
    574 
    575       partial_sink.WriteSpaceUsed(
    576           p_ser.CurrentAllocationAddress(NEW_SPACE),
    577           p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
    578           p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
    579           p_ser.CurrentAllocationAddress(CODE_SPACE),
    580           p_ser.CurrentAllocationAddress(MAP_SPACE),
    581           p_ser.CurrentAllocationAddress(CELL_SPACE),
    582           p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
    583 
    584       startup_sink.WriteSpaceUsed(
    585           startup_serializer.CurrentAllocationAddress(NEW_SPACE),
    586           startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
    587           startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
    588           startup_serializer.CurrentAllocationAddress(CODE_SPACE),
    589           startup_serializer.CurrentAllocationAddress(MAP_SPACE),
    590           startup_serializer.CurrentAllocationAddress(CELL_SPACE),
    591           startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
    592       startup_name.Dispose();
    593     }
    594     v8_isolate->Dispose();
    595   }
    596 }
    597 
    598 
    599 UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization, ContextSerialization) {
    600   if (!Snapshot::HaveASnapshotToStartFrom()) {
    601     int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
    602     Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
    603     SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
    604 
    605     v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
    606     CHECK(v8_isolate);
    607     startup_name.Dispose();
    608     {
    609       v8::Isolate::Scope isolate_scope(v8_isolate);
    610 
    611       const char* file_name = FLAG_testing_serialization_file;
    612 
    613       int snapshot_size = 0;
    614       byte* snapshot = ReadBytes(file_name, &snapshot_size);
    615 
    616       Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
    617       Object* root;
    618       {
    619         SnapshotByteSource source(snapshot, snapshot_size);
    620         Deserializer deserializer(&source);
    621         ReserveSpaceForSnapshot(&deserializer, file_name);
    622         deserializer.DeserializePartial(isolate, &root);
    623         CHECK(root->IsContext());
    624       }
    625       HandleScope handle_scope(isolate);
    626       Handle<Object> root_handle(root, isolate);
    627 
    628 
    629       Object* root2;
    630       {
    631         SnapshotByteSource source(snapshot, snapshot_size);
    632         Deserializer deserializer(&source);
    633         ReserveSpaceForSnapshot(&deserializer, file_name);
    634         deserializer.DeserializePartial(isolate, &root2);
    635         CHECK(root2->IsContext());
    636         CHECK(*root_handle != root2);
    637       }
    638     }
    639     v8_isolate->Dispose();
    640   }
    641 }
    642 
    643 
    644 TEST(TestThatAlwaysSucceeds) {
    645 }
    646 
    647 
    648 TEST(TestThatAlwaysFails) {
    649   bool ArtificialFailure = false;
    650   CHECK(ArtificialFailure);
    651 }
    652 
    653 
    654 DEPENDENT_TEST(DependentTestThatAlwaysFails, TestThatAlwaysSucceeds) {
    655   bool ArtificialFailure2 = false;
    656   CHECK(ArtificialFailure2);
    657 }
    658 
    659 
    660 int CountBuiltins() {
    661   // Check that we have not deserialized any additional builtin.
    662   HeapIterator iterator(CcTest::heap());
    663   DisallowHeapAllocation no_allocation;
    664   int counter = 0;
    665   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
    666     if (obj->IsCode() && Code::cast(obj)->kind() == Code::BUILTIN) counter++;
    667   }
    668   return counter;
    669 }
    670 
    671 
    672 TEST(SerializeToplevelOnePlusOne) {
    673   FLAG_serialize_toplevel = true;
    674   LocalContext context;
    675   Isolate* isolate = CcTest::i_isolate();
    676   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
    677 
    678   v8::HandleScope scope(CcTest::isolate());
    679 
    680   const char* source = "1 + 1";
    681 
    682   Handle<String> orig_source = isolate->factory()
    683                                    ->NewStringFromUtf8(CStrVector(source))
    684                                    .ToHandleChecked();
    685   Handle<String> copy_source = isolate->factory()
    686                                    ->NewStringFromUtf8(CStrVector(source))
    687                                    .ToHandleChecked();
    688   CHECK(!orig_source.is_identical_to(copy_source));
    689   CHECK(orig_source->Equals(*copy_source));
    690 
    691   ScriptData* cache = NULL;
    692 
    693   Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
    694       orig_source, Handle<String>(), 0, 0, false,
    695       Handle<Context>(isolate->native_context()), NULL, &cache,
    696       v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
    697 
    698   int builtins_count = CountBuiltins();
    699 
    700   Handle<SharedFunctionInfo> copy;
    701   {
    702     DisallowCompilation no_compile_expected(isolate);
    703     copy = Compiler::CompileScript(
    704         copy_source, Handle<String>(), 0, 0, false,
    705         Handle<Context>(isolate->native_context()), NULL, &cache,
    706         v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
    707   }
    708 
    709   CHECK_NE(*orig, *copy);
    710   CHECK(Script::cast(copy->script())->source() == *copy_source);
    711 
    712   Handle<JSFunction> copy_fun =
    713       isolate->factory()->NewFunctionFromSharedFunctionInfo(
    714           copy, isolate->native_context());
    715   Handle<JSObject> global(isolate->context()->global_object());
    716   Handle<Object> copy_result =
    717       Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
    718   CHECK_EQ(2, Handle<Smi>::cast(copy_result)->value());
    719 
    720   CHECK_EQ(builtins_count, CountBuiltins());
    721 
    722   delete cache;
    723 }
    724 
    725 
    726 TEST(SerializeToplevelInternalizedString) {
    727   FLAG_serialize_toplevel = true;
    728   LocalContext context;
    729   Isolate* isolate = CcTest::i_isolate();
    730   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
    731 
    732   v8::HandleScope scope(CcTest::isolate());
    733 
    734   const char* source = "'string1'";
    735 
    736   Handle<String> orig_source = isolate->factory()
    737                                    ->NewStringFromUtf8(CStrVector(source))
    738                                    .ToHandleChecked();
    739   Handle<String> copy_source = isolate->factory()
    740                                    ->NewStringFromUtf8(CStrVector(source))
    741                                    .ToHandleChecked();
    742   CHECK(!orig_source.is_identical_to(copy_source));
    743   CHECK(orig_source->Equals(*copy_source));
    744 
    745   Handle<JSObject> global(isolate->context()->global_object());
    746   ScriptData* cache = NULL;
    747 
    748   Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
    749       orig_source, Handle<String>(), 0, 0, false,
    750       Handle<Context>(isolate->native_context()), NULL, &cache,
    751       v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
    752   Handle<JSFunction> orig_fun =
    753       isolate->factory()->NewFunctionFromSharedFunctionInfo(
    754           orig, isolate->native_context());
    755   Handle<Object> orig_result =
    756       Execution::Call(isolate, orig_fun, global, 0, NULL).ToHandleChecked();
    757   CHECK(orig_result->IsInternalizedString());
    758 
    759   int builtins_count = CountBuiltins();
    760 
    761   Handle<SharedFunctionInfo> copy;
    762   {
    763     DisallowCompilation no_compile_expected(isolate);
    764     copy = Compiler::CompileScript(
    765         copy_source, Handle<String>(), 0, 0, false,
    766         Handle<Context>(isolate->native_context()), NULL, &cache,
    767         v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
    768   }
    769   CHECK_NE(*orig, *copy);
    770   CHECK(Script::cast(copy->script())->source() == *copy_source);
    771 
    772   Handle<JSFunction> copy_fun =
    773       isolate->factory()->NewFunctionFromSharedFunctionInfo(
    774           copy, isolate->native_context());
    775   CHECK_NE(*orig_fun, *copy_fun);
    776   Handle<Object> copy_result =
    777       Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
    778   CHECK(orig_result.is_identical_to(copy_result));
    779   Handle<String> expected =
    780       isolate->factory()->NewStringFromAsciiChecked("string1");
    781 
    782   CHECK(Handle<String>::cast(copy_result)->Equals(*expected));
    783   CHECK_EQ(builtins_count, CountBuiltins());
    784 
    785   delete cache;
    786 }
    787 
    788 
    789 TEST(SerializeToplevelIsolates) {
    790   FLAG_serialize_toplevel = true;
    791 
    792   const char* source = "function f() { return 'abc'; }; f() + 'def'";
    793   v8::ScriptCompiler::CachedData* cache;
    794 
    795   v8::Isolate* isolate1 = v8::Isolate::New();
    796   {
    797     v8::Isolate::Scope iscope(isolate1);
    798     v8::HandleScope scope(isolate1);
    799     v8::Local<v8::Context> context = v8::Context::New(isolate1);
    800     v8::Context::Scope context_scope(context);
    801 
    802     v8::Local<v8::String> source_str = v8_str(source);
    803     v8::ScriptOrigin origin(v8_str("test"));
    804     v8::ScriptCompiler::Source source(source_str, origin);
    805     v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
    806         isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
    807     const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
    808     // Persist cached data.
    809     uint8_t* buffer = NewArray<uint8_t>(data->length);
    810     MemCopy(buffer, data->data, data->length);
    811     cache = new v8::ScriptCompiler::CachedData(
    812         buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
    813 
    814     v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
    815     CHECK(result->ToString()->Equals(v8_str("abcdef")));
    816   }
    817   isolate1->Dispose();
    818 
    819   v8::Isolate* isolate2 = v8::Isolate::New();
    820   {
    821     v8::Isolate::Scope iscope(isolate2);
    822     v8::HandleScope scope(isolate2);
    823     v8::Local<v8::Context> context = v8::Context::New(isolate2);
    824     v8::Context::Scope context_scope(context);
    825 
    826     v8::Local<v8::String> source_str = v8_str(source);
    827     v8::ScriptOrigin origin(v8_str("test"));
    828     v8::ScriptCompiler::Source source(source_str, origin, cache);
    829     v8::Local<v8::UnboundScript> script;
    830     {
    831       DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
    832       script = v8::ScriptCompiler::CompileUnbound(
    833           isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache);
    834     }
    835     v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
    836     CHECK(result->ToString()->Equals(v8_str("abcdef")));
    837   }
    838   isolate2->Dispose();
    839 }
    840