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