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/ast/scopeinfo.h" 35 #include "src/bootstrapper.h" 36 #include "src/compilation-cache.h" 37 #include "src/debug/debug.h" 38 #include "src/heap/spaces.h" 39 #include "src/objects.h" 40 #include "src/parsing/parser.h" 41 #include "src/runtime/runtime.h" 42 #include "src/snapshot/natives.h" 43 #include "src/snapshot/serialize.h" 44 #include "src/snapshot/snapshot.h" 45 #include "test/cctest/cctest.h" 46 #include "test/cctest/heap/utils-inl.h" 47 48 using namespace v8::internal; 49 50 51 bool DefaultSnapshotAvailable() { 52 return i::Snapshot::DefaultSnapshotBlob() != NULL; 53 } 54 55 56 void DisableTurbofan() { 57 const char* flag = "--turbo-filter=\"\""; 58 FlagList::SetFlagsFromString(flag, StrLength(flag)); 59 } 60 61 62 // TestIsolate is used for testing isolate serialization. 63 class TestIsolate : public Isolate { 64 public: 65 static v8::Isolate* NewInitialized(bool enable_serializer) { 66 i::Isolate* isolate = new TestIsolate(enable_serializer); 67 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 68 v8::Isolate::Scope isolate_scope(v8_isolate); 69 isolate->Init(NULL); 70 return v8_isolate; 71 } 72 explicit TestIsolate(bool enable_serializer) : Isolate(enable_serializer) { 73 set_array_buffer_allocator(CcTest::array_buffer_allocator()); 74 } 75 }; 76 77 78 void WritePayload(const Vector<const byte>& payload, const char* file_name) { 79 FILE* file = v8::base::OS::FOpen(file_name, "wb"); 80 if (file == NULL) { 81 PrintF("Unable to write to snapshot file \"%s\"\n", file_name); 82 exit(1); 83 } 84 size_t written = fwrite(payload.begin(), 1, payload.length(), file); 85 if (written != static_cast<size_t>(payload.length())) { 86 i::PrintF("Writing snapshot file failed.. Aborting.\n"); 87 exit(1); 88 } 89 fclose(file); 90 } 91 92 93 static bool WriteToFile(Isolate* isolate, const char* snapshot_file) { 94 SnapshotByteSink sink; 95 StartupSerializer ser(isolate, &sink); 96 ser.SerializeStrongReferences(); 97 ser.SerializeWeakReferencesAndDeferred(); 98 SnapshotData snapshot_data(ser); 99 WritePayload(snapshot_data.RawData(), snapshot_file); 100 return true; 101 } 102 103 104 static void Serialize(v8::Isolate* isolate) { 105 // We have to create one context. One reason for this is so that the builtins 106 // can be loaded from v8natives.js and their addresses can be processed. This 107 // will clear the pending fixups array, which would otherwise contain GC roots 108 // that would confuse the serialization/deserialization process. 109 v8::Isolate::Scope isolate_scope(isolate); 110 { 111 v8::HandleScope scope(isolate); 112 v8::Context::New(isolate); 113 } 114 115 Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate); 116 internal_isolate->heap()->CollectAllAvailableGarbage("serialize"); 117 WriteToFile(internal_isolate, FLAG_testing_serialization_file); 118 } 119 120 121 Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head, 122 Vector<const uint8_t> body, 123 Vector<const uint8_t> tail, int repeats) { 124 int source_length = head.length() + body.length() * repeats + tail.length(); 125 uint8_t* source = NewArray<uint8_t>(static_cast<size_t>(source_length)); 126 CopyChars(source, head.start(), head.length()); 127 for (int i = 0; i < repeats; i++) { 128 CopyChars(source + head.length() + i * body.length(), body.start(), 129 body.length()); 130 } 131 CopyChars(source + head.length() + repeats * body.length(), tail.start(), 132 tail.length()); 133 return Vector<const uint8_t>(const_cast<const uint8_t*>(source), 134 source_length); 135 } 136 137 138 // Test that the whole heap can be serialized. 139 UNINITIALIZED_TEST(Serialize) { 140 DisableTurbofan(); 141 if (DefaultSnapshotAvailable()) return; 142 v8::Isolate* isolate = TestIsolate::NewInitialized(true); 143 Serialize(isolate); 144 } 145 146 147 // Test that heap serialization is non-destructive. 148 UNINITIALIZED_TEST(SerializeTwice) { 149 DisableTurbofan(); 150 if (DefaultSnapshotAvailable()) return; 151 v8::Isolate* isolate = TestIsolate::NewInitialized(true); 152 Serialize(isolate); 153 Serialize(isolate); 154 } 155 156 157 //---------------------------------------------------------------------------- 158 // Tests that the heap can be deserialized. 159 160 v8::Isolate* InitializeFromFile(const char* snapshot_file) { 161 int len; 162 byte* str = ReadBytes(snapshot_file, &len); 163 if (!str) return NULL; 164 v8::Isolate* v8_isolate = NULL; 165 { 166 SnapshotData snapshot_data(Vector<const byte>(str, len)); 167 Deserializer deserializer(&snapshot_data); 168 Isolate* isolate = new TestIsolate(false); 169 v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 170 v8::Isolate::Scope isolate_scope(v8_isolate); 171 isolate->Init(&deserializer); 172 } 173 DeleteArray(str); 174 return v8_isolate; 175 } 176 177 178 static v8::Isolate* Deserialize() { 179 v8::Isolate* isolate = InitializeFromFile(FLAG_testing_serialization_file); 180 CHECK(isolate); 181 return isolate; 182 } 183 184 185 static void SanityCheck(v8::Isolate* v8_isolate) { 186 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 187 v8::HandleScope scope(v8_isolate); 188 #ifdef VERIFY_HEAP 189 isolate->heap()->Verify(); 190 #endif 191 CHECK(isolate->global_object()->IsJSObject()); 192 CHECK(isolate->native_context()->IsContext()); 193 CHECK(isolate->heap()->string_table()->IsStringTable()); 194 isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("Empty")); 195 } 196 197 198 UNINITIALIZED_DEPENDENT_TEST(Deserialize, Serialize) { 199 // The serialize-deserialize tests only work if the VM is built without 200 // serialization. That doesn't matter. We don't need to be able to 201 // serialize a snapshot in a VM that is booted from a snapshot. 202 DisableTurbofan(); 203 if (DefaultSnapshotAvailable()) return; 204 v8::Isolate* isolate = Deserialize(); 205 { 206 v8::HandleScope handle_scope(isolate); 207 v8::Isolate::Scope isolate_scope(isolate); 208 209 v8::Local<v8::Context> env = v8::Context::New(isolate); 210 env->Enter(); 211 212 SanityCheck(isolate); 213 } 214 isolate->Dispose(); 215 } 216 217 218 UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerialization, 219 SerializeTwice) { 220 DisableTurbofan(); 221 if (DefaultSnapshotAvailable()) return; 222 v8::Isolate* isolate = Deserialize(); 223 { 224 v8::Isolate::Scope isolate_scope(isolate); 225 v8::HandleScope handle_scope(isolate); 226 227 v8::Local<v8::Context> env = v8::Context::New(isolate); 228 env->Enter(); 229 230 SanityCheck(isolate); 231 } 232 isolate->Dispose(); 233 } 234 235 236 UNINITIALIZED_DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) { 237 DisableTurbofan(); 238 if (DefaultSnapshotAvailable()) return; 239 v8::Isolate* isolate = Deserialize(); 240 { 241 v8::Isolate::Scope isolate_scope(isolate); 242 v8::HandleScope handle_scope(isolate); 243 244 245 v8::Local<v8::Context> env = v8::Context::New(isolate); 246 env->Enter(); 247 248 const char* c_source = "\"1234\".length"; 249 v8::Local<v8::Script> script = v8_compile(c_source); 250 v8::Maybe<int32_t> result = script->Run(isolate->GetCurrentContext()) 251 .ToLocalChecked() 252 ->Int32Value(isolate->GetCurrentContext()); 253 CHECK_EQ(4, result.FromJust()); 254 } 255 isolate->Dispose(); 256 } 257 258 259 UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2, 260 SerializeTwice) { 261 DisableTurbofan(); 262 if (DefaultSnapshotAvailable()) return; 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 const char* c_source = "\"1234\".length"; 272 v8::Local<v8::Script> script = v8_compile(c_source); 273 v8::Maybe<int32_t> result = script->Run(isolate->GetCurrentContext()) 274 .ToLocalChecked() 275 ->Int32Value(isolate->GetCurrentContext()); 276 CHECK_EQ(4, result.FromJust()); 277 } 278 isolate->Dispose(); 279 } 280 281 282 UNINITIALIZED_TEST(PartialSerialization) { 283 DisableTurbofan(); 284 if (DefaultSnapshotAvailable()) return; 285 v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); 286 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 287 v8_isolate->Enter(); 288 { 289 Heap* heap = isolate->heap(); 290 291 v8::Persistent<v8::Context> env; 292 { 293 HandleScope scope(isolate); 294 env.Reset(v8_isolate, v8::Context::New(v8_isolate)); 295 } 296 CHECK(!env.IsEmpty()); 297 { 298 v8::HandleScope handle_scope(v8_isolate); 299 v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); 300 } 301 // Make sure all builtin scripts are cached. 302 { 303 HandleScope scope(isolate); 304 for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { 305 isolate->bootstrapper()->SourceLookup<Natives>(i); 306 } 307 } 308 heap->CollectAllGarbage(); 309 heap->CollectAllGarbage(); 310 311 Object* raw_foo; 312 { 313 v8::HandleScope handle_scope(v8_isolate); 314 v8::Local<v8::String> foo = v8_str("foo"); 315 CHECK(!foo.IsEmpty()); 316 raw_foo = *(v8::Utils::OpenHandle(*foo)); 317 } 318 319 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; 320 Vector<char> startup_name = Vector<char>::New(file_name_length + 1); 321 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); 322 323 { 324 v8::HandleScope handle_scope(v8_isolate); 325 v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); 326 } 327 env.Reset(); 328 329 SnapshotByteSink startup_sink; 330 StartupSerializer startup_serializer(isolate, &startup_sink); 331 startup_serializer.SerializeStrongReferences(); 332 333 SnapshotByteSink partial_sink; 334 PartialSerializer partial_serializer(isolate, &startup_serializer, 335 &partial_sink); 336 partial_serializer.Serialize(&raw_foo); 337 338 startup_serializer.SerializeWeakReferencesAndDeferred(); 339 340 SnapshotData startup_snapshot(startup_serializer); 341 SnapshotData partial_snapshot(partial_serializer); 342 343 WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file); 344 WritePayload(startup_snapshot.RawData(), startup_name.start()); 345 346 startup_name.Dispose(); 347 } 348 v8_isolate->Exit(); 349 v8_isolate->Dispose(); 350 } 351 352 353 UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization, PartialSerialization) { 354 DisableTurbofan(); 355 if (DefaultSnapshotAvailable()) return; 356 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; 357 Vector<char> startup_name = Vector<char>::New(file_name_length + 1); 358 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); 359 360 v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start()); 361 CHECK(v8_isolate); 362 startup_name.Dispose(); 363 { 364 v8::Isolate::Scope isolate_scope(v8_isolate); 365 366 const char* file_name = FLAG_testing_serialization_file; 367 368 int snapshot_size = 0; 369 byte* snapshot = ReadBytes(file_name, &snapshot_size); 370 371 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 372 HandleScope handle_scope(isolate); 373 Handle<Object> root; 374 // Intentionally empty handle. The deserializer should not come across 375 // any references to the global proxy in this test. 376 Handle<JSGlobalProxy> global_proxy = Handle<JSGlobalProxy>::null(); 377 { 378 SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); 379 Deserializer deserializer(&snapshot_data); 380 root = deserializer.DeserializePartial(isolate, global_proxy) 381 .ToHandleChecked(); 382 CHECK(root->IsString()); 383 } 384 385 Handle<Object> root2; 386 { 387 SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); 388 Deserializer deserializer(&snapshot_data); 389 root2 = deserializer.DeserializePartial(isolate, global_proxy) 390 .ToHandleChecked(); 391 CHECK(root2->IsString()); 392 CHECK(root.is_identical_to(root2)); 393 } 394 395 DeleteArray(snapshot); 396 } 397 v8_isolate->Dispose(); 398 } 399 400 401 UNINITIALIZED_TEST(ContextSerialization) { 402 DisableTurbofan(); 403 if (DefaultSnapshotAvailable()) return; 404 v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); 405 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 406 Heap* heap = isolate->heap(); 407 { 408 v8::Isolate::Scope isolate_scope(v8_isolate); 409 410 v8::Persistent<v8::Context> env; 411 { 412 HandleScope scope(isolate); 413 env.Reset(v8_isolate, v8::Context::New(v8_isolate)); 414 } 415 CHECK(!env.IsEmpty()); 416 { 417 v8::HandleScope handle_scope(v8_isolate); 418 v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); 419 } 420 // Make sure all builtin scripts are cached. 421 { 422 HandleScope scope(isolate); 423 for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { 424 isolate->bootstrapper()->SourceLookup<Natives>(i); 425 } 426 } 427 // If we don't do this then we end up with a stray root pointing at the 428 // context even after we have disposed of env. 429 heap->CollectAllGarbage(); 430 431 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; 432 Vector<char> startup_name = Vector<char>::New(file_name_length + 1); 433 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); 434 435 { 436 v8::HandleScope handle_scope(v8_isolate); 437 v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); 438 } 439 440 i::Object* raw_context = *v8::Utils::OpenPersistent(env); 441 442 env.Reset(); 443 444 SnapshotByteSink startup_sink; 445 StartupSerializer startup_serializer(isolate, &startup_sink); 446 startup_serializer.SerializeStrongReferences(); 447 448 SnapshotByteSink partial_sink; 449 PartialSerializer partial_serializer(isolate, &startup_serializer, 450 &partial_sink); 451 partial_serializer.Serialize(&raw_context); 452 startup_serializer.SerializeWeakReferencesAndDeferred(); 453 454 SnapshotData startup_snapshot(startup_serializer); 455 SnapshotData partial_snapshot(partial_serializer); 456 457 WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file); 458 WritePayload(startup_snapshot.RawData(), startup_name.start()); 459 460 startup_name.Dispose(); 461 } 462 v8_isolate->Dispose(); 463 } 464 465 466 UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization, ContextSerialization) { 467 DisableTurbofan(); 468 if (DefaultSnapshotAvailable()) return; 469 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; 470 Vector<char> startup_name = Vector<char>::New(file_name_length + 1); 471 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); 472 473 v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start()); 474 CHECK(v8_isolate); 475 startup_name.Dispose(); 476 { 477 v8::Isolate::Scope isolate_scope(v8_isolate); 478 479 const char* file_name = FLAG_testing_serialization_file; 480 481 int snapshot_size = 0; 482 byte* snapshot = ReadBytes(file_name, &snapshot_size); 483 484 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 485 HandleScope handle_scope(isolate); 486 Handle<Object> root; 487 Handle<JSGlobalProxy> global_proxy = 488 isolate->factory()->NewUninitializedJSGlobalProxy(); 489 { 490 SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); 491 Deserializer deserializer(&snapshot_data); 492 root = deserializer.DeserializePartial(isolate, global_proxy) 493 .ToHandleChecked(); 494 CHECK(root->IsContext()); 495 CHECK(Handle<Context>::cast(root)->global_proxy() == *global_proxy); 496 } 497 498 Handle<Object> root2; 499 { 500 SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); 501 Deserializer deserializer(&snapshot_data); 502 root2 = deserializer.DeserializePartial(isolate, global_proxy) 503 .ToHandleChecked(); 504 CHECK(root2->IsContext()); 505 CHECK(!root.is_identical_to(root2)); 506 } 507 DeleteArray(snapshot); 508 } 509 v8_isolate->Dispose(); 510 } 511 512 513 UNINITIALIZED_TEST(CustomContextSerialization) { 514 DisableTurbofan(); 515 if (DefaultSnapshotAvailable()) return; 516 v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); 517 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 518 { 519 v8::Isolate::Scope isolate_scope(v8_isolate); 520 521 v8::Persistent<v8::Context> env; 522 { 523 HandleScope scope(isolate); 524 env.Reset(v8_isolate, v8::Context::New(v8_isolate)); 525 } 526 CHECK(!env.IsEmpty()); 527 { 528 v8::HandleScope handle_scope(v8_isolate); 529 v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); 530 // After execution, e's function context refers to the global object. 531 CompileRun( 532 "var e;" 533 "(function() {" 534 " e = function(s) { return eval (s); }" 535 "})();" 536 "var o = this;" 537 "var r = Math.sin(0) + Math.cos(0);" 538 "var f = (function(a, b) { return a + b; }).bind(1, 2, 3);" 539 "var s = parseInt('12345');"); 540 541 Vector<const uint8_t> source = ConstructSource( 542 STATIC_CHAR_VECTOR("function g() { return [,"), 543 STATIC_CHAR_VECTOR("1,"), 544 STATIC_CHAR_VECTOR("];} a = g(); b = g(); b.push(1);"), 100000); 545 v8::MaybeLocal<v8::String> source_str = v8::String::NewFromOneByte( 546 v8_isolate, source.start(), v8::NewStringType::kNormal, 547 source.length()); 548 CompileRun(source_str.ToLocalChecked()); 549 source.Dispose(); 550 } 551 // Make sure all builtin scripts are cached. 552 { 553 HandleScope scope(isolate); 554 for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { 555 isolate->bootstrapper()->SourceLookup<Natives>(i); 556 } 557 } 558 // If we don't do this then we end up with a stray root pointing at the 559 // context even after we have disposed of env. 560 isolate->heap()->CollectAllAvailableGarbage("snapshotting"); 561 562 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; 563 Vector<char> startup_name = Vector<char>::New(file_name_length + 1); 564 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); 565 566 { 567 v8::HandleScope handle_scope(v8_isolate); 568 v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); 569 } 570 571 i::Object* raw_context = *v8::Utils::OpenPersistent(env); 572 573 env.Reset(); 574 575 SnapshotByteSink startup_sink; 576 StartupSerializer startup_serializer(isolate, &startup_sink); 577 startup_serializer.SerializeStrongReferences(); 578 579 SnapshotByteSink partial_sink; 580 PartialSerializer partial_serializer(isolate, &startup_serializer, 581 &partial_sink); 582 partial_serializer.Serialize(&raw_context); 583 startup_serializer.SerializeWeakReferencesAndDeferred(); 584 585 SnapshotData startup_snapshot(startup_serializer); 586 SnapshotData partial_snapshot(partial_serializer); 587 588 WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file); 589 WritePayload(startup_snapshot.RawData(), startup_name.start()); 590 591 startup_name.Dispose(); 592 } 593 v8_isolate->Dispose(); 594 } 595 596 597 UNINITIALIZED_DEPENDENT_TEST(CustomContextDeserialization, 598 CustomContextSerialization) { 599 DisableTurbofan(); 600 FLAG_crankshaft = false; 601 if (DefaultSnapshotAvailable()) return; 602 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; 603 Vector<char> startup_name = Vector<char>::New(file_name_length + 1); 604 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); 605 606 v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start()); 607 CHECK(v8_isolate); 608 startup_name.Dispose(); 609 { 610 v8::Isolate::Scope isolate_scope(v8_isolate); 611 612 const char* file_name = FLAG_testing_serialization_file; 613 614 int snapshot_size = 0; 615 byte* snapshot = ReadBytes(file_name, &snapshot_size); 616 617 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 618 HandleScope handle_scope(isolate); 619 Handle<Object> root; 620 Handle<JSGlobalProxy> global_proxy = 621 isolate->factory()->NewUninitializedJSGlobalProxy(); 622 { 623 SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); 624 Deserializer deserializer(&snapshot_data); 625 root = deserializer.DeserializePartial(isolate, global_proxy) 626 .ToHandleChecked(); 627 CHECK(root->IsContext()); 628 Handle<Context> context = Handle<Context>::cast(root); 629 CHECK(context->global_proxy() == *global_proxy); 630 Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o"); 631 Handle<JSObject> global_object(context->global_object(), isolate); 632 Handle<Object> property = JSReceiver::GetDataProperty(global_object, o); 633 CHECK(property.is_identical_to(global_proxy)); 634 635 v8::Local<v8::Context> v8_context = v8::Utils::ToLocal(context); 636 v8::Context::Scope context_scope(v8_context); 637 double r = CompileRun("r") 638 ->ToNumber(v8_isolate->GetCurrentContext()) 639 .ToLocalChecked() 640 ->Value(); 641 CHECK_EQ(1, r); 642 int f = CompileRun("f()") 643 ->ToNumber(v8_isolate->GetCurrentContext()) 644 .ToLocalChecked() 645 ->Int32Value(v8_isolate->GetCurrentContext()) 646 .FromJust(); 647 CHECK_EQ(5, f); 648 f = CompileRun("e('f()')") 649 ->ToNumber(v8_isolate->GetCurrentContext()) 650 .ToLocalChecked() 651 ->Int32Value(v8_isolate->GetCurrentContext()) 652 .FromJust(); 653 CHECK_EQ(5, f); 654 v8::Local<v8::String> s = CompileRun("s") 655 ->ToString(v8_isolate->GetCurrentContext()) 656 .ToLocalChecked(); 657 CHECK(s->Equals(v8_isolate->GetCurrentContext(), v8_str("12345")) 658 .FromJust()); 659 int a = CompileRun("a.length") 660 ->ToNumber(v8_isolate->GetCurrentContext()) 661 .ToLocalChecked() 662 ->Int32Value(v8_isolate->GetCurrentContext()) 663 .FromJust(); 664 CHECK_EQ(100001, a); 665 int b = CompileRun("b.length") 666 ->ToNumber(v8_isolate->GetCurrentContext()) 667 .ToLocalChecked() 668 ->Int32Value(v8_isolate->GetCurrentContext()) 669 .FromJust(); 670 CHECK_EQ(100002, b); 671 } 672 DeleteArray(snapshot); 673 } 674 v8_isolate->Dispose(); 675 } 676 677 678 TEST(PerIsolateSnapshotBlobs) { 679 DisableTurbofan(); 680 const char* source1 = "function f() { return 42; }"; 681 const char* source2 = 682 "function f() { return g() * 2; }" 683 "function g() { return 43; }" 684 "/./.test('a')"; 685 686 v8::StartupData data1 = v8::V8::CreateSnapshotDataBlob(source1); 687 v8::StartupData data2 = v8::V8::CreateSnapshotDataBlob(source2); 688 689 v8::Isolate::CreateParams params1; 690 params1.snapshot_blob = &data1; 691 params1.array_buffer_allocator = CcTest::array_buffer_allocator(); 692 693 v8::Isolate* isolate1 = v8::Isolate::New(params1); 694 { 695 v8::Isolate::Scope i_scope(isolate1); 696 v8::HandleScope h_scope(isolate1); 697 v8::Local<v8::Context> context = v8::Context::New(isolate1); 698 delete[] data1.data; // We can dispose of the snapshot blob now. 699 v8::Context::Scope c_scope(context); 700 v8::Maybe<int32_t> result = 701 CompileRun("f()")->Int32Value(isolate1->GetCurrentContext()); 702 CHECK_EQ(42, result.FromJust()); 703 CHECK(CompileRun("this.g")->IsUndefined()); 704 } 705 isolate1->Dispose(); 706 707 v8::Isolate::CreateParams params2; 708 params2.snapshot_blob = &data2; 709 params2.array_buffer_allocator = CcTest::array_buffer_allocator(); 710 v8::Isolate* isolate2 = v8::Isolate::New(params2); 711 { 712 v8::Isolate::Scope i_scope(isolate2); 713 v8::HandleScope h_scope(isolate2); 714 v8::Local<v8::Context> context = v8::Context::New(isolate2); 715 delete[] data2.data; // We can dispose of the snapshot blob now. 716 v8::Context::Scope c_scope(context); 717 v8::Maybe<int32_t> result = 718 CompileRun("f()")->Int32Value(isolate2->GetCurrentContext()); 719 CHECK_EQ(86, result.FromJust()); 720 result = CompileRun("g()")->Int32Value(isolate2->GetCurrentContext()); 721 CHECK_EQ(43, result.FromJust()); 722 } 723 isolate2->Dispose(); 724 } 725 726 727 static void SerializationFunctionTemplate( 728 const v8::FunctionCallbackInfo<v8::Value>& args) { 729 args.GetReturnValue().Set(args[0]); 730 } 731 732 733 TEST(PerIsolateSnapshotBlobsOutdatedContextWithOverflow) { 734 DisableTurbofan(); 735 736 const char* source1 = 737 "var o = {};" 738 "(function() {" 739 " function f1(x) { return f2(x) instanceof Array; }" 740 " function f2(x) { return foo.bar(x); }" 741 " o.a = f2.bind(null);" 742 " o.b = 1;" 743 " o.c = 2;" 744 " o.d = 3;" 745 " o.e = 4;" 746 "})();\n"; 747 748 const char* source2 = "o.a(42)"; 749 750 v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source1); 751 752 v8::Isolate::CreateParams params; 753 params.snapshot_blob = &data; 754 params.array_buffer_allocator = CcTest::array_buffer_allocator(); 755 756 v8::Isolate* isolate = v8::Isolate::New(params); 757 { 758 v8::Isolate::Scope i_scope(isolate); 759 v8::HandleScope h_scope(isolate); 760 761 v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); 762 v8::Local<v8::ObjectTemplate> property = v8::ObjectTemplate::New(isolate); 763 v8::Local<v8::FunctionTemplate> function = 764 v8::FunctionTemplate::New(isolate, SerializationFunctionTemplate); 765 property->Set(isolate, "bar", function); 766 global->Set(isolate, "foo", property); 767 768 v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global); 769 delete[] data.data; // We can dispose of the snapshot blob now. 770 v8::Context::Scope c_scope(context); 771 v8::Local<v8::Value> result = CompileRun(source2); 772 v8::Maybe<bool> compare = v8_str("42")->Equals( 773 v8::Isolate::GetCurrent()->GetCurrentContext(), result); 774 CHECK(compare.FromJust()); 775 } 776 isolate->Dispose(); 777 } 778 779 780 TEST(PerIsolateSnapshotBlobsWithLocker) { 781 DisableTurbofan(); 782 v8::Isolate::CreateParams create_params; 783 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 784 v8::Isolate* isolate0 = v8::Isolate::New(create_params); 785 { 786 v8::Locker locker(isolate0); 787 v8::Isolate::Scope i_scope(isolate0); 788 v8::HandleScope h_scope(isolate0); 789 v8::Local<v8::Context> context = v8::Context::New(isolate0); 790 v8::Context::Scope c_scope(context); 791 v8::Maybe<int32_t> result = 792 CompileRun("Math.cos(0)")->Int32Value(isolate0->GetCurrentContext()); 793 CHECK_EQ(1, result.FromJust()); 794 } 795 isolate0->Dispose(); 796 797 const char* source1 = "function f() { return 42; }"; 798 799 v8::StartupData data1 = v8::V8::CreateSnapshotDataBlob(source1); 800 801 v8::Isolate::CreateParams params1; 802 params1.snapshot_blob = &data1; 803 params1.array_buffer_allocator = CcTest::array_buffer_allocator(); 804 v8::Isolate* isolate1 = v8::Isolate::New(params1); 805 { 806 v8::Locker locker(isolate1); 807 v8::Isolate::Scope i_scope(isolate1); 808 v8::HandleScope h_scope(isolate1); 809 v8::Local<v8::Context> context = v8::Context::New(isolate1); 810 delete[] data1.data; // We can dispose of the snapshot blob now. 811 v8::Context::Scope c_scope(context); 812 v8::Maybe<int32_t> result = CompileRun("f()")->Int32Value(context); 813 CHECK_EQ(42, result.FromJust()); 814 } 815 isolate1->Dispose(); 816 } 817 818 819 TEST(SnapshotBlobsStackOverflow) { 820 DisableTurbofan(); 821 const char* source = 822 "var a = [0];" 823 "var b = a;" 824 "for (var i = 0; i < 10000; i++) {" 825 " var c = [i];" 826 " b.push(c);" 827 " b.push(c);" 828 " b = c;" 829 "}"; 830 831 v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source); 832 833 v8::Isolate::CreateParams params; 834 params.snapshot_blob = &data; 835 params.array_buffer_allocator = CcTest::array_buffer_allocator(); 836 837 v8::Isolate* isolate = v8::Isolate::New(params); 838 { 839 v8::Isolate::Scope i_scope(isolate); 840 v8::HandleScope h_scope(isolate); 841 v8::Local<v8::Context> context = v8::Context::New(isolate); 842 delete[] data.data; // We can dispose of the snapshot blob now. 843 v8::Context::Scope c_scope(context); 844 const char* test = 845 "var sum = 0;" 846 "while (a) {" 847 " sum += a[0];" 848 " a = a[1];" 849 "}" 850 "sum"; 851 v8::Maybe<int32_t> result = 852 CompileRun(test)->Int32Value(isolate->GetCurrentContext()); 853 CHECK_EQ(9999 * 5000, result.FromJust()); 854 } 855 isolate->Dispose(); 856 } 857 858 859 TEST(TestThatAlwaysSucceeds) { 860 } 861 862 863 TEST(TestThatAlwaysFails) { 864 bool ArtificialFailure = false; 865 CHECK(ArtificialFailure); 866 } 867 868 869 DEPENDENT_TEST(DependentTestThatAlwaysFails, TestThatAlwaysSucceeds) { 870 bool ArtificialFailure2 = false; 871 CHECK(ArtificialFailure2); 872 } 873 874 875 int CountBuiltins() { 876 // Check that we have not deserialized any additional builtin. 877 HeapIterator iterator(CcTest::heap()); 878 DisallowHeapAllocation no_allocation; 879 int counter = 0; 880 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { 881 if (obj->IsCode() && Code::cast(obj)->kind() == Code::BUILTIN) counter++; 882 } 883 return counter; 884 } 885 886 887 static Handle<SharedFunctionInfo> CompileScript( 888 Isolate* isolate, Handle<String> source, Handle<String> name, 889 ScriptData** cached_data, v8::ScriptCompiler::CompileOptions options) { 890 return Compiler::CompileScript( 891 source, name, 0, 0, v8::ScriptOriginOptions(), Handle<Object>(), 892 Handle<Context>(isolate->native_context()), NULL, cached_data, options, 893 NOT_NATIVES_CODE, false); 894 } 895 896 897 TEST(SerializeToplevelOnePlusOne) { 898 FLAG_serialize_toplevel = true; 899 LocalContext context; 900 Isolate* isolate = CcTest::i_isolate(); 901 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 902 903 v8::HandleScope scope(CcTest::isolate()); 904 905 const char* source = "1 + 1"; 906 907 Handle<String> orig_source = isolate->factory() 908 ->NewStringFromUtf8(CStrVector(source)) 909 .ToHandleChecked(); 910 Handle<String> copy_source = isolate->factory() 911 ->NewStringFromUtf8(CStrVector(source)) 912 .ToHandleChecked(); 913 CHECK(!orig_source.is_identical_to(copy_source)); 914 CHECK(orig_source->Equals(*copy_source)); 915 916 ScriptData* cache = NULL; 917 918 Handle<SharedFunctionInfo> orig = 919 CompileScript(isolate, orig_source, Handle<String>(), &cache, 920 v8::ScriptCompiler::kProduceCodeCache); 921 922 int builtins_count = CountBuiltins(); 923 924 Handle<SharedFunctionInfo> copy; 925 { 926 DisallowCompilation no_compile_expected(isolate); 927 copy = CompileScript(isolate, copy_source, Handle<String>(), &cache, 928 v8::ScriptCompiler::kConsumeCodeCache); 929 } 930 931 CHECK_NE(*orig, *copy); 932 CHECK(Script::cast(copy->script())->source() == *copy_source); 933 934 Handle<JSFunction> copy_fun = 935 isolate->factory()->NewFunctionFromSharedFunctionInfo( 936 copy, isolate->native_context()); 937 Handle<JSObject> global(isolate->context()->global_object()); 938 Handle<Object> copy_result = 939 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 940 CHECK_EQ(2, Handle<Smi>::cast(copy_result)->value()); 941 942 CHECK_EQ(builtins_count, CountBuiltins()); 943 944 delete cache; 945 } 946 947 948 TEST(CodeCachePromotedToCompilationCache) { 949 FLAG_serialize_toplevel = true; 950 LocalContext context; 951 Isolate* isolate = CcTest::i_isolate(); 952 953 v8::HandleScope scope(CcTest::isolate()); 954 955 const char* source = "1 + 1"; 956 957 Handle<String> src = isolate->factory() 958 ->NewStringFromUtf8(CStrVector(source)) 959 .ToHandleChecked(); 960 ScriptData* cache = NULL; 961 962 CompileScript(isolate, src, src, &cache, 963 v8::ScriptCompiler::kProduceCodeCache); 964 965 DisallowCompilation no_compile_expected(isolate); 966 Handle<SharedFunctionInfo> copy = CompileScript( 967 isolate, src, src, &cache, v8::ScriptCompiler::kConsumeCodeCache); 968 969 CHECK(isolate->compilation_cache() 970 ->LookupScript(src, src, 0, 0, v8::ScriptOriginOptions(), 971 isolate->native_context(), SLOPPY) 972 .ToHandleChecked() 973 .is_identical_to(copy)); 974 975 delete cache; 976 } 977 978 979 TEST(SerializeToplevelInternalizedString) { 980 FLAG_serialize_toplevel = true; 981 LocalContext context; 982 Isolate* isolate = CcTest::i_isolate(); 983 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 984 985 v8::HandleScope scope(CcTest::isolate()); 986 987 const char* source = "'string1'"; 988 989 Handle<String> orig_source = isolate->factory() 990 ->NewStringFromUtf8(CStrVector(source)) 991 .ToHandleChecked(); 992 Handle<String> copy_source = isolate->factory() 993 ->NewStringFromUtf8(CStrVector(source)) 994 .ToHandleChecked(); 995 CHECK(!orig_source.is_identical_to(copy_source)); 996 CHECK(orig_source->Equals(*copy_source)); 997 998 Handle<JSObject> global(isolate->context()->global_object()); 999 ScriptData* cache = NULL; 1000 1001 Handle<SharedFunctionInfo> orig = 1002 CompileScript(isolate, orig_source, Handle<String>(), &cache, 1003 v8::ScriptCompiler::kProduceCodeCache); 1004 Handle<JSFunction> orig_fun = 1005 isolate->factory()->NewFunctionFromSharedFunctionInfo( 1006 orig, isolate->native_context()); 1007 Handle<Object> orig_result = 1008 Execution::Call(isolate, orig_fun, global, 0, NULL).ToHandleChecked(); 1009 CHECK(orig_result->IsInternalizedString()); 1010 1011 int builtins_count = CountBuiltins(); 1012 1013 Handle<SharedFunctionInfo> copy; 1014 { 1015 DisallowCompilation no_compile_expected(isolate); 1016 copy = CompileScript(isolate, copy_source, Handle<String>(), &cache, 1017 v8::ScriptCompiler::kConsumeCodeCache); 1018 } 1019 CHECK_NE(*orig, *copy); 1020 CHECK(Script::cast(copy->script())->source() == *copy_source); 1021 1022 Handle<JSFunction> copy_fun = 1023 isolate->factory()->NewFunctionFromSharedFunctionInfo( 1024 copy, isolate->native_context()); 1025 CHECK_NE(*orig_fun, *copy_fun); 1026 Handle<Object> copy_result = 1027 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 1028 CHECK(orig_result.is_identical_to(copy_result)); 1029 Handle<String> expected = 1030 isolate->factory()->NewStringFromAsciiChecked("string1"); 1031 1032 CHECK(Handle<String>::cast(copy_result)->Equals(*expected)); 1033 CHECK_EQ(builtins_count, CountBuiltins()); 1034 1035 delete cache; 1036 } 1037 1038 1039 TEST(SerializeToplevelLargeCodeObject) { 1040 FLAG_serialize_toplevel = true; 1041 LocalContext context; 1042 Isolate* isolate = CcTest::i_isolate(); 1043 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1044 1045 v8::HandleScope scope(CcTest::isolate()); 1046 1047 Vector<const uint8_t> source = 1048 ConstructSource(STATIC_CHAR_VECTOR("var j=1; try { if (j) throw 1;"), 1049 STATIC_CHAR_VECTOR("for(var i=0;i<1;i++)j++;"), 1050 STATIC_CHAR_VECTOR("} catch (e) { j=7; } j"), 10000); 1051 Handle<String> source_str = 1052 isolate->factory()->NewStringFromOneByte(source).ToHandleChecked(); 1053 1054 Handle<JSObject> global(isolate->context()->global_object()); 1055 ScriptData* cache = NULL; 1056 1057 Handle<SharedFunctionInfo> orig = 1058 CompileScript(isolate, source_str, Handle<String>(), &cache, 1059 v8::ScriptCompiler::kProduceCodeCache); 1060 1061 CHECK(isolate->heap()->InSpace(orig->code(), LO_SPACE)); 1062 1063 Handle<SharedFunctionInfo> copy; 1064 { 1065 DisallowCompilation no_compile_expected(isolate); 1066 copy = CompileScript(isolate, source_str, Handle<String>(), &cache, 1067 v8::ScriptCompiler::kConsumeCodeCache); 1068 } 1069 CHECK_NE(*orig, *copy); 1070 1071 Handle<JSFunction> copy_fun = 1072 isolate->factory()->NewFunctionFromSharedFunctionInfo( 1073 copy, isolate->native_context()); 1074 1075 Handle<Object> copy_result = 1076 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 1077 1078 int result_int; 1079 CHECK(copy_result->ToInt32(&result_int)); 1080 CHECK_EQ(7, result_int); 1081 1082 delete cache; 1083 source.Dispose(); 1084 } 1085 1086 1087 TEST(SerializeToplevelLargeStrings) { 1088 FLAG_serialize_toplevel = true; 1089 LocalContext context; 1090 Isolate* isolate = CcTest::i_isolate(); 1091 Factory* f = isolate->factory(); 1092 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1093 1094 v8::HandleScope scope(CcTest::isolate()); 1095 1096 Vector<const uint8_t> source_s = ConstructSource( 1097 STATIC_CHAR_VECTOR("var s = \""), STATIC_CHAR_VECTOR("abcdef"), 1098 STATIC_CHAR_VECTOR("\";"), 1000000); 1099 Vector<const uint8_t> source_t = ConstructSource( 1100 STATIC_CHAR_VECTOR("var t = \""), STATIC_CHAR_VECTOR("uvwxyz"), 1101 STATIC_CHAR_VECTOR("\"; s + t"), 999999); 1102 Handle<String> source_str = 1103 f->NewConsString(f->NewStringFromOneByte(source_s).ToHandleChecked(), 1104 f->NewStringFromOneByte(source_t).ToHandleChecked()) 1105 .ToHandleChecked(); 1106 1107 Handle<JSObject> global(isolate->context()->global_object()); 1108 ScriptData* cache = NULL; 1109 1110 Handle<SharedFunctionInfo> orig = 1111 CompileScript(isolate, source_str, Handle<String>(), &cache, 1112 v8::ScriptCompiler::kProduceCodeCache); 1113 1114 Handle<SharedFunctionInfo> copy; 1115 { 1116 DisallowCompilation no_compile_expected(isolate); 1117 copy = CompileScript(isolate, source_str, Handle<String>(), &cache, 1118 v8::ScriptCompiler::kConsumeCodeCache); 1119 } 1120 CHECK_NE(*orig, *copy); 1121 1122 Handle<JSFunction> copy_fun = 1123 isolate->factory()->NewFunctionFromSharedFunctionInfo( 1124 copy, isolate->native_context()); 1125 1126 Handle<Object> copy_result = 1127 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 1128 1129 CHECK_EQ(6 * 1999999, Handle<String>::cast(copy_result)->length()); 1130 Handle<Object> property = JSReceiver::GetDataProperty( 1131 isolate->global_object(), f->NewStringFromAsciiChecked("s")); 1132 CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE)); 1133 property = JSReceiver::GetDataProperty(isolate->global_object(), 1134 f->NewStringFromAsciiChecked("t")); 1135 CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE)); 1136 // Make sure we do not serialize too much, e.g. include the source string. 1137 CHECK_LT(cache->length(), 13000000); 1138 1139 delete cache; 1140 source_s.Dispose(); 1141 source_t.Dispose(); 1142 } 1143 1144 1145 TEST(SerializeToplevelThreeBigStrings) { 1146 FLAG_serialize_toplevel = true; 1147 LocalContext context; 1148 Isolate* isolate = CcTest::i_isolate(); 1149 Factory* f = isolate->factory(); 1150 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1151 1152 v8::HandleScope scope(CcTest::isolate()); 1153 1154 Vector<const uint8_t> source_a = 1155 ConstructSource(STATIC_CHAR_VECTOR("var a = \""), STATIC_CHAR_VECTOR("a"), 1156 STATIC_CHAR_VECTOR("\";"), 700000); 1157 Handle<String> source_a_str = 1158 f->NewStringFromOneByte(source_a).ToHandleChecked(); 1159 1160 Vector<const uint8_t> source_b = 1161 ConstructSource(STATIC_CHAR_VECTOR("var b = \""), STATIC_CHAR_VECTOR("b"), 1162 STATIC_CHAR_VECTOR("\";"), 600000); 1163 Handle<String> source_b_str = 1164 f->NewStringFromOneByte(source_b).ToHandleChecked(); 1165 1166 Vector<const uint8_t> source_c = 1167 ConstructSource(STATIC_CHAR_VECTOR("var c = \""), STATIC_CHAR_VECTOR("c"), 1168 STATIC_CHAR_VECTOR("\";"), 500000); 1169 Handle<String> source_c_str = 1170 f->NewStringFromOneByte(source_c).ToHandleChecked(); 1171 1172 Handle<String> source_str = 1173 f->NewConsString( 1174 f->NewConsString(source_a_str, source_b_str).ToHandleChecked(), 1175 source_c_str).ToHandleChecked(); 1176 1177 Handle<JSObject> global(isolate->context()->global_object()); 1178 ScriptData* cache = NULL; 1179 1180 Handle<SharedFunctionInfo> orig = 1181 CompileScript(isolate, source_str, Handle<String>(), &cache, 1182 v8::ScriptCompiler::kProduceCodeCache); 1183 1184 Handle<SharedFunctionInfo> copy; 1185 { 1186 DisallowCompilation no_compile_expected(isolate); 1187 copy = CompileScript(isolate, source_str, Handle<String>(), &cache, 1188 v8::ScriptCompiler::kConsumeCodeCache); 1189 } 1190 CHECK_NE(*orig, *copy); 1191 1192 Handle<JSFunction> copy_fun = 1193 isolate->factory()->NewFunctionFromSharedFunctionInfo( 1194 copy, isolate->native_context()); 1195 1196 USE(Execution::Call(isolate, copy_fun, global, 0, NULL)); 1197 1198 v8::Maybe<int32_t> result = 1199 CompileRun("(a + b).length") 1200 ->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext()); 1201 CHECK_EQ(600000 + 700000, result.FromJust()); 1202 result = CompileRun("(b + c).length") 1203 ->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext()); 1204 CHECK_EQ(500000 + 600000, result.FromJust()); 1205 Heap* heap = isolate->heap(); 1206 v8::Local<v8::String> result_str = 1207 CompileRun("a") 1208 ->ToString(CcTest::isolate()->GetCurrentContext()) 1209 .ToLocalChecked(); 1210 CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), LO_SPACE)); 1211 result_str = CompileRun("b") 1212 ->ToString(CcTest::isolate()->GetCurrentContext()) 1213 .ToLocalChecked(); 1214 CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), OLD_SPACE)); 1215 result_str = CompileRun("c") 1216 ->ToString(CcTest::isolate()->GetCurrentContext()) 1217 .ToLocalChecked(); 1218 CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), OLD_SPACE)); 1219 1220 delete cache; 1221 source_a.Dispose(); 1222 source_b.Dispose(); 1223 source_c.Dispose(); 1224 } 1225 1226 1227 class SerializerOneByteResource 1228 : public v8::String::ExternalOneByteStringResource { 1229 public: 1230 SerializerOneByteResource(const char* data, size_t length) 1231 : data_(data), length_(length) {} 1232 virtual const char* data() const { return data_; } 1233 virtual size_t length() const { return length_; } 1234 1235 private: 1236 const char* data_; 1237 size_t length_; 1238 }; 1239 1240 1241 class SerializerTwoByteResource : public v8::String::ExternalStringResource { 1242 public: 1243 SerializerTwoByteResource(const char* data, size_t length) 1244 : data_(AsciiToTwoByteString(data)), length_(length) {} 1245 ~SerializerTwoByteResource() { DeleteArray<const uint16_t>(data_); } 1246 1247 virtual const uint16_t* data() const { return data_; } 1248 virtual size_t length() const { return length_; } 1249 1250 private: 1251 const uint16_t* data_; 1252 size_t length_; 1253 }; 1254 1255 1256 TEST(SerializeToplevelExternalString) { 1257 FLAG_serialize_toplevel = true; 1258 LocalContext context; 1259 Isolate* isolate = CcTest::i_isolate(); 1260 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1261 1262 v8::HandleScope scope(CcTest::isolate()); 1263 1264 // Obtain external internalized one-byte string. 1265 SerializerOneByteResource one_byte_resource("one_byte", 8); 1266 Handle<String> one_byte_string = 1267 isolate->factory()->NewStringFromAsciiChecked("one_byte"); 1268 one_byte_string = isolate->factory()->InternalizeString(one_byte_string); 1269 one_byte_string->MakeExternal(&one_byte_resource); 1270 CHECK(one_byte_string->IsExternalOneByteString()); 1271 CHECK(one_byte_string->IsInternalizedString()); 1272 1273 // Obtain external internalized two-byte string. 1274 SerializerTwoByteResource two_byte_resource("two_byte", 8); 1275 Handle<String> two_byte_string = 1276 isolate->factory()->NewStringFromAsciiChecked("two_byte"); 1277 two_byte_string = isolate->factory()->InternalizeString(two_byte_string); 1278 two_byte_string->MakeExternal(&two_byte_resource); 1279 CHECK(two_byte_string->IsExternalTwoByteString()); 1280 CHECK(two_byte_string->IsInternalizedString()); 1281 1282 const char* source = 1283 "var o = {} \n" 1284 "o.one_byte = 7; \n" 1285 "o.two_byte = 8; \n" 1286 "o.one_byte + o.two_byte; \n"; 1287 Handle<String> source_string = isolate->factory() 1288 ->NewStringFromUtf8(CStrVector(source)) 1289 .ToHandleChecked(); 1290 1291 Handle<JSObject> global(isolate->context()->global_object()); 1292 ScriptData* cache = NULL; 1293 1294 Handle<SharedFunctionInfo> orig = 1295 CompileScript(isolate, source_string, Handle<String>(), &cache, 1296 v8::ScriptCompiler::kProduceCodeCache); 1297 1298 Handle<SharedFunctionInfo> copy; 1299 { 1300 DisallowCompilation no_compile_expected(isolate); 1301 copy = CompileScript(isolate, source_string, Handle<String>(), &cache, 1302 v8::ScriptCompiler::kConsumeCodeCache); 1303 } 1304 CHECK_NE(*orig, *copy); 1305 1306 Handle<JSFunction> copy_fun = 1307 isolate->factory()->NewFunctionFromSharedFunctionInfo( 1308 copy, isolate->native_context()); 1309 1310 Handle<Object> copy_result = 1311 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 1312 1313 CHECK_EQ(15.0, copy_result->Number()); 1314 1315 delete cache; 1316 } 1317 1318 1319 TEST(SerializeToplevelLargeExternalString) { 1320 FLAG_serialize_toplevel = true; 1321 LocalContext context; 1322 Isolate* isolate = CcTest::i_isolate(); 1323 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1324 1325 Factory* f = isolate->factory(); 1326 1327 v8::HandleScope scope(CcTest::isolate()); 1328 1329 // Create a huge external internalized string to use as variable name. 1330 Vector<const uint8_t> string = 1331 ConstructSource(STATIC_CHAR_VECTOR(""), STATIC_CHAR_VECTOR("abcdef"), 1332 STATIC_CHAR_VECTOR(""), 999999); 1333 Handle<String> name = f->NewStringFromOneByte(string).ToHandleChecked(); 1334 SerializerOneByteResource one_byte_resource( 1335 reinterpret_cast<const char*>(string.start()), string.length()); 1336 name = f->InternalizeString(name); 1337 name->MakeExternal(&one_byte_resource); 1338 CHECK(name->IsExternalOneByteString()); 1339 CHECK(name->IsInternalizedString()); 1340 CHECK(isolate->heap()->InSpace(*name, LO_SPACE)); 1341 1342 // Create the source, which is "var <literal> = 42; <literal>". 1343 Handle<String> source_str = 1344 f->NewConsString( 1345 f->NewConsString(f->NewStringFromAsciiChecked("var "), name) 1346 .ToHandleChecked(), 1347 f->NewConsString(f->NewStringFromAsciiChecked(" = 42; "), name) 1348 .ToHandleChecked()).ToHandleChecked(); 1349 1350 Handle<JSObject> global(isolate->context()->global_object()); 1351 ScriptData* cache = NULL; 1352 1353 Handle<SharedFunctionInfo> orig = 1354 CompileScript(isolate, source_str, Handle<String>(), &cache, 1355 v8::ScriptCompiler::kProduceCodeCache); 1356 1357 Handle<SharedFunctionInfo> copy; 1358 { 1359 DisallowCompilation no_compile_expected(isolate); 1360 copy = CompileScript(isolate, source_str, Handle<String>(), &cache, 1361 v8::ScriptCompiler::kConsumeCodeCache); 1362 } 1363 CHECK_NE(*orig, *copy); 1364 1365 Handle<JSFunction> copy_fun = 1366 f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context()); 1367 1368 Handle<Object> copy_result = 1369 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 1370 1371 CHECK_EQ(42.0, copy_result->Number()); 1372 1373 delete cache; 1374 string.Dispose(); 1375 } 1376 1377 1378 TEST(SerializeToplevelExternalScriptName) { 1379 FLAG_serialize_toplevel = true; 1380 LocalContext context; 1381 Isolate* isolate = CcTest::i_isolate(); 1382 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1383 1384 Factory* f = isolate->factory(); 1385 1386 v8::HandleScope scope(CcTest::isolate()); 1387 1388 const char* source = 1389 "var a = [1, 2, 3, 4];" 1390 "a.reduce(function(x, y) { return x + y }, 0)"; 1391 1392 Handle<String> source_string = 1393 f->NewStringFromUtf8(CStrVector(source)).ToHandleChecked(); 1394 1395 const SerializerOneByteResource one_byte_resource("one_byte", 8); 1396 Handle<String> name = 1397 f->NewExternalStringFromOneByte(&one_byte_resource).ToHandleChecked(); 1398 CHECK(name->IsExternalOneByteString()); 1399 CHECK(!name->IsInternalizedString()); 1400 1401 Handle<JSObject> global(isolate->context()->global_object()); 1402 ScriptData* cache = NULL; 1403 1404 Handle<SharedFunctionInfo> orig = 1405 CompileScript(isolate, source_string, name, &cache, 1406 v8::ScriptCompiler::kProduceCodeCache); 1407 1408 Handle<SharedFunctionInfo> copy; 1409 { 1410 DisallowCompilation no_compile_expected(isolate); 1411 copy = CompileScript(isolate, source_string, name, &cache, 1412 v8::ScriptCompiler::kConsumeCodeCache); 1413 } 1414 CHECK_NE(*orig, *copy); 1415 1416 Handle<JSFunction> copy_fun = 1417 f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context()); 1418 1419 Handle<Object> copy_result = 1420 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 1421 1422 CHECK_EQ(10.0, copy_result->Number()); 1423 1424 delete cache; 1425 } 1426 1427 1428 static bool toplevel_test_code_event_found = false; 1429 1430 1431 static void SerializerCodeEventListener(const v8::JitCodeEvent* event) { 1432 if (event->type == v8::JitCodeEvent::CODE_ADDED && 1433 memcmp(event->name.str, "Script:~test", 12) == 0) { 1434 toplevel_test_code_event_found = true; 1435 } 1436 } 1437 1438 1439 v8::ScriptCompiler::CachedData* ProduceCache(const char* source) { 1440 v8::ScriptCompiler::CachedData* cache; 1441 v8::Isolate::CreateParams create_params; 1442 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1443 v8::Isolate* isolate1 = v8::Isolate::New(create_params); 1444 { 1445 v8::Isolate::Scope iscope(isolate1); 1446 v8::HandleScope scope(isolate1); 1447 v8::Local<v8::Context> context = v8::Context::New(isolate1); 1448 v8::Context::Scope context_scope(context); 1449 1450 v8::Local<v8::String> source_str = v8_str(source); 1451 v8::ScriptOrigin origin(v8_str("test")); 1452 v8::ScriptCompiler::Source source(source_str, origin); 1453 v8::Local<v8::UnboundScript> script = 1454 v8::ScriptCompiler::CompileUnboundScript( 1455 isolate1, &source, v8::ScriptCompiler::kProduceCodeCache) 1456 .ToLocalChecked(); 1457 const v8::ScriptCompiler::CachedData* data = source.GetCachedData(); 1458 CHECK(data); 1459 // Persist cached data. 1460 uint8_t* buffer = NewArray<uint8_t>(data->length); 1461 MemCopy(buffer, data->data, data->length); 1462 cache = new v8::ScriptCompiler::CachedData( 1463 buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned); 1464 1465 v8::Local<v8::Value> result = script->BindToCurrentContext() 1466 ->Run(isolate1->GetCurrentContext()) 1467 .ToLocalChecked(); 1468 v8::Local<v8::String> result_string = 1469 result->ToString(isolate1->GetCurrentContext()).ToLocalChecked(); 1470 CHECK(result_string->Equals(isolate1->GetCurrentContext(), v8_str("abcdef")) 1471 .FromJust()); 1472 } 1473 isolate1->Dispose(); 1474 return cache; 1475 } 1476 1477 1478 TEST(SerializeToplevelIsolates) { 1479 FLAG_serialize_toplevel = true; 1480 1481 const char* source = "function f() { return 'abc'; }; f() + 'def'"; 1482 v8::ScriptCompiler::CachedData* cache = ProduceCache(source); 1483 1484 v8::Isolate::CreateParams create_params; 1485 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1486 v8::Isolate* isolate2 = v8::Isolate::New(create_params); 1487 isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault, 1488 SerializerCodeEventListener); 1489 toplevel_test_code_event_found = false; 1490 { 1491 v8::Isolate::Scope iscope(isolate2); 1492 v8::HandleScope scope(isolate2); 1493 v8::Local<v8::Context> context = v8::Context::New(isolate2); 1494 v8::Context::Scope context_scope(context); 1495 1496 v8::Local<v8::String> source_str = v8_str(source); 1497 v8::ScriptOrigin origin(v8_str("test")); 1498 v8::ScriptCompiler::Source source(source_str, origin, cache); 1499 v8::Local<v8::UnboundScript> script; 1500 { 1501 DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2)); 1502 script = v8::ScriptCompiler::CompileUnboundScript( 1503 isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache) 1504 .ToLocalChecked(); 1505 } 1506 CHECK(!cache->rejected); 1507 v8::Local<v8::Value> result = script->BindToCurrentContext() 1508 ->Run(isolate2->GetCurrentContext()) 1509 .ToLocalChecked(); 1510 CHECK(result->ToString(isolate2->GetCurrentContext()) 1511 .ToLocalChecked() 1512 ->Equals(isolate2->GetCurrentContext(), v8_str("abcdef")) 1513 .FromJust()); 1514 } 1515 CHECK(toplevel_test_code_event_found); 1516 isolate2->Dispose(); 1517 } 1518 1519 1520 TEST(SerializeToplevelFlagChange) { 1521 FLAG_serialize_toplevel = true; 1522 1523 const char* source = "function f() { return 'abc'; }; f() + 'def'"; 1524 v8::ScriptCompiler::CachedData* cache = ProduceCache(source); 1525 1526 v8::Isolate::CreateParams create_params; 1527 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1528 v8::Isolate* isolate2 = v8::Isolate::New(create_params); 1529 1530 FLAG_allow_natives_syntax = true; // Flag change should trigger cache reject. 1531 FlagList::EnforceFlagImplications(); 1532 { 1533 v8::Isolate::Scope iscope(isolate2); 1534 v8::HandleScope scope(isolate2); 1535 v8::Local<v8::Context> context = v8::Context::New(isolate2); 1536 v8::Context::Scope context_scope(context); 1537 1538 v8::Local<v8::String> source_str = v8_str(source); 1539 v8::ScriptOrigin origin(v8_str("test")); 1540 v8::ScriptCompiler::Source source(source_str, origin, cache); 1541 v8::ScriptCompiler::CompileUnboundScript( 1542 isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache) 1543 .ToLocalChecked(); 1544 CHECK(cache->rejected); 1545 } 1546 isolate2->Dispose(); 1547 } 1548 1549 1550 TEST(SerializeToplevelBitFlip) { 1551 FLAG_serialize_toplevel = true; 1552 1553 const char* source = "function f() { return 'abc'; }; f() + 'def'"; 1554 v8::ScriptCompiler::CachedData* cache = ProduceCache(source); 1555 1556 // Random bit flip. 1557 const_cast<uint8_t*>(cache->data)[337] ^= 0x40; 1558 1559 v8::Isolate::CreateParams create_params; 1560 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1561 v8::Isolate* isolate2 = v8::Isolate::New(create_params); 1562 { 1563 v8::Isolate::Scope iscope(isolate2); 1564 v8::HandleScope scope(isolate2); 1565 v8::Local<v8::Context> context = v8::Context::New(isolate2); 1566 v8::Context::Scope context_scope(context); 1567 1568 v8::Local<v8::String> source_str = v8_str(source); 1569 v8::ScriptOrigin origin(v8_str("test")); 1570 v8::ScriptCompiler::Source source(source_str, origin, cache); 1571 v8::ScriptCompiler::CompileUnboundScript( 1572 isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache) 1573 .ToLocalChecked(); 1574 CHECK(cache->rejected); 1575 } 1576 isolate2->Dispose(); 1577 } 1578 1579 1580 TEST(SerializeWithHarmonyScoping) { 1581 FLAG_serialize_toplevel = true; 1582 1583 const char* source1 = "'use strict'; let x = 'X'"; 1584 const char* source2 = "'use strict'; let y = 'Y'"; 1585 const char* source3 = "'use strict'; x + y"; 1586 1587 v8::ScriptCompiler::CachedData* cache; 1588 1589 v8::Isolate::CreateParams create_params; 1590 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1591 v8::Isolate* isolate1 = v8::Isolate::New(create_params); 1592 { 1593 v8::Isolate::Scope iscope(isolate1); 1594 v8::HandleScope scope(isolate1); 1595 v8::Local<v8::Context> context = v8::Context::New(isolate1); 1596 v8::Context::Scope context_scope(context); 1597 1598 CompileRun(source1); 1599 CompileRun(source2); 1600 1601 v8::Local<v8::String> source_str = v8_str(source3); 1602 v8::ScriptOrigin origin(v8_str("test")); 1603 v8::ScriptCompiler::Source source(source_str, origin); 1604 v8::Local<v8::UnboundScript> script = 1605 v8::ScriptCompiler::CompileUnboundScript( 1606 isolate1, &source, v8::ScriptCompiler::kProduceCodeCache) 1607 .ToLocalChecked(); 1608 const v8::ScriptCompiler::CachedData* data = source.GetCachedData(); 1609 CHECK(data); 1610 // Persist cached data. 1611 uint8_t* buffer = NewArray<uint8_t>(data->length); 1612 MemCopy(buffer, data->data, data->length); 1613 cache = new v8::ScriptCompiler::CachedData( 1614 buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned); 1615 1616 v8::Local<v8::Value> result = script->BindToCurrentContext() 1617 ->Run(isolate1->GetCurrentContext()) 1618 .ToLocalChecked(); 1619 v8::Local<v8::String> result_str = 1620 result->ToString(isolate1->GetCurrentContext()).ToLocalChecked(); 1621 CHECK(result_str->Equals(isolate1->GetCurrentContext(), v8_str("XY")) 1622 .FromJust()); 1623 } 1624 isolate1->Dispose(); 1625 1626 v8::Isolate* isolate2 = v8::Isolate::New(create_params); 1627 { 1628 v8::Isolate::Scope iscope(isolate2); 1629 v8::HandleScope scope(isolate2); 1630 v8::Local<v8::Context> context = v8::Context::New(isolate2); 1631 v8::Context::Scope context_scope(context); 1632 1633 // Reverse order of prior running scripts. 1634 CompileRun(source2); 1635 CompileRun(source1); 1636 1637 v8::Local<v8::String> source_str = v8_str(source3); 1638 v8::ScriptOrigin origin(v8_str("test")); 1639 v8::ScriptCompiler::Source source(source_str, origin, cache); 1640 v8::Local<v8::UnboundScript> script; 1641 { 1642 DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2)); 1643 script = v8::ScriptCompiler::CompileUnboundScript( 1644 isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache) 1645 .ToLocalChecked(); 1646 } 1647 v8::Local<v8::Value> result = script->BindToCurrentContext() 1648 ->Run(isolate2->GetCurrentContext()) 1649 .ToLocalChecked(); 1650 v8::Local<v8::String> result_str = 1651 result->ToString(isolate2->GetCurrentContext()).ToLocalChecked(); 1652 CHECK(result_str->Equals(isolate2->GetCurrentContext(), v8_str("XY")) 1653 .FromJust()); 1654 } 1655 isolate2->Dispose(); 1656 } 1657 1658 1659 TEST(SerializeInternalReference) { 1660 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 1661 return; 1662 #endif 1663 // Disable experimental natives that are loaded after deserialization. 1664 FLAG_function_context_specialization = false; 1665 FLAG_always_opt = true; 1666 const char* flag = "--turbo-filter=foo"; 1667 FlagList::SetFlagsFromString(flag, StrLength(flag)); 1668 1669 const char* source = 1670 "var foo = (function(stdlib, foreign, heap) {" 1671 " function foo(i) {" 1672 " i = i|0;" 1673 " var j = 0;" 1674 " switch (i) {" 1675 " case 0:" 1676 " case 1: j = 1; break;" 1677 " case 2:" 1678 " case 3: j = 2; break;" 1679 " case 4:" 1680 " case 5: j = foo(3) + 1; break;" 1681 " default: j = 0; break;" 1682 " }" 1683 " return j + 10;" 1684 " }" 1685 " return { foo: foo };" 1686 "})(this, {}, undefined).foo;" 1687 "foo(1);"; 1688 1689 v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source); 1690 CHECK(data.data); 1691 1692 v8::Isolate::CreateParams params; 1693 params.snapshot_blob = &data; 1694 params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1695 v8::Isolate* isolate = v8::Isolate::New(params); 1696 { 1697 v8::Isolate::Scope i_scope(isolate); 1698 v8::HandleScope h_scope(isolate); 1699 v8::Local<v8::Context> context = v8::Context::New(isolate); 1700 delete[] data.data; // We can dispose of the snapshot blob now. 1701 v8::Context::Scope c_scope(context); 1702 v8::Local<v8::Function> foo = 1703 v8::Local<v8::Function>::Cast(CompileRun("foo")); 1704 1705 // There are at least 6 internal references. 1706 int mask = RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | 1707 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED); 1708 RelocIterator it( 1709 Handle<JSFunction>::cast(v8::Utils::OpenHandle(*foo))->code(), mask); 1710 for (int i = 0; i < 6; ++i) { 1711 CHECK(!it.done()); 1712 it.next(); 1713 } 1714 1715 CHECK(Handle<JSFunction>::cast(v8::Utils::OpenHandle(*foo)) 1716 ->code() 1717 ->is_turbofanned()); 1718 CHECK_EQ(11, CompileRun("foo(0)") 1719 ->Int32Value(isolate->GetCurrentContext()) 1720 .FromJust()); 1721 CHECK_EQ(11, CompileRun("foo(1)") 1722 ->Int32Value(isolate->GetCurrentContext()) 1723 .FromJust()); 1724 CHECK_EQ(12, CompileRun("foo(2)") 1725 ->Int32Value(isolate->GetCurrentContext()) 1726 .FromJust()); 1727 CHECK_EQ(12, CompileRun("foo(3)") 1728 ->Int32Value(isolate->GetCurrentContext()) 1729 .FromJust()); 1730 CHECK_EQ(23, CompileRun("foo(4)") 1731 ->Int32Value(isolate->GetCurrentContext()) 1732 .FromJust()); 1733 CHECK_EQ(23, CompileRun("foo(5)") 1734 ->Int32Value(isolate->GetCurrentContext()) 1735 .FromJust()); 1736 CHECK_EQ(10, CompileRun("foo(6)") 1737 ->Int32Value(isolate->GetCurrentContext()) 1738 .FromJust()); 1739 } 1740 isolate->Dispose(); 1741 } 1742 1743 1744 TEST(Regress503552) { 1745 // Test that the code serializer can deal with weak cells that form a linked 1746 // list during incremental marking. 1747 1748 CcTest::InitializeVM(); 1749 Isolate* isolate = CcTest::i_isolate(); 1750 1751 HandleScope scope(isolate); 1752 Handle<String> source = isolate->factory()->NewStringFromAsciiChecked( 1753 "function f() {} function g() {}"); 1754 ScriptData* script_data = NULL; 1755 Handle<SharedFunctionInfo> shared = Compiler::CompileScript( 1756 source, Handle<String>(), 0, 0, v8::ScriptOriginOptions(), 1757 Handle<Object>(), Handle<Context>(isolate->native_context()), NULL, 1758 &script_data, v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE, 1759 false); 1760 delete script_data; 1761 1762 SimulateIncrementalMarking(isolate->heap()); 1763 1764 script_data = CodeSerializer::Serialize(isolate, shared, source); 1765 delete script_data; 1766 } 1767 1768 1769 TEST(SerializationMemoryStats) { 1770 FLAG_profile_deserialization = true; 1771 FLAG_always_opt = false; 1772 v8::StartupData blob = v8::V8::CreateSnapshotDataBlob(); 1773 delete[] blob.data; 1774 } 1775