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>
AddressOf(T id)50 static Address AddressOf(T id) {
51   return ExternalReference(id, CcTest::i_isolate()).address();
52 }
53 
54 
55 template <class T>
Encode(const ExternalReferenceEncoder & encoder,T id)56 static uint32_t Encode(const ExternalReferenceEncoder& encoder, T id) {
57   return encoder.Encode(AddressOf(id));
58 }
59 
60 
make_code(TypeCode type,int id)61 static int make_code(TypeCode type, int id) {
62   return static_cast<uint32_t>(type) << kReferenceTypeShift | id;
63 }
64 
65 
TEST(ExternalReferenceEncoder)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 
TEST(ExternalReferenceDecoder)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:
FileByteSink(const char * snapshot_file)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   }
~FileByteSink()127   virtual ~FileByteSink() {
128     if (fp_ != NULL) {
129       fclose(fp_);
130     }
131   }
Put(byte b,const char * description)132   virtual void Put(byte b, const char* description) {
133     if (fp_ != NULL) {
134       fputc(b, fp_);
135     }
136   }
Position()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 
WriteSpaceUsed(int new_space_used,int pointer_space_used,int data_space_used,int code_space_used,int map_space_used,int cell_space_used,int property_cell_space_used)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 
WriteToFile(Isolate * isolate,const char * snapshot_file)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 
Serialize(v8::Isolate * isolate)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.
UNINITIALIZED_TEST(Serialize)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.
UNINITIALIZED_TEST(SerializeTwice)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 
ReserveSpaceForSnapshot(Deserializer * deserializer,const char * file_name)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 
InitializeFromFile(const char * snapshot_file)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 
Deserialize()295 static v8::Isolate* Deserialize() {
296   v8::Isolate* isolate = InitializeFromFile(FLAG_testing_serialization_file);
297   CHECK(isolate);
298   return isolate;
299 }
300 
301 
SanityCheck(v8::Isolate * v8_isolate)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 
UNINITIALIZED_DEPENDENT_TEST(Deserialize,Serialize)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 
UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerialization,SerializeTwice)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 
UNINITIALIZED_DEPENDENT_TEST(DeserializeAndRunScript2,Serialize)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 
UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,SerializeTwice)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 
UNINITIALIZED_TEST(PartialSerialization)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 
UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization,PartialSerialization)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 
UNINITIALIZED_TEST(ContextSerialization)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 
UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization,ContextSerialization)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 
TEST(TestThatAlwaysSucceeds)644 TEST(TestThatAlwaysSucceeds) {
645 }
646 
647 
TEST(TestThatAlwaysFails)648 TEST(TestThatAlwaysFails) {
649   bool ArtificialFailure = false;
650   CHECK(ArtificialFailure);
651 }
652 
653 
DEPENDENT_TEST(DependentTestThatAlwaysFails,TestThatAlwaysSucceeds)654 DEPENDENT_TEST(DependentTestThatAlwaysFails, TestThatAlwaysSucceeds) {
655   bool ArtificialFailure2 = false;
656   CHECK(ArtificialFailure2);
657 }
658 
659 
CountBuiltins()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 
TEST(SerializeToplevelOnePlusOne)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 
TEST(SerializeToplevelInternalizedString)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 
TEST(SerializeToplevelIsolates)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