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> 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 int 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, 34), 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 class FileByteSink : public SnapshotByteSink { 118 public: 119 explicit FileByteSink(const char* snapshot_file) { 120 fp_ = v8::base::OS::FOpen(snapshot_file, "wb"); 121 file_name_ = snapshot_file; 122 if (fp_ == NULL) { 123 PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file); 124 exit(1); 125 } 126 } 127 virtual ~FileByteSink() { 128 if (fp_ != NULL) { 129 fclose(fp_); 130 } 131 } 132 virtual void Put(byte b, const char* description) { 133 if (fp_ != NULL) { 134 fputc(b, fp_); 135 } 136 } 137 virtual int Position() { 138 return ftell(fp_); 139 } 140 void WriteSpaceUsed( 141 int new_space_used, 142 int pointer_space_used, 143 int data_space_used, 144 int code_space_used, 145 int map_space_used, 146 int cell_space_used, 147 int property_cell_space_used); 148 149 private: 150 FILE* fp_; 151 const char* file_name_; 152 }; 153 154 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 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 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. 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. 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 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 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 295 static v8::Isolate* Deserialize() { 296 v8::Isolate* isolate = InitializeFromFile(FLAG_testing_serialization_file); 297 CHECK(isolate); 298 return isolate; 299 } 300 301 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 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 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 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 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 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 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 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 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 644 TEST(TestThatAlwaysSucceeds) { 645 } 646 647 648 TEST(TestThatAlwaysFails) { 649 bool ArtificialFailure = false; 650 CHECK(ArtificialFailure); 651 } 652 653 654 DEPENDENT_TEST(DependentTestThatAlwaysFails, TestThatAlwaysSucceeds) { 655 bool ArtificialFailure2 = false; 656 CHECK(ArtificialFailure2); 657 } 658 659 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 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 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 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