55eac60f37a27b27d9e923d2820f6dc2bf149352
[platform/upstream/nodejs.git] / deps / v8 / test / cctest / test-serialize.cc
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/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 uint32_t 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, 33),
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 void WritePayload(const Vector<const byte>& payload, const char* file_name) {
118   FILE* file = v8::base::OS::FOpen(file_name, "wb");
119   if (file == NULL) {
120     PrintF("Unable to write to snapshot file \"%s\"\n", file_name);
121     exit(1);
122   }
123   size_t written = fwrite(payload.begin(), 1, payload.length(), file);
124   if (written != static_cast<size_t>(payload.length())) {
125     i::PrintF("Writing snapshot file failed.. Aborting.\n");
126     exit(1);
127   }
128   fclose(file);
129 }
130
131
132 static bool WriteToFile(Isolate* isolate, const char* snapshot_file) {
133   SnapshotByteSink sink;
134   StartupSerializer ser(isolate, &sink);
135   ser.Serialize();
136   SnapshotData snapshot_data(ser);
137   WritePayload(snapshot_data.RawData(), snapshot_file);
138   return true;
139 }
140
141
142 static void Serialize(v8::Isolate* isolate) {
143   // We have to create one context.  One reason for this is so that the builtins
144   // can be loaded from v8natives.js and their addresses can be processed.  This
145   // will clear the pending fixups array, which would otherwise contain GC roots
146   // that would confuse the serialization/deserialization process.
147   v8::Isolate::Scope isolate_scope(isolate);
148   {
149     v8::HandleScope scope(isolate);
150     v8::Context::New(isolate);
151   }
152
153   Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
154   internal_isolate->heap()->CollectAllAvailableGarbage("serialize");
155   WriteToFile(internal_isolate, FLAG_testing_serialization_file);
156 }
157
158
159 Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head,
160                                       Vector<const uint8_t> body,
161                                       Vector<const uint8_t> tail, int repeats) {
162   int source_length = head.length() + body.length() * repeats + tail.length();
163   uint8_t* source = NewArray<uint8_t>(static_cast<size_t>(source_length));
164   CopyChars(source, head.start(), head.length());
165   for (int i = 0; i < repeats; i++) {
166     CopyChars(source + head.length() + i * body.length(), body.start(),
167               body.length());
168   }
169   CopyChars(source + head.length() + repeats * body.length(), tail.start(),
170             tail.length());
171   return Vector<const uint8_t>(const_cast<const uint8_t*>(source),
172                                source_length);
173 }
174
175
176 // Test that the whole heap can be serialized.
177 UNINITIALIZED_TEST(Serialize) {
178   if (!Snapshot::HaveASnapshotToStartFrom()) {
179     v8::Isolate::CreateParams params;
180     params.enable_serializer = true;
181     v8::Isolate* isolate = v8::Isolate::New(params);
182     Serialize(isolate);
183   }
184 }
185
186
187 // Test that heap serialization is non-destructive.
188 UNINITIALIZED_TEST(SerializeTwice) {
189   if (!Snapshot::HaveASnapshotToStartFrom()) {
190     v8::Isolate::CreateParams params;
191     params.enable_serializer = true;
192     v8::Isolate* isolate = v8::Isolate::New(params);
193     Serialize(isolate);
194     Serialize(isolate);
195   }
196 }
197
198
199 //----------------------------------------------------------------------------
200 // Tests that the heap can be deserialized.
201
202 v8::Isolate* InitializeFromFile(const char* snapshot_file) {
203   int len;
204   byte* str = ReadBytes(snapshot_file, &len);
205   if (!str) return NULL;
206   v8::Isolate* v8_isolate = NULL;
207   {
208     SnapshotData snapshot_data(Vector<const byte>(str, len));
209     Deserializer deserializer(&snapshot_data);
210     Isolate* isolate = Isolate::NewForTesting();
211     v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
212     v8::Isolate::Scope isolate_scope(v8_isolate);
213     isolate->Init(&deserializer);
214   }
215   DeleteArray(str);
216   return v8_isolate;
217 }
218
219
220 static v8::Isolate* Deserialize() {
221   v8::Isolate* isolate = InitializeFromFile(FLAG_testing_serialization_file);
222   CHECK(isolate);
223   return isolate;
224 }
225
226
227 static void SanityCheck(v8::Isolate* v8_isolate) {
228   Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
229   v8::HandleScope scope(v8_isolate);
230 #ifdef VERIFY_HEAP
231   isolate->heap()->Verify();
232 #endif
233   CHECK(isolate->global_object()->IsJSObject());
234   CHECK(isolate->native_context()->IsContext());
235   CHECK(isolate->heap()->string_table()->IsStringTable());
236   isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("Empty"));
237 }
238
239
240 UNINITIALIZED_DEPENDENT_TEST(Deserialize, Serialize) {
241   // The serialize-deserialize tests only work if the VM is built without
242   // serialization.  That doesn't matter.  We don't need to be able to
243   // serialize a snapshot in a VM that is booted from a snapshot.
244   if (!Snapshot::HaveASnapshotToStartFrom()) {
245     v8::Isolate* isolate = Deserialize();
246     {
247       v8::HandleScope handle_scope(isolate);
248       v8::Isolate::Scope isolate_scope(isolate);
249
250       v8::Local<v8::Context> env = v8::Context::New(isolate);
251       env->Enter();
252
253       SanityCheck(isolate);
254     }
255     isolate->Dispose();
256   }
257 }
258
259
260 UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerialization,
261                              SerializeTwice) {
262   if (!Snapshot::HaveASnapshotToStartFrom()) {
263     v8::Isolate* isolate = Deserialize();
264     {
265       v8::Isolate::Scope isolate_scope(isolate);
266       v8::HandleScope handle_scope(isolate);
267
268       v8::Local<v8::Context> env = v8::Context::New(isolate);
269       env->Enter();
270
271       SanityCheck(isolate);
272     }
273     isolate->Dispose();
274   }
275 }
276
277
278 UNINITIALIZED_DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
279   if (!Snapshot::HaveASnapshotToStartFrom()) {
280     v8::Isolate* isolate = Deserialize();
281     {
282       v8::Isolate::Scope isolate_scope(isolate);
283       v8::HandleScope handle_scope(isolate);
284
285
286       v8::Local<v8::Context> env = v8::Context::New(isolate);
287       env->Enter();
288
289       const char* c_source = "\"1234\".length";
290       v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
291       v8::Local<v8::Script> script = v8::Script::Compile(source);
292       CHECK_EQ(4, script->Run()->Int32Value());
293     }
294     isolate->Dispose();
295   }
296 }
297
298
299 UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
300                              SerializeTwice) {
301   if (!Snapshot::HaveASnapshotToStartFrom()) {
302     v8::Isolate* isolate = Deserialize();
303     {
304       v8::Isolate::Scope isolate_scope(isolate);
305       v8::HandleScope handle_scope(isolate);
306
307       v8::Local<v8::Context> env = v8::Context::New(isolate);
308       env->Enter();
309
310       const char* c_source = "\"1234\".length";
311       v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
312       v8::Local<v8::Script> script = v8::Script::Compile(source);
313       CHECK_EQ(4, script->Run()->Int32Value());
314     }
315     isolate->Dispose();
316   }
317 }
318
319
320 UNINITIALIZED_TEST(PartialSerialization) {
321   if (!Snapshot::HaveASnapshotToStartFrom()) {
322     v8::Isolate::CreateParams params;
323     params.enable_serializer = true;
324     v8::Isolate* v8_isolate = v8::Isolate::New(params);
325     Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
326     v8_isolate->Enter();
327     {
328       Heap* heap = isolate->heap();
329
330       v8::Persistent<v8::Context> env;
331       {
332         HandleScope scope(isolate);
333         env.Reset(v8_isolate, v8::Context::New(v8_isolate));
334       }
335       DCHECK(!env.IsEmpty());
336       {
337         v8::HandleScope handle_scope(v8_isolate);
338         v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
339       }
340       // Make sure all builtin scripts are cached.
341       {
342         HandleScope scope(isolate);
343         for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
344           isolate->bootstrapper()->NativesSourceLookup(i);
345         }
346       }
347       heap->CollectAllGarbage(Heap::kNoGCFlags);
348       heap->CollectAllGarbage(Heap::kNoGCFlags);
349
350       Object* raw_foo;
351       {
352         v8::HandleScope handle_scope(v8_isolate);
353         v8::Local<v8::String> foo = v8::String::NewFromUtf8(v8_isolate, "foo");
354         DCHECK(!foo.IsEmpty());
355         raw_foo = *(v8::Utils::OpenHandle(*foo));
356       }
357
358       int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
359       Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
360       SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
361
362       {
363         v8::HandleScope handle_scope(v8_isolate);
364         v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
365       }
366       env.Reset();
367
368       SnapshotByteSink startup_sink;
369       StartupSerializer startup_serializer(isolate, &startup_sink);
370       startup_serializer.SerializeStrongReferences();
371
372       SnapshotByteSink partial_sink;
373       PartialSerializer partial_serializer(isolate, &startup_serializer,
374                                            &partial_sink);
375       partial_serializer.Serialize(&raw_foo);
376
377       startup_serializer.SerializeWeakReferences();
378
379       SnapshotData startup_snapshot(startup_serializer);
380       SnapshotData partial_snapshot(partial_serializer);
381
382       WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
383       WritePayload(startup_snapshot.RawData(), startup_name.start());
384
385       startup_name.Dispose();
386     }
387     v8_isolate->Exit();
388     v8_isolate->Dispose();
389   }
390 }
391
392
393 UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
394   if (!Snapshot::HaveASnapshotToStartFrom()) {
395     int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
396     Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
397     SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
398
399     v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
400     CHECK(v8_isolate);
401     startup_name.Dispose();
402     {
403       v8::Isolate::Scope isolate_scope(v8_isolate);
404
405       const char* file_name = FLAG_testing_serialization_file;
406
407       int snapshot_size = 0;
408       byte* snapshot = ReadBytes(file_name, &snapshot_size);
409
410       Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
411       HandleScope handle_scope(isolate);
412       Handle<Object> root;
413       Handle<FixedArray> outdated_contexts;
414       // Intentionally empty handle. The deserializer should not come across
415       // any references to the global proxy in this test.
416       Handle<JSGlobalProxy> global_proxy = Handle<JSGlobalProxy>::null();
417       {
418         SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
419         Deserializer deserializer(&snapshot_data);
420         root = deserializer.DeserializePartial(isolate, global_proxy,
421                                                &outdated_contexts)
422                    .ToHandleChecked();
423         CHECK_EQ(0, outdated_contexts->length());
424         CHECK(root->IsString());
425       }
426
427       Handle<Object> root2;
428       {
429         SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
430         Deserializer deserializer(&snapshot_data);
431         root2 = deserializer.DeserializePartial(isolate, global_proxy,
432                                                 &outdated_contexts)
433                     .ToHandleChecked();
434         CHECK(root2->IsString());
435         CHECK(root.is_identical_to(root2));
436       }
437     }
438     v8_isolate->Dispose();
439   }
440 }
441
442
443 UNINITIALIZED_TEST(ContextSerialization) {
444   if (!Snapshot::HaveASnapshotToStartFrom()) {
445     v8::Isolate::CreateParams params;
446     params.enable_serializer = true;
447     v8::Isolate* v8_isolate = v8::Isolate::New(params);
448     Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
449     Heap* heap = isolate->heap();
450     {
451       v8::Isolate::Scope isolate_scope(v8_isolate);
452
453       v8::Persistent<v8::Context> env;
454       {
455         HandleScope scope(isolate);
456         env.Reset(v8_isolate, v8::Context::New(v8_isolate));
457       }
458       DCHECK(!env.IsEmpty());
459       {
460         v8::HandleScope handle_scope(v8_isolate);
461         v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
462       }
463       // Make sure all builtin scripts are cached.
464       {
465         HandleScope scope(isolate);
466         for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
467           isolate->bootstrapper()->NativesSourceLookup(i);
468         }
469       }
470       // If we don't do this then we end up with a stray root pointing at the
471       // context even after we have disposed of env.
472       heap->CollectAllGarbage(Heap::kNoGCFlags);
473
474       int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
475       Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
476       SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
477
478       {
479         v8::HandleScope handle_scope(v8_isolate);
480         v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
481       }
482
483       i::Object* raw_context = *v8::Utils::OpenPersistent(env);
484
485       env.Reset();
486
487       SnapshotByteSink startup_sink;
488       StartupSerializer startup_serializer(isolate, &startup_sink);
489       startup_serializer.SerializeStrongReferences();
490
491       SnapshotByteSink partial_sink;
492       PartialSerializer partial_serializer(isolate, &startup_serializer,
493                                            &partial_sink);
494       partial_serializer.Serialize(&raw_context);
495       startup_serializer.SerializeWeakReferences();
496
497       SnapshotData startup_snapshot(startup_serializer);
498       SnapshotData partial_snapshot(partial_serializer);
499
500       WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
501       WritePayload(startup_snapshot.RawData(), startup_name.start());
502
503       startup_name.Dispose();
504     }
505     v8_isolate->Dispose();
506   }
507 }
508
509
510 UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization, ContextSerialization) {
511   if (!Snapshot::HaveASnapshotToStartFrom()) {
512     int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
513     Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
514     SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
515
516     v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
517     CHECK(v8_isolate);
518     startup_name.Dispose();
519     {
520       v8::Isolate::Scope isolate_scope(v8_isolate);
521
522       const char* file_name = FLAG_testing_serialization_file;
523
524       int snapshot_size = 0;
525       byte* snapshot = ReadBytes(file_name, &snapshot_size);
526
527       Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
528       HandleScope handle_scope(isolate);
529       Handle<Object> root;
530       Handle<FixedArray> outdated_contexts;
531       Handle<JSGlobalProxy> global_proxy =
532           isolate->factory()->NewUninitializedJSGlobalProxy();
533       {
534         SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
535         Deserializer deserializer(&snapshot_data);
536         root = deserializer.DeserializePartial(isolate, global_proxy,
537                                                &outdated_contexts)
538                    .ToHandleChecked();
539         CHECK(root->IsContext());
540         CHECK(Handle<Context>::cast(root)->global_proxy() == *global_proxy);
541         CHECK_EQ(1, outdated_contexts->length());
542       }
543
544       Handle<Object> root2;
545       {
546         SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
547         Deserializer deserializer(&snapshot_data);
548         root2 = deserializer.DeserializePartial(isolate, global_proxy,
549                                                 &outdated_contexts)
550                     .ToHandleChecked();
551         CHECK(root2->IsContext());
552         CHECK(!root.is_identical_to(root2));
553       }
554     }
555     v8_isolate->Dispose();
556   }
557 }
558
559
560 UNINITIALIZED_TEST(CustomContextSerialization) {
561   if (!Snapshot::HaveASnapshotToStartFrom()) {
562     v8::Isolate::CreateParams params;
563     params.enable_serializer = true;
564     v8::Isolate* v8_isolate = v8::Isolate::New(params);
565     Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
566     {
567       v8::Isolate::Scope isolate_scope(v8_isolate);
568
569       v8::Persistent<v8::Context> env;
570       {
571         HandleScope scope(isolate);
572         env.Reset(v8_isolate, v8::Context::New(v8_isolate));
573       }
574       DCHECK(!env.IsEmpty());
575       {
576         v8::HandleScope handle_scope(v8_isolate);
577         v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
578         // After execution, e's function context refers to the global object.
579         CompileRun(
580             "var e;"
581             "(function() {"
582             "  e = function(s) { return eval (s); }"
583             "})();"
584             "var o = this;"
585             "var r = Math.random() + Math.cos(0);"
586             "var f = (function(a, b) { return a + b; }).bind(1, 2, 3);"
587             "var s = parseInt('12345');");
588
589         Vector<const uint8_t> source = ConstructSource(
590             STATIC_CHAR_VECTOR("function g() { return [,"),
591             STATIC_CHAR_VECTOR("1,"),
592             STATIC_CHAR_VECTOR("];} a = g(); b = g(); b.push(1);"), 100000);
593         v8::Handle<v8::String> source_str = v8::String::NewFromOneByte(
594             v8_isolate, source.start(), v8::String::kNormalString,
595             source.length());
596         CompileRun(source_str);
597         source.Dispose();
598       }
599       // Make sure all builtin scripts are cached.
600       {
601         HandleScope scope(isolate);
602         for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
603           isolate->bootstrapper()->NativesSourceLookup(i);
604         }
605       }
606       // If we don't do this then we end up with a stray root pointing at the
607       // context even after we have disposed of env.
608       isolate->heap()->CollectAllAvailableGarbage("snapshotting");
609
610       int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
611       Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
612       SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
613
614       {
615         v8::HandleScope handle_scope(v8_isolate);
616         v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
617       }
618
619       i::Object* raw_context = *v8::Utils::OpenPersistent(env);
620
621       env.Reset();
622
623       SnapshotByteSink startup_sink;
624       StartupSerializer startup_serializer(isolate, &startup_sink);
625       startup_serializer.SerializeStrongReferences();
626
627       SnapshotByteSink partial_sink;
628       PartialSerializer partial_serializer(isolate, &startup_serializer,
629                                            &partial_sink);
630       partial_serializer.Serialize(&raw_context);
631       startup_serializer.SerializeWeakReferences();
632
633       SnapshotData startup_snapshot(startup_serializer);
634       SnapshotData partial_snapshot(partial_serializer);
635
636       WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
637       WritePayload(startup_snapshot.RawData(), startup_name.start());
638
639       startup_name.Dispose();
640     }
641     v8_isolate->Dispose();
642   }
643 }
644
645
646 UNINITIALIZED_DEPENDENT_TEST(CustomContextDeserialization,
647                              CustomContextSerialization) {
648   FLAG_crankshaft = false;
649   if (!Snapshot::HaveASnapshotToStartFrom()) {
650     int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
651     Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
652     SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
653
654     v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
655     CHECK(v8_isolate);
656     startup_name.Dispose();
657     {
658       v8::Isolate::Scope isolate_scope(v8_isolate);
659
660       const char* file_name = FLAG_testing_serialization_file;
661
662       int snapshot_size = 0;
663       byte* snapshot = ReadBytes(file_name, &snapshot_size);
664
665       Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
666       HandleScope handle_scope(isolate);
667       Handle<Object> root;
668       Handle<FixedArray> outdated_contexts;
669       Handle<JSGlobalProxy> global_proxy =
670           isolate->factory()->NewUninitializedJSGlobalProxy();
671       {
672         SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
673         Deserializer deserializer(&snapshot_data);
674         root = deserializer.DeserializePartial(isolate, global_proxy,
675                                                &outdated_contexts)
676                    .ToHandleChecked();
677         CHECK_EQ(2, outdated_contexts->length());
678         CHECK(root->IsContext());
679         Handle<Context> context = Handle<Context>::cast(root);
680         CHECK(context->global_proxy() == *global_proxy);
681         Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o");
682         Handle<JSObject> global_object(context->global_object(), isolate);
683         Handle<Object> property = JSObject::GetDataProperty(global_object, o);
684         CHECK(property.is_identical_to(global_proxy));
685
686         v8::Handle<v8::Context> v8_context = v8::Utils::ToLocal(context);
687         v8::Context::Scope context_scope(v8_context);
688         double r = CompileRun("r")->ToNumber(v8_isolate)->Value();
689         CHECK(r >= 1 && r <= 2);
690         int f = CompileRun("f()")->ToNumber(v8_isolate)->Int32Value();
691         CHECK_EQ(5, f);
692         f = CompileRun("e('f()')")->ToNumber(v8_isolate)->Int32Value();
693         CHECK_EQ(5, f);
694         v8::Handle<v8::String> s = CompileRun("s")->ToString(v8_isolate);
695         CHECK(s->Equals(v8_str("12345")));
696         int a = CompileRun("a.length")->ToNumber(v8_isolate)->Int32Value();
697         CHECK_EQ(100001, a);
698         int b = CompileRun("b.length")->ToNumber(v8_isolate)->Int32Value();
699         CHECK_EQ(100002, b);
700       }
701     }
702     v8_isolate->Dispose();
703   }
704 }
705
706
707 TEST(TestThatAlwaysSucceeds) {
708 }
709
710
711 TEST(TestThatAlwaysFails) {
712   bool ArtificialFailure = false;
713   CHECK(ArtificialFailure);
714 }
715
716
717 DEPENDENT_TEST(DependentTestThatAlwaysFails, TestThatAlwaysSucceeds) {
718   bool ArtificialFailure2 = false;
719   CHECK(ArtificialFailure2);
720 }
721
722
723 int CountBuiltins() {
724   // Check that we have not deserialized any additional builtin.
725   HeapIterator iterator(CcTest::heap());
726   DisallowHeapAllocation no_allocation;
727   int counter = 0;
728   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
729     if (obj->IsCode() && Code::cast(obj)->kind() == Code::BUILTIN) counter++;
730   }
731   return counter;
732 }
733
734
735 static Handle<SharedFunctionInfo> CompileScript(
736     Isolate* isolate, Handle<String> source, Handle<String> name,
737     ScriptData** cached_data, v8::ScriptCompiler::CompileOptions options) {
738   return Compiler::CompileScript(source, name, 0, 0, false, false,
739                                  Handle<Context>(isolate->native_context()),
740                                  NULL, cached_data, options, NOT_NATIVES_CODE,
741                                  false);
742 }
743
744
745 TEST(SerializeToplevelOnePlusOne) {
746   FLAG_serialize_toplevel = true;
747   LocalContext context;
748   Isolate* isolate = CcTest::i_isolate();
749   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
750
751   v8::HandleScope scope(CcTest::isolate());
752
753   const char* source = "1 + 1";
754
755   Handle<String> orig_source = isolate->factory()
756                                    ->NewStringFromUtf8(CStrVector(source))
757                                    .ToHandleChecked();
758   Handle<String> copy_source = isolate->factory()
759                                    ->NewStringFromUtf8(CStrVector(source))
760                                    .ToHandleChecked();
761   CHECK(!orig_source.is_identical_to(copy_source));
762   CHECK(orig_source->Equals(*copy_source));
763
764   ScriptData* cache = NULL;
765
766   Handle<SharedFunctionInfo> orig =
767       CompileScript(isolate, orig_source, Handle<String>(), &cache,
768                     v8::ScriptCompiler::kProduceCodeCache);
769
770   int builtins_count = CountBuiltins();
771
772   Handle<SharedFunctionInfo> copy;
773   {
774     DisallowCompilation no_compile_expected(isolate);
775     copy = CompileScript(isolate, copy_source, Handle<String>(), &cache,
776                          v8::ScriptCompiler::kConsumeCodeCache);
777   }
778
779   CHECK_NE(*orig, *copy);
780   CHECK(Script::cast(copy->script())->source() == *copy_source);
781
782   Handle<JSFunction> copy_fun =
783       isolate->factory()->NewFunctionFromSharedFunctionInfo(
784           copy, isolate->native_context());
785   Handle<JSObject> global(isolate->context()->global_object());
786   Handle<Object> copy_result =
787       Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
788   CHECK_EQ(2, Handle<Smi>::cast(copy_result)->value());
789
790   CHECK_EQ(builtins_count, CountBuiltins());
791
792   delete cache;
793 }
794
795
796 TEST(CodeCachePromotedToCompilationCache) {
797   FLAG_serialize_toplevel = true;
798   LocalContext context;
799   Isolate* isolate = CcTest::i_isolate();
800
801   v8::HandleScope scope(CcTest::isolate());
802
803   const char* source = "1 + 1";
804
805   Handle<String> src = isolate->factory()
806                            ->NewStringFromUtf8(CStrVector(source))
807                            .ToHandleChecked();
808   ScriptData* cache = NULL;
809
810   CompileScript(isolate, src, src, &cache,
811                 v8::ScriptCompiler::kProduceCodeCache);
812
813   DisallowCompilation no_compile_expected(isolate);
814   Handle<SharedFunctionInfo> copy = CompileScript(
815       isolate, src, src, &cache, v8::ScriptCompiler::kConsumeCodeCache);
816
817   CHECK(isolate->compilation_cache()
818             ->LookupScript(src, src, 0, 0, false, false,
819                            isolate->native_context(), SLOPPY)
820             .ToHandleChecked()
821             .is_identical_to(copy));
822
823   delete cache;
824 }
825
826
827 TEST(SerializeToplevelInternalizedString) {
828   FLAG_serialize_toplevel = true;
829   LocalContext context;
830   Isolate* isolate = CcTest::i_isolate();
831   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
832
833   v8::HandleScope scope(CcTest::isolate());
834
835   const char* source = "'string1'";
836
837   Handle<String> orig_source = isolate->factory()
838                                    ->NewStringFromUtf8(CStrVector(source))
839                                    .ToHandleChecked();
840   Handle<String> copy_source = isolate->factory()
841                                    ->NewStringFromUtf8(CStrVector(source))
842                                    .ToHandleChecked();
843   CHECK(!orig_source.is_identical_to(copy_source));
844   CHECK(orig_source->Equals(*copy_source));
845
846   Handle<JSObject> global(isolate->context()->global_object());
847   ScriptData* cache = NULL;
848
849   Handle<SharedFunctionInfo> orig =
850       CompileScript(isolate, orig_source, Handle<String>(), &cache,
851                     v8::ScriptCompiler::kProduceCodeCache);
852   Handle<JSFunction> orig_fun =
853       isolate->factory()->NewFunctionFromSharedFunctionInfo(
854           orig, isolate->native_context());
855   Handle<Object> orig_result =
856       Execution::Call(isolate, orig_fun, global, 0, NULL).ToHandleChecked();
857   CHECK(orig_result->IsInternalizedString());
858
859   int builtins_count = CountBuiltins();
860
861   Handle<SharedFunctionInfo> copy;
862   {
863     DisallowCompilation no_compile_expected(isolate);
864     copy = CompileScript(isolate, copy_source, Handle<String>(), &cache,
865                          v8::ScriptCompiler::kConsumeCodeCache);
866   }
867   CHECK_NE(*orig, *copy);
868   CHECK(Script::cast(copy->script())->source() == *copy_source);
869
870   Handle<JSFunction> copy_fun =
871       isolate->factory()->NewFunctionFromSharedFunctionInfo(
872           copy, isolate->native_context());
873   CHECK_NE(*orig_fun, *copy_fun);
874   Handle<Object> copy_result =
875       Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
876   CHECK(orig_result.is_identical_to(copy_result));
877   Handle<String> expected =
878       isolate->factory()->NewStringFromAsciiChecked("string1");
879
880   CHECK(Handle<String>::cast(copy_result)->Equals(*expected));
881   CHECK_EQ(builtins_count, CountBuiltins());
882
883   delete cache;
884 }
885
886
887 TEST(SerializeToplevelLargeCodeObject) {
888   FLAG_serialize_toplevel = true;
889   LocalContext context;
890   Isolate* isolate = CcTest::i_isolate();
891   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
892
893   v8::HandleScope scope(CcTest::isolate());
894
895   Vector<const uint8_t> source =
896       ConstructSource(STATIC_CHAR_VECTOR("var j=1; try { if (j) throw 1;"),
897                       STATIC_CHAR_VECTOR("for(var i=0;i<1;i++)j++;"),
898                       STATIC_CHAR_VECTOR("} catch (e) { j=7; } j"), 10000);
899   Handle<String> source_str =
900       isolate->factory()->NewStringFromOneByte(source).ToHandleChecked();
901
902   Handle<JSObject> global(isolate->context()->global_object());
903   ScriptData* cache = NULL;
904
905   Handle<SharedFunctionInfo> orig =
906       CompileScript(isolate, source_str, Handle<String>(), &cache,
907                     v8::ScriptCompiler::kProduceCodeCache);
908
909   CHECK(isolate->heap()->InSpace(orig->code(), LO_SPACE));
910
911   Handle<SharedFunctionInfo> copy;
912   {
913     DisallowCompilation no_compile_expected(isolate);
914     copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
915                          v8::ScriptCompiler::kConsumeCodeCache);
916   }
917   CHECK_NE(*orig, *copy);
918
919   Handle<JSFunction> copy_fun =
920       isolate->factory()->NewFunctionFromSharedFunctionInfo(
921           copy, isolate->native_context());
922
923   Handle<Object> copy_result =
924       Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
925
926   int result_int;
927   CHECK(copy_result->ToInt32(&result_int));
928   CHECK_EQ(7, result_int);
929
930   delete cache;
931   source.Dispose();
932 }
933
934
935 TEST(SerializeToplevelLargeStrings) {
936   FLAG_serialize_toplevel = true;
937   LocalContext context;
938   Isolate* isolate = CcTest::i_isolate();
939   Factory* f = isolate->factory();
940   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
941
942   v8::HandleScope scope(CcTest::isolate());
943
944   Vector<const uint8_t> source_s = ConstructSource(
945       STATIC_CHAR_VECTOR("var s = \""), STATIC_CHAR_VECTOR("abcdef"),
946       STATIC_CHAR_VECTOR("\";"), 1000000);
947   Vector<const uint8_t> source_t = ConstructSource(
948       STATIC_CHAR_VECTOR("var t = \""), STATIC_CHAR_VECTOR("uvwxyz"),
949       STATIC_CHAR_VECTOR("\"; s + t"), 999999);
950   Handle<String> source_str =
951       f->NewConsString(f->NewStringFromOneByte(source_s).ToHandleChecked(),
952                        f->NewStringFromOneByte(source_t).ToHandleChecked())
953           .ToHandleChecked();
954
955   Handle<JSObject> global(isolate->context()->global_object());
956   ScriptData* cache = NULL;
957
958   Handle<SharedFunctionInfo> orig =
959       CompileScript(isolate, source_str, Handle<String>(), &cache,
960                     v8::ScriptCompiler::kProduceCodeCache);
961
962   Handle<SharedFunctionInfo> copy;
963   {
964     DisallowCompilation no_compile_expected(isolate);
965     copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
966                          v8::ScriptCompiler::kConsumeCodeCache);
967   }
968   CHECK_NE(*orig, *copy);
969
970   Handle<JSFunction> copy_fun =
971       isolate->factory()->NewFunctionFromSharedFunctionInfo(
972           copy, isolate->native_context());
973
974   Handle<Object> copy_result =
975       Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
976
977   CHECK_EQ(6 * 1999999, Handle<String>::cast(copy_result)->length());
978   Handle<Object> property = JSObject::GetDataProperty(
979       isolate->global_object(), f->NewStringFromAsciiChecked("s"));
980   CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
981   property = JSObject::GetDataProperty(isolate->global_object(),
982                                        f->NewStringFromAsciiChecked("t"));
983   CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
984   // Make sure we do not serialize too much, e.g. include the source string.
985   CHECK_LT(cache->length(), 13000000);
986
987   delete cache;
988   source_s.Dispose();
989   source_t.Dispose();
990 }
991
992
993 TEST(SerializeToplevelThreeBigStrings) {
994   FLAG_serialize_toplevel = true;
995   LocalContext context;
996   Isolate* isolate = CcTest::i_isolate();
997   Factory* f = isolate->factory();
998   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
999
1000   v8::HandleScope scope(CcTest::isolate());
1001
1002   Vector<const uint8_t> source_a =
1003       ConstructSource(STATIC_CHAR_VECTOR("var a = \""), STATIC_CHAR_VECTOR("a"),
1004                       STATIC_CHAR_VECTOR("\";"), 700000);
1005   Handle<String> source_a_str =
1006       f->NewStringFromOneByte(source_a).ToHandleChecked();
1007
1008   Vector<const uint8_t> source_b =
1009       ConstructSource(STATIC_CHAR_VECTOR("var b = \""), STATIC_CHAR_VECTOR("b"),
1010                       STATIC_CHAR_VECTOR("\";"), 600000);
1011   Handle<String> source_b_str =
1012       f->NewStringFromOneByte(source_b).ToHandleChecked();
1013
1014   Vector<const uint8_t> source_c =
1015       ConstructSource(STATIC_CHAR_VECTOR("var c = \""), STATIC_CHAR_VECTOR("c"),
1016                       STATIC_CHAR_VECTOR("\";"), 500000);
1017   Handle<String> source_c_str =
1018       f->NewStringFromOneByte(source_c).ToHandleChecked();
1019
1020   Handle<String> source_str =
1021       f->NewConsString(
1022              f->NewConsString(source_a_str, source_b_str).ToHandleChecked(),
1023              source_c_str).ToHandleChecked();
1024
1025   Handle<JSObject> global(isolate->context()->global_object());
1026   ScriptData* cache = NULL;
1027
1028   Handle<SharedFunctionInfo> orig =
1029       CompileScript(isolate, source_str, Handle<String>(), &cache,
1030                     v8::ScriptCompiler::kProduceCodeCache);
1031
1032   Handle<SharedFunctionInfo> copy;
1033   {
1034     DisallowCompilation no_compile_expected(isolate);
1035     copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
1036                          v8::ScriptCompiler::kConsumeCodeCache);
1037   }
1038   CHECK_NE(*orig, *copy);
1039
1040   Handle<JSFunction> copy_fun =
1041       isolate->factory()->NewFunctionFromSharedFunctionInfo(
1042           copy, isolate->native_context());
1043
1044   USE(Execution::Call(isolate, copy_fun, global, 0, NULL));
1045
1046   CHECK_EQ(600000 + 700000, CompileRun("(a + b).length")->Int32Value());
1047   CHECK_EQ(500000 + 600000, CompileRun("(b + c).length")->Int32Value());
1048   Heap* heap = isolate->heap();
1049   CHECK(heap->InSpace(
1050       *v8::Utils::OpenHandle(*CompileRun("a")->ToString(CcTest::isolate())),
1051       OLD_DATA_SPACE));
1052   CHECK(heap->InSpace(
1053       *v8::Utils::OpenHandle(*CompileRun("b")->ToString(CcTest::isolate())),
1054       OLD_DATA_SPACE));
1055   CHECK(heap->InSpace(
1056       *v8::Utils::OpenHandle(*CompileRun("c")->ToString(CcTest::isolate())),
1057       OLD_DATA_SPACE));
1058
1059   delete cache;
1060   source_a.Dispose();
1061   source_b.Dispose();
1062   source_c.Dispose();
1063 }
1064
1065
1066 class SerializerOneByteResource
1067     : public v8::String::ExternalOneByteStringResource {
1068  public:
1069   SerializerOneByteResource(const char* data, size_t length)
1070       : data_(data), length_(length) {}
1071   virtual const char* data() const { return data_; }
1072   virtual size_t length() const { return length_; }
1073
1074  private:
1075   const char* data_;
1076   size_t length_;
1077 };
1078
1079
1080 class SerializerTwoByteResource : public v8::String::ExternalStringResource {
1081  public:
1082   SerializerTwoByteResource(const char* data, size_t length)
1083       : data_(AsciiToTwoByteString(data)), length_(length) {}
1084   ~SerializerTwoByteResource() { DeleteArray<const uint16_t>(data_); }
1085
1086   virtual const uint16_t* data() const { return data_; }
1087   virtual size_t length() const { return length_; }
1088
1089  private:
1090   const uint16_t* data_;
1091   size_t length_;
1092 };
1093
1094
1095 TEST(SerializeToplevelExternalString) {
1096   FLAG_serialize_toplevel = true;
1097   LocalContext context;
1098   Isolate* isolate = CcTest::i_isolate();
1099   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
1100
1101   v8::HandleScope scope(CcTest::isolate());
1102
1103   // Obtain external internalized one-byte string.
1104   SerializerOneByteResource one_byte_resource("one_byte", 8);
1105   Handle<String> one_byte_string =
1106       isolate->factory()->NewStringFromAsciiChecked("one_byte");
1107   one_byte_string = isolate->factory()->InternalizeString(one_byte_string);
1108   one_byte_string->MakeExternal(&one_byte_resource);
1109   CHECK(one_byte_string->IsExternalOneByteString());
1110   CHECK(one_byte_string->IsInternalizedString());
1111
1112   // Obtain external internalized two-byte string.
1113   SerializerTwoByteResource two_byte_resource("two_byte", 8);
1114   Handle<String> two_byte_string =
1115       isolate->factory()->NewStringFromAsciiChecked("two_byte");
1116   two_byte_string = isolate->factory()->InternalizeString(two_byte_string);
1117   two_byte_string->MakeExternal(&two_byte_resource);
1118   CHECK(two_byte_string->IsExternalTwoByteString());
1119   CHECK(two_byte_string->IsInternalizedString());
1120
1121   const char* source =
1122       "var o = {}               \n"
1123       "o.one_byte = 7;          \n"
1124       "o.two_byte = 8;          \n"
1125       "o.one_byte + o.two_byte; \n";
1126   Handle<String> source_string = isolate->factory()
1127                                      ->NewStringFromUtf8(CStrVector(source))
1128                                      .ToHandleChecked();
1129
1130   Handle<JSObject> global(isolate->context()->global_object());
1131   ScriptData* cache = NULL;
1132
1133   Handle<SharedFunctionInfo> orig =
1134       CompileScript(isolate, source_string, Handle<String>(), &cache,
1135                     v8::ScriptCompiler::kProduceCodeCache);
1136
1137   Handle<SharedFunctionInfo> copy;
1138   {
1139     DisallowCompilation no_compile_expected(isolate);
1140     copy = CompileScript(isolate, source_string, Handle<String>(), &cache,
1141                          v8::ScriptCompiler::kConsumeCodeCache);
1142   }
1143   CHECK_NE(*orig, *copy);
1144
1145   Handle<JSFunction> copy_fun =
1146       isolate->factory()->NewFunctionFromSharedFunctionInfo(
1147           copy, isolate->native_context());
1148
1149   Handle<Object> copy_result =
1150       Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
1151
1152   CHECK_EQ(15.0f, copy_result->Number());
1153
1154   delete cache;
1155 }
1156
1157
1158 TEST(SerializeToplevelLargeExternalString) {
1159   FLAG_serialize_toplevel = true;
1160   LocalContext context;
1161   Isolate* isolate = CcTest::i_isolate();
1162   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
1163
1164   Factory* f = isolate->factory();
1165
1166   v8::HandleScope scope(CcTest::isolate());
1167
1168   // Create a huge external internalized string to use as variable name.
1169   Vector<const uint8_t> string =
1170       ConstructSource(STATIC_CHAR_VECTOR(""), STATIC_CHAR_VECTOR("abcdef"),
1171                       STATIC_CHAR_VECTOR(""), 999999);
1172   Handle<String> name = f->NewStringFromOneByte(string).ToHandleChecked();
1173   SerializerOneByteResource one_byte_resource(
1174       reinterpret_cast<const char*>(string.start()), string.length());
1175   name = f->InternalizeString(name);
1176   name->MakeExternal(&one_byte_resource);
1177   CHECK(name->IsExternalOneByteString());
1178   CHECK(name->IsInternalizedString());
1179   CHECK(isolate->heap()->InSpace(*name, LO_SPACE));
1180
1181   // Create the source, which is "var <literal> = 42; <literal>".
1182   Handle<String> source_str =
1183       f->NewConsString(
1184              f->NewConsString(f->NewStringFromAsciiChecked("var "), name)
1185                  .ToHandleChecked(),
1186              f->NewConsString(f->NewStringFromAsciiChecked(" = 42; "), name)
1187                  .ToHandleChecked()).ToHandleChecked();
1188
1189   Handle<JSObject> global(isolate->context()->global_object());
1190   ScriptData* cache = NULL;
1191
1192   Handle<SharedFunctionInfo> orig =
1193       CompileScript(isolate, source_str, Handle<String>(), &cache,
1194                     v8::ScriptCompiler::kProduceCodeCache);
1195
1196   Handle<SharedFunctionInfo> copy;
1197   {
1198     DisallowCompilation no_compile_expected(isolate);
1199     copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
1200                          v8::ScriptCompiler::kConsumeCodeCache);
1201   }
1202   CHECK_NE(*orig, *copy);
1203
1204   Handle<JSFunction> copy_fun =
1205       f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
1206
1207   Handle<Object> copy_result =
1208       Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
1209
1210   CHECK_EQ(42.0f, copy_result->Number());
1211
1212   delete cache;
1213   string.Dispose();
1214 }
1215
1216
1217 TEST(SerializeToplevelExternalScriptName) {
1218   FLAG_serialize_toplevel = true;
1219   LocalContext context;
1220   Isolate* isolate = CcTest::i_isolate();
1221   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
1222
1223   Factory* f = isolate->factory();
1224
1225   v8::HandleScope scope(CcTest::isolate());
1226
1227   const char* source =
1228       "var a = [1, 2, 3, 4];"
1229       "a.reduce(function(x, y) { return x + y }, 0)";
1230
1231   Handle<String> source_string =
1232       f->NewStringFromUtf8(CStrVector(source)).ToHandleChecked();
1233
1234   const SerializerOneByteResource one_byte_resource("one_byte", 8);
1235   Handle<String> name =
1236       f->NewExternalStringFromOneByte(&one_byte_resource).ToHandleChecked();
1237   CHECK(name->IsExternalOneByteString());
1238   CHECK(!name->IsInternalizedString());
1239
1240   Handle<JSObject> global(isolate->context()->global_object());
1241   ScriptData* cache = NULL;
1242
1243   Handle<SharedFunctionInfo> orig =
1244       CompileScript(isolate, source_string, name, &cache,
1245                     v8::ScriptCompiler::kProduceCodeCache);
1246
1247   Handle<SharedFunctionInfo> copy;
1248   {
1249     DisallowCompilation no_compile_expected(isolate);
1250     copy = CompileScript(isolate, source_string, name, &cache,
1251                          v8::ScriptCompiler::kConsumeCodeCache);
1252   }
1253   CHECK_NE(*orig, *copy);
1254
1255   Handle<JSFunction> copy_fun =
1256       f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
1257
1258   Handle<Object> copy_result =
1259       Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
1260
1261   CHECK_EQ(10.0f, copy_result->Number());
1262
1263   delete cache;
1264 }
1265
1266
1267 static bool toplevel_test_code_event_found = false;
1268
1269
1270 static void SerializerCodeEventListener(const v8::JitCodeEvent* event) {
1271   if (event->type == v8::JitCodeEvent::CODE_ADDED &&
1272       memcmp(event->name.str, "Script:~test", 12) == 0) {
1273     toplevel_test_code_event_found = true;
1274   }
1275 }
1276
1277
1278 v8::ScriptCompiler::CachedData* ProduceCache(const char* source) {
1279   v8::ScriptCompiler::CachedData* cache;
1280   v8::Isolate* isolate1 = v8::Isolate::New();
1281   {
1282     v8::Isolate::Scope iscope(isolate1);
1283     v8::HandleScope scope(isolate1);
1284     v8::Local<v8::Context> context = v8::Context::New(isolate1);
1285     v8::Context::Scope context_scope(context);
1286
1287     v8::Local<v8::String> source_str = v8_str(source);
1288     v8::ScriptOrigin origin(v8_str("test"));
1289     v8::ScriptCompiler::Source source(source_str, origin);
1290     v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
1291         isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
1292     const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
1293     CHECK(data);
1294     // Persist cached data.
1295     uint8_t* buffer = NewArray<uint8_t>(data->length);
1296     MemCopy(buffer, data->data, data->length);
1297     cache = new v8::ScriptCompiler::CachedData(
1298         buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
1299
1300     v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
1301     CHECK(result->ToString(isolate1)->Equals(v8_str("abcdef")));
1302   }
1303   isolate1->Dispose();
1304   return cache;
1305 }
1306
1307
1308 TEST(SerializeToplevelIsolates) {
1309   FLAG_serialize_toplevel = true;
1310
1311   const char* source = "function f() { return 'abc'; }; f() + 'def'";
1312   v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
1313
1314   v8::Isolate* isolate2 = v8::Isolate::New();
1315   isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
1316                                    SerializerCodeEventListener);
1317   toplevel_test_code_event_found = false;
1318   {
1319     v8::Isolate::Scope iscope(isolate2);
1320     v8::HandleScope scope(isolate2);
1321     v8::Local<v8::Context> context = v8::Context::New(isolate2);
1322     v8::Context::Scope context_scope(context);
1323
1324     v8::Local<v8::String> source_str = v8_str(source);
1325     v8::ScriptOrigin origin(v8_str("test"));
1326     v8::ScriptCompiler::Source source(source_str, origin, cache);
1327     v8::Local<v8::UnboundScript> script;
1328     {
1329       DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
1330       script = v8::ScriptCompiler::CompileUnbound(
1331           isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache);
1332     }
1333     CHECK(!cache->rejected);
1334     v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
1335     CHECK(result->ToString(isolate2)->Equals(v8_str("abcdef")));
1336   }
1337   DCHECK(toplevel_test_code_event_found);
1338   isolate2->Dispose();
1339 }
1340
1341
1342 TEST(SerializeToplevelFlagChange) {
1343   FLAG_serialize_toplevel = true;
1344
1345   const char* source = "function f() { return 'abc'; }; f() + 'def'";
1346   v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
1347
1348   v8::Isolate* isolate2 = v8::Isolate::New();
1349   FLAG_allow_natives_syntax = true;  // Flag change should trigger cache reject.
1350   {
1351     v8::Isolate::Scope iscope(isolate2);
1352     v8::HandleScope scope(isolate2);
1353     v8::Local<v8::Context> context = v8::Context::New(isolate2);
1354     v8::Context::Scope context_scope(context);
1355
1356     v8::Local<v8::String> source_str = v8_str(source);
1357     v8::ScriptOrigin origin(v8_str("test"));
1358     v8::ScriptCompiler::Source source(source_str, origin, cache);
1359     v8::ScriptCompiler::CompileUnbound(isolate2, &source,
1360                                        v8::ScriptCompiler::kConsumeCodeCache);
1361     CHECK(cache->rejected);
1362   }
1363   isolate2->Dispose();
1364 }
1365
1366
1367 TEST(SerializeToplevelBitFlip) {
1368   FLAG_serialize_toplevel = true;
1369
1370   const char* source = "function f() { return 'abc'; }; f() + 'def'";
1371   v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
1372
1373   // Random bit flip.
1374   const_cast<uint8_t*>(cache->data)[337] ^= 0x40;
1375
1376   v8::Isolate* isolate2 = v8::Isolate::New();
1377   {
1378     v8::Isolate::Scope iscope(isolate2);
1379     v8::HandleScope scope(isolate2);
1380     v8::Local<v8::Context> context = v8::Context::New(isolate2);
1381     v8::Context::Scope context_scope(context);
1382
1383     v8::Local<v8::String> source_str = v8_str(source);
1384     v8::ScriptOrigin origin(v8_str("test"));
1385     v8::ScriptCompiler::Source source(source_str, origin, cache);
1386     v8::ScriptCompiler::CompileUnbound(isolate2, &source,
1387                                        v8::ScriptCompiler::kConsumeCodeCache);
1388     CHECK(cache->rejected);
1389   }
1390   isolate2->Dispose();
1391 }
1392
1393
1394 TEST(SerializeWithHarmonyScoping) {
1395   FLAG_serialize_toplevel = true;
1396   FLAG_harmony_scoping = true;
1397
1398   const char* source1 = "'use strict'; let x = 'X'";
1399   const char* source2 = "'use strict'; let y = 'Y'";
1400   const char* source3 = "'use strict'; x + y";
1401
1402   v8::ScriptCompiler::CachedData* cache;
1403
1404   v8::Isolate* isolate1 = v8::Isolate::New();
1405   {
1406     v8::Isolate::Scope iscope(isolate1);
1407     v8::HandleScope scope(isolate1);
1408     v8::Local<v8::Context> context = v8::Context::New(isolate1);
1409     v8::Context::Scope context_scope(context);
1410
1411     CompileRun(source1);
1412     CompileRun(source2);
1413
1414     v8::Local<v8::String> source_str = v8_str(source3);
1415     v8::ScriptOrigin origin(v8_str("test"));
1416     v8::ScriptCompiler::Source source(source_str, origin);
1417     v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
1418         isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
1419     const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
1420     CHECK(data);
1421     // Persist cached data.
1422     uint8_t* buffer = NewArray<uint8_t>(data->length);
1423     MemCopy(buffer, data->data, data->length);
1424     cache = new v8::ScriptCompiler::CachedData(
1425         buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
1426
1427     v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
1428     CHECK(result->ToString(isolate1)->Equals(v8_str("XY")));
1429   }
1430   isolate1->Dispose();
1431
1432   v8::Isolate* isolate2 = v8::Isolate::New();
1433   {
1434     v8::Isolate::Scope iscope(isolate2);
1435     v8::HandleScope scope(isolate2);
1436     v8::Local<v8::Context> context = v8::Context::New(isolate2);
1437     v8::Context::Scope context_scope(context);
1438
1439     // Reverse order of prior running scripts.
1440     CompileRun(source2);
1441     CompileRun(source1);
1442
1443     v8::Local<v8::String> source_str = v8_str(source3);
1444     v8::ScriptOrigin origin(v8_str("test"));
1445     v8::ScriptCompiler::Source source(source_str, origin, cache);
1446     v8::Local<v8::UnboundScript> script;
1447     {
1448       DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
1449       script = v8::ScriptCompiler::CompileUnbound(
1450           isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache);
1451     }
1452     v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
1453     CHECK(result->ToString(isolate2)->Equals(v8_str("XY")));
1454   }
1455   isolate2->Dispose();
1456 }