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 "v8.h"
33
34#include "debug.h"
35#include "ic-inl.h"
36#include "runtime.h"
37#include "serialize.h"
38#include "scopeinfo.h"
39#include "snapshot.h"
40#include "cctest.h"
41#include "spaces.h"
42#include "objects.h"
43#include "natives.h"
44#include "bootstrapper.h"
45
46using namespace v8::internal;
47
48static const unsigned kCounters = 256;
49static int local_counters[kCounters];
50static const char* local_counter_names[kCounters];
51
52
53static unsigned CounterHash(const char* s) {
54  unsigned hash = 0;
55  while (*++s) {
56    hash |= hash << 5;
57    hash += *s;
58  }
59  return hash;
60}
61
62
63// Callback receiver to track counters in test.
64static int* counter_function(const char* name) {
65  unsigned hash = CounterHash(name) % kCounters;
66  unsigned original_hash = hash;
67  USE(original_hash);
68  while (true) {
69    if (local_counter_names[hash] == name) {
70      return &local_counters[hash];
71    }
72    if (local_counter_names[hash] == 0) {
73      local_counter_names[hash] = name;
74      return &local_counters[hash];
75    }
76    if (strcmp(local_counter_names[hash], name) == 0) {
77      return &local_counters[hash];
78    }
79    hash = (hash + 1) % kCounters;
80    ASSERT(hash != original_hash);  // Hash table has been filled up.
81  }
82}
83
84
85template <class T>
86static Address AddressOf(T id) {
87  return ExternalReference(id, CcTest::i_isolate()).address();
88}
89
90
91template <class T>
92static uint32_t Encode(const ExternalReferenceEncoder& encoder, T id) {
93  return encoder.Encode(AddressOf(id));
94}
95
96
97static int make_code(TypeCode type, int id) {
98  return static_cast<uint32_t>(type) << kReferenceTypeShift | id;
99}
100
101
102TEST(ExternalReferenceEncoder) {
103  Isolate* isolate = CcTest::i_isolate();
104  isolate->stats_table()->SetCounterFunction(counter_function);
105  v8::V8::Initialize();
106
107  ExternalReferenceEncoder encoder(isolate);
108  CHECK_EQ(make_code(BUILTIN, Builtins::kArrayCode),
109           Encode(encoder, Builtins::kArrayCode));
110  CHECK_EQ(make_code(v8::internal::RUNTIME_FUNCTION, Runtime::kAbort),
111           Encode(encoder, Runtime::kAbort));
112  ExternalReference total_compile_size =
113      ExternalReference(isolate->counters()->total_compile_size());
114  CHECK_EQ(make_code(STATS_COUNTER, Counters::k_total_compile_size),
115           encoder.Encode(total_compile_size.address()));
116  ExternalReference stack_limit_address =
117      ExternalReference::address_of_stack_limit(isolate);
118  CHECK_EQ(make_code(UNCLASSIFIED, 4),
119           encoder.Encode(stack_limit_address.address()));
120  ExternalReference real_stack_limit_address =
121      ExternalReference::address_of_real_stack_limit(isolate);
122  CHECK_EQ(make_code(UNCLASSIFIED, 5),
123           encoder.Encode(real_stack_limit_address.address()));
124#ifdef ENABLE_DEBUGGER_SUPPORT
125  CHECK_EQ(make_code(UNCLASSIFIED, 16),
126           encoder.Encode(ExternalReference::debug_break(isolate).address()));
127#endif  // ENABLE_DEBUGGER_SUPPORT
128  CHECK_EQ(make_code(UNCLASSIFIED, 10),
129           encoder.Encode(
130               ExternalReference::new_space_start(isolate).address()));
131  CHECK_EQ(make_code(UNCLASSIFIED, 3),
132           encoder.Encode(
133               ExternalReference::roots_array_start(isolate).address()));
134  CHECK_EQ(make_code(UNCLASSIFIED, 52),
135           encoder.Encode(ExternalReference::cpu_features().address()));
136}
137
138
139TEST(ExternalReferenceDecoder) {
140  Isolate* isolate = CcTest::i_isolate();
141  isolate->stats_table()->SetCounterFunction(counter_function);
142  v8::V8::Initialize();
143
144  ExternalReferenceDecoder decoder(isolate);
145  CHECK_EQ(AddressOf(Builtins::kArrayCode),
146           decoder.Decode(make_code(BUILTIN, Builtins::kArrayCode)));
147  CHECK_EQ(AddressOf(Runtime::kAbort),
148           decoder.Decode(make_code(v8::internal::RUNTIME_FUNCTION,
149                                    Runtime::kAbort)));
150  ExternalReference total_compile_size =
151      ExternalReference(isolate->counters()->total_compile_size());
152  CHECK_EQ(total_compile_size.address(),
153           decoder.Decode(
154               make_code(STATS_COUNTER,
155                         Counters::k_total_compile_size)));
156  CHECK_EQ(ExternalReference::address_of_stack_limit(isolate).address(),
157           decoder.Decode(make_code(UNCLASSIFIED, 4)));
158  CHECK_EQ(ExternalReference::address_of_real_stack_limit(isolate).address(),
159           decoder.Decode(make_code(UNCLASSIFIED, 5)));
160#ifdef ENABLE_DEBUGGER_SUPPORT
161  CHECK_EQ(ExternalReference::debug_break(isolate).address(),
162           decoder.Decode(make_code(UNCLASSIFIED, 16)));
163#endif  // ENABLE_DEBUGGER_SUPPORT
164  CHECK_EQ(ExternalReference::new_space_start(isolate).address(),
165           decoder.Decode(make_code(UNCLASSIFIED, 10)));
166}
167
168
169class FileByteSink : public SnapshotByteSink {
170 public:
171  explicit FileByteSink(const char* snapshot_file) {
172    fp_ = OS::FOpen(snapshot_file, "wb");
173    file_name_ = snapshot_file;
174    if (fp_ == NULL) {
175      PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file);
176      exit(1);
177    }
178  }
179  virtual ~FileByteSink() {
180    if (fp_ != NULL) {
181      fclose(fp_);
182    }
183  }
184  virtual void Put(int byte, const char* description) {
185    if (fp_ != NULL) {
186      fputc(byte, fp_);
187    }
188  }
189  virtual int Position() {
190    return ftell(fp_);
191  }
192  void WriteSpaceUsed(
193      int new_space_used,
194      int pointer_space_used,
195      int data_space_used,
196      int code_space_used,
197      int map_space_used,
198      int cell_space_used,
199      int property_cell_space_used);
200
201 private:
202  FILE* fp_;
203  const char* file_name_;
204};
205
206
207void FileByteSink::WriteSpaceUsed(
208      int new_space_used,
209      int pointer_space_used,
210      int data_space_used,
211      int code_space_used,
212      int map_space_used,
213      int cell_space_used,
214      int property_cell_space_used) {
215  int file_name_length = StrLength(file_name_) + 10;
216  Vector<char> name = Vector<char>::New(file_name_length + 1);
217  OS::SNPrintF(name, "%s.size", file_name_);
218  FILE* fp = OS::FOpen(name.start(), "w");
219  name.Dispose();
220  fprintf(fp, "new %d\n", new_space_used);
221  fprintf(fp, "pointer %d\n", pointer_space_used);
222  fprintf(fp, "data %d\n", data_space_used);
223  fprintf(fp, "code %d\n", code_space_used);
224  fprintf(fp, "map %d\n", map_space_used);
225  fprintf(fp, "cell %d\n", cell_space_used);
226  fprintf(fp, "property cell %d\n", property_cell_space_used);
227  fclose(fp);
228}
229
230
231static bool WriteToFile(Isolate* isolate, const char* snapshot_file) {
232  FileByteSink file(snapshot_file);
233  StartupSerializer ser(isolate, &file);
234  ser.Serialize();
235
236  file.WriteSpaceUsed(
237      ser.CurrentAllocationAddress(NEW_SPACE),
238      ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
239      ser.CurrentAllocationAddress(OLD_DATA_SPACE),
240      ser.CurrentAllocationAddress(CODE_SPACE),
241      ser.CurrentAllocationAddress(MAP_SPACE),
242      ser.CurrentAllocationAddress(CELL_SPACE),
243      ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
244
245  return true;
246}
247
248
249static void Serialize() {
250  // We have to create one context.  One reason for this is so that the builtins
251  // can be loaded from v8natives.js and their addresses can be processed.  This
252  // will clear the pending fixups array, which would otherwise contain GC roots
253  // that would confuse the serialization/deserialization process.
254  v8::Isolate* isolate = CcTest::isolate();
255  {
256    v8::HandleScope scope(isolate);
257    v8::Context::New(isolate);
258  }
259
260  Isolate* internal_isolate = CcTest::i_isolate();
261  internal_isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "serialize");
262  WriteToFile(internal_isolate, FLAG_testing_serialization_file);
263}
264
265
266// Test that the whole heap can be serialized.
267TEST(Serialize) {
268  if (!Snapshot::HaveASnapshotToStartFrom()) {
269    Serializer::Enable(CcTest::i_isolate());
270    v8::V8::Initialize();
271    Serialize();
272  }
273}
274
275
276// Test that heap serialization is non-destructive.
277TEST(SerializeTwice) {
278  if (!Snapshot::HaveASnapshotToStartFrom()) {
279    Serializer::Enable(CcTest::i_isolate());
280    v8::V8::Initialize();
281    Serialize();
282    Serialize();
283  }
284}
285
286
287//----------------------------------------------------------------------------
288// Tests that the heap can be deserialized.
289
290static void Deserialize() {
291  CHECK(Snapshot::Initialize(FLAG_testing_serialization_file));
292}
293
294
295static void SanityCheck() {
296  Isolate* isolate = CcTest::i_isolate();
297  v8::HandleScope scope(CcTest::isolate());
298#ifdef VERIFY_HEAP
299  CcTest::heap()->Verify();
300#endif
301  CHECK(isolate->global_object()->IsJSObject());
302  CHECK(isolate->native_context()->IsContext());
303  CHECK(CcTest::heap()->string_table()->IsStringTable());
304  CHECK(!isolate->factory()->InternalizeOneByteString(
305      STATIC_ASCII_VECTOR("Empty"))->IsFailure());
306}
307
308
309DEPENDENT_TEST(Deserialize, Serialize) {
310  // The serialize-deserialize tests only work if the VM is built without
311  // serialization.  That doesn't matter.  We don't need to be able to
312  // serialize a snapshot in a VM that is booted from a snapshot.
313  if (!Snapshot::HaveASnapshotToStartFrom()) {
314    v8::Isolate* isolate = CcTest::isolate();
315    v8::HandleScope scope(isolate);
316    Deserialize();
317
318    v8::Local<v8::Context> env = v8::Context::New(isolate);
319    env->Enter();
320
321    SanityCheck();
322  }
323}
324
325
326DEPENDENT_TEST(DeserializeFromSecondSerialization, SerializeTwice) {
327  if (!Snapshot::HaveASnapshotToStartFrom()) {
328    v8::Isolate* isolate = CcTest::isolate();
329    v8::HandleScope scope(isolate);
330    Deserialize();
331
332    v8::Local<v8::Context> env = v8::Context::New(isolate);
333    env->Enter();
334
335    SanityCheck();
336  }
337}
338
339
340DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
341  if (!Snapshot::HaveASnapshotToStartFrom()) {
342    v8::Isolate* isolate = CcTest::isolate();
343    v8::HandleScope scope(isolate);
344    Deserialize();
345
346    v8::Local<v8::Context> env = v8::Context::New(isolate);
347    env->Enter();
348
349    const char* c_source = "\"1234\".length";
350    v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
351    v8::Local<v8::Script> script = v8::Script::Compile(source);
352    CHECK_EQ(4, script->Run()->Int32Value());
353  }
354}
355
356
357DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
358               SerializeTwice) {
359  if (!Snapshot::HaveASnapshotToStartFrom()) {
360    v8::Isolate* isolate = CcTest::isolate();
361    v8::HandleScope scope(isolate);
362    Deserialize();
363
364    v8::Local<v8::Context> env = v8::Context::New(isolate);
365    env->Enter();
366
367    const char* c_source = "\"1234\".length";
368    v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
369    v8::Local<v8::Script> script = v8::Script::Compile(source);
370    CHECK_EQ(4, script->Run()->Int32Value());
371  }
372}
373
374
375TEST(PartialSerialization) {
376  if (!Snapshot::HaveASnapshotToStartFrom()) {
377    Isolate* isolate = CcTest::i_isolate();
378    Serializer::Enable(isolate);
379    v8::V8::Initialize();
380    v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
381    Heap* heap = isolate->heap();
382
383    v8::Persistent<v8::Context> env;
384    {
385      HandleScope scope(isolate);
386      env.Reset(v8_isolate, v8::Context::New(v8_isolate));
387    }
388    ASSERT(!env.IsEmpty());
389    {
390      v8::HandleScope handle_scope(v8_isolate);
391      v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
392    }
393    // Make sure all builtin scripts are cached.
394    { HandleScope scope(isolate);
395      for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
396        isolate->bootstrapper()->NativesSourceLookup(i);
397      }
398    }
399    heap->CollectAllGarbage(Heap::kNoGCFlags);
400    heap->CollectAllGarbage(Heap::kNoGCFlags);
401
402    Object* raw_foo;
403    {
404      v8::HandleScope handle_scope(v8_isolate);
405      v8::Local<v8::String> foo = v8::String::NewFromUtf8(v8_isolate, "foo");
406      ASSERT(!foo.IsEmpty());
407      raw_foo = *(v8::Utils::OpenHandle(*foo));
408    }
409
410    int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
411    Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
412    OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
413
414    {
415      v8::HandleScope handle_scope(v8_isolate);
416      v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
417    }
418    env.Reset();
419
420    FileByteSink startup_sink(startup_name.start());
421    StartupSerializer startup_serializer(isolate, &startup_sink);
422    startup_serializer.SerializeStrongReferences();
423
424    FileByteSink partial_sink(FLAG_testing_serialization_file);
425    PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
426    p_ser.Serialize(&raw_foo);
427    startup_serializer.SerializeWeakReferences();
428
429    partial_sink.WriteSpaceUsed(
430        p_ser.CurrentAllocationAddress(NEW_SPACE),
431        p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
432        p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
433        p_ser.CurrentAllocationAddress(CODE_SPACE),
434        p_ser.CurrentAllocationAddress(MAP_SPACE),
435        p_ser.CurrentAllocationAddress(CELL_SPACE),
436        p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
437
438    startup_sink.WriteSpaceUsed(
439        startup_serializer.CurrentAllocationAddress(NEW_SPACE),
440        startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
441        startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
442        startup_serializer.CurrentAllocationAddress(CODE_SPACE),
443        startup_serializer.CurrentAllocationAddress(MAP_SPACE),
444        startup_serializer.CurrentAllocationAddress(CELL_SPACE),
445        startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
446    startup_name.Dispose();
447  }
448}
449
450
451static void ReserveSpaceForSnapshot(Deserializer* deserializer,
452                                    const char* file_name) {
453  int file_name_length = StrLength(file_name) + 10;
454  Vector<char> name = Vector<char>::New(file_name_length + 1);
455  OS::SNPrintF(name, "%s.size", file_name);
456  FILE* fp = OS::FOpen(name.start(), "r");
457  name.Dispose();
458  int new_size, pointer_size, data_size, code_size, map_size, cell_size,
459      property_cell_size;
460#ifdef _MSC_VER
461  // Avoid warning about unsafe fscanf from MSVC.
462  // Please note that this is only fine if %c and %s are not being used.
463#define fscanf fscanf_s
464#endif
465  CHECK_EQ(1, fscanf(fp, "new %d\n", &new_size));
466  CHECK_EQ(1, fscanf(fp, "pointer %d\n", &pointer_size));
467  CHECK_EQ(1, fscanf(fp, "data %d\n", &data_size));
468  CHECK_EQ(1, fscanf(fp, "code %d\n", &code_size));
469  CHECK_EQ(1, fscanf(fp, "map %d\n", &map_size));
470  CHECK_EQ(1, fscanf(fp, "cell %d\n", &cell_size));
471  CHECK_EQ(1, fscanf(fp, "property cell %d\n", &property_cell_size));
472#ifdef _MSC_VER
473#undef fscanf
474#endif
475  fclose(fp);
476  deserializer->set_reservation(NEW_SPACE, new_size);
477  deserializer->set_reservation(OLD_POINTER_SPACE, pointer_size);
478  deserializer->set_reservation(OLD_DATA_SPACE, data_size);
479  deserializer->set_reservation(CODE_SPACE, code_size);
480  deserializer->set_reservation(MAP_SPACE, map_size);
481  deserializer->set_reservation(CELL_SPACE, cell_size);
482  deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_size);
483}
484
485
486DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
487  if (!Snapshot::IsEnabled()) {
488    int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
489    Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
490    OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
491
492    CHECK(Snapshot::Initialize(startup_name.start()));
493    startup_name.Dispose();
494
495    const char* file_name = FLAG_testing_serialization_file;
496
497    int snapshot_size = 0;
498    byte* snapshot = ReadBytes(file_name, &snapshot_size);
499
500    Isolate* isolate = CcTest::i_isolate();
501    Object* root;
502    {
503      SnapshotByteSource source(snapshot, snapshot_size);
504      Deserializer deserializer(&source);
505      ReserveSpaceForSnapshot(&deserializer, file_name);
506      deserializer.DeserializePartial(isolate, &root);
507      CHECK(root->IsString());
508    }
509    HandleScope handle_scope(isolate);
510    Handle<Object> root_handle(root, isolate);
511
512
513    Object* root2;
514    {
515      SnapshotByteSource source(snapshot, snapshot_size);
516      Deserializer deserializer(&source);
517      ReserveSpaceForSnapshot(&deserializer, file_name);
518      deserializer.DeserializePartial(isolate, &root2);
519      CHECK(root2->IsString());
520      CHECK(*root_handle == root2);
521    }
522  }
523}
524
525
526TEST(ContextSerialization) {
527  if (!Snapshot::HaveASnapshotToStartFrom()) {
528    Isolate* isolate = CcTest::i_isolate();
529    Serializer::Enable(isolate);
530    v8::V8::Initialize();
531    v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
532    Heap* heap = isolate->heap();
533
534    v8::Persistent<v8::Context> env;
535    {
536      HandleScope scope(isolate);
537      env.Reset(v8_isolate, v8::Context::New(v8_isolate));
538    }
539    ASSERT(!env.IsEmpty());
540    {
541      v8::HandleScope handle_scope(v8_isolate);
542      v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
543    }
544    // Make sure all builtin scripts are cached.
545    { HandleScope scope(isolate);
546      for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
547        isolate->bootstrapper()->NativesSourceLookup(i);
548      }
549    }
550    // If we don't do this then we end up with a stray root pointing at the
551    // context even after we have disposed of env.
552    heap->CollectAllGarbage(Heap::kNoGCFlags);
553
554    int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
555    Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
556    OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
557
558    {
559      v8::HandleScope handle_scope(v8_isolate);
560      v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
561    }
562
563    i::Object* raw_context = *v8::Utils::OpenPersistent(env);
564
565    env.Reset();
566
567    FileByteSink startup_sink(startup_name.start());
568    StartupSerializer startup_serializer(isolate, &startup_sink);
569    startup_serializer.SerializeStrongReferences();
570
571    FileByteSink partial_sink(FLAG_testing_serialization_file);
572    PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
573    p_ser.Serialize(&raw_context);
574    startup_serializer.SerializeWeakReferences();
575
576    partial_sink.WriteSpaceUsed(
577        p_ser.CurrentAllocationAddress(NEW_SPACE),
578        p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
579        p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
580        p_ser.CurrentAllocationAddress(CODE_SPACE),
581        p_ser.CurrentAllocationAddress(MAP_SPACE),
582        p_ser.CurrentAllocationAddress(CELL_SPACE),
583        p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
584
585    startup_sink.WriteSpaceUsed(
586        startup_serializer.CurrentAllocationAddress(NEW_SPACE),
587        startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
588        startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
589        startup_serializer.CurrentAllocationAddress(CODE_SPACE),
590        startup_serializer.CurrentAllocationAddress(MAP_SPACE),
591        startup_serializer.CurrentAllocationAddress(CELL_SPACE),
592        startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
593    startup_name.Dispose();
594  }
595}
596
597
598DEPENDENT_TEST(ContextDeserialization, ContextSerialization) {
599  if (!Snapshot::HaveASnapshotToStartFrom()) {
600    int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
601    Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
602    OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
603
604    CHECK(Snapshot::Initialize(startup_name.start()));
605    startup_name.Dispose();
606
607    const char* file_name = FLAG_testing_serialization_file;
608
609    int snapshot_size = 0;
610    byte* snapshot = ReadBytes(file_name, &snapshot_size);
611
612    Isolate* isolate = CcTest::i_isolate();
613    Object* root;
614    {
615      SnapshotByteSource source(snapshot, snapshot_size);
616      Deserializer deserializer(&source);
617      ReserveSpaceForSnapshot(&deserializer, file_name);
618      deserializer.DeserializePartial(isolate, &root);
619      CHECK(root->IsContext());
620    }
621    HandleScope handle_scope(isolate);
622    Handle<Object> root_handle(root, isolate);
623
624
625    Object* root2;
626    {
627      SnapshotByteSource source(snapshot, snapshot_size);
628      Deserializer deserializer(&source);
629      ReserveSpaceForSnapshot(&deserializer, file_name);
630      deserializer.DeserializePartial(isolate, &root2);
631      CHECK(root2->IsContext());
632      CHECK(*root_handle != root2);
633    }
634  }
635}
636
637
638TEST(TestThatAlwaysSucceeds) {
639}
640
641
642TEST(TestThatAlwaysFails) {
643  bool ArtificialFailure = false;
644  CHECK(ArtificialFailure);
645}
646
647
648DEPENDENT_TEST(DependentTestThatAlwaysFails, TestThatAlwaysSucceeds) {
649  bool ArtificialFailure2 = false;
650  CHECK(ArtificialFailure2);
651}
652