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
46using namespace v8::internal;
47
48
49template <class T>
50static Address AddressOf(T id) {
51  return ExternalReference(id, CcTest::i_isolate()).address();
52}
53
54
55template <class T>
56static uint32_t Encode(const ExternalReferenceEncoder& encoder, T id) {
57  return encoder.Encode(AddressOf(id));
58}
59
60
61static int make_code(TypeCode type, int id) {
62  return static_cast<uint32_t>(type) << kReferenceTypeShift | id;
63}
64
65
66TEST(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
96TEST(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
117class 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
155void 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
179static 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
197static 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.
215UNINITIALIZED_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.
226UNINITIALIZED_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
241static 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
276v8::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
295static v8::Isolate* Deserialize() {
296  v8::Isolate* isolate = InitializeFromFile(FLAG_testing_serialization_file);
297  CHECK(isolate);
298  return isolate;
299}
300
301
302static 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
315UNINITIALIZED_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
335UNINITIALIZED_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
353UNINITIALIZED_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
374UNINITIALIZED_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
395UNINITIALIZED_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
477UNINITIALIZED_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
522UNINITIALIZED_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
599UNINITIALIZED_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
644TEST(TestThatAlwaysSucceeds) {
645}
646
647
648TEST(TestThatAlwaysFails) {
649  bool ArtificialFailure = false;
650  CHECK(ArtificialFailure);
651}
652
653
654DEPENDENT_TEST(DependentTestThatAlwaysFails, TestThatAlwaysSucceeds) {
655  bool ArtificialFailure2 = false;
656  CHECK(ArtificialFailure2);
657}
658
659
660int 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
672TEST(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
726TEST(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
789TEST(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