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/macro-assembler.h" 40 #include "src/objects.h" 41 #include "src/parsing/parser.h" 42 #include "src/runtime/runtime.h" 43 #include "src/snapshot/code-serializer.h" 44 #include "src/snapshot/deserializer.h" 45 #include "src/snapshot/natives.h" 46 #include "src/snapshot/partial-serializer.h" 47 #include "src/snapshot/snapshot.h" 48 #include "src/snapshot/startup-serializer.h" 49 #include "test/cctest/cctest.h" 50 #include "test/cctest/heap/heap-utils.h" 51 52 using namespace v8::internal; 53 54 void DisableTurbofan() { 55 const char* flag = "--turbo-filter=\"\""; 56 FlagList::SetFlagsFromString(flag, StrLength(flag)); 57 } 58 59 60 // TestIsolate is used for testing isolate serialization. 61 class TestIsolate : public Isolate { 62 public: 63 static v8::Isolate* NewInitialized(bool enable_serializer) { 64 i::Isolate* isolate = new TestIsolate(enable_serializer); 65 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 66 v8::Isolate::Scope isolate_scope(v8_isolate); 67 isolate->Init(NULL); 68 return v8_isolate; 69 } 70 explicit TestIsolate(bool enable_serializer) : Isolate(enable_serializer) { 71 set_array_buffer_allocator(CcTest::array_buffer_allocator()); 72 } 73 }; 74 75 static Vector<const byte> WritePayload(const Vector<const byte>& payload) { 76 int length = payload.length(); 77 byte* blob = NewArray<byte>(length); 78 memcpy(blob, payload.begin(), length); 79 return Vector<const byte>(const_cast<const byte*>(blob), length); 80 } 81 82 static Vector<const byte> Serialize(v8::Isolate* isolate) { 83 // We have to create one context. One reason for this is so that the builtins 84 // can be loaded from v8natives.js and their addresses can be processed. This 85 // will clear the pending fixups array, which would otherwise contain GC roots 86 // that would confuse the serialization/deserialization process. 87 v8::Isolate::Scope isolate_scope(isolate); 88 { 89 v8::HandleScope scope(isolate); 90 v8::Context::New(isolate); 91 } 92 93 Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate); 94 internal_isolate->heap()->CollectAllAvailableGarbage("serialize"); 95 StartupSerializer ser(internal_isolate, 96 v8::SnapshotCreator::FunctionCodeHandling::kClear); 97 ser.SerializeStrongReferences(); 98 ser.SerializeWeakReferencesAndDeferred(); 99 SnapshotData snapshot_data(&ser); 100 return WritePayload(snapshot_data.RawData()); 101 } 102 103 104 Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head, 105 Vector<const uint8_t> body, 106 Vector<const uint8_t> tail, int repeats) { 107 int source_length = head.length() + body.length() * repeats + tail.length(); 108 uint8_t* source = NewArray<uint8_t>(static_cast<size_t>(source_length)); 109 CopyChars(source, head.start(), head.length()); 110 for (int i = 0; i < repeats; i++) { 111 CopyChars(source + head.length() + i * body.length(), body.start(), 112 body.length()); 113 } 114 CopyChars(source + head.length() + repeats * body.length(), tail.start(), 115 tail.length()); 116 return Vector<const uint8_t>(const_cast<const uint8_t*>(source), 117 source_length); 118 } 119 120 v8::Isolate* InitializeFromBlob(Vector<const byte> blob) { 121 v8::Isolate* v8_isolate = NULL; 122 { 123 SnapshotData snapshot_data(blob); 124 Deserializer deserializer(&snapshot_data); 125 Isolate* isolate = new TestIsolate(false); 126 v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 127 v8::Isolate::Scope isolate_scope(v8_isolate); 128 isolate->Init(&deserializer); 129 } 130 return v8_isolate; 131 } 132 133 static v8::Isolate* Deserialize(Vector<const byte> blob) { 134 v8::Isolate* isolate = InitializeFromBlob(blob); 135 CHECK(isolate); 136 return isolate; 137 } 138 139 140 static void SanityCheck(v8::Isolate* v8_isolate) { 141 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 142 v8::HandleScope scope(v8_isolate); 143 #ifdef VERIFY_HEAP 144 isolate->heap()->Verify(); 145 #endif 146 CHECK(isolate->global_object()->IsJSObject()); 147 CHECK(isolate->native_context()->IsContext()); 148 CHECK(isolate->heap()->string_table()->IsStringTable()); 149 isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("Empty")); 150 } 151 152 UNINITIALIZED_TEST(StartupSerializerOnce) { 153 // The serialize-deserialize tests only work if the VM is built without 154 // serialization. That doesn't matter. We don't need to be able to 155 // serialize a snapshot in a VM that is booted from a snapshot. 156 DisableTurbofan(); 157 v8::Isolate* isolate = TestIsolate::NewInitialized(true); 158 Vector<const byte> blob = Serialize(isolate); 159 isolate = Deserialize(blob); 160 blob.Dispose(); 161 { 162 v8::HandleScope handle_scope(isolate); 163 v8::Isolate::Scope isolate_scope(isolate); 164 165 v8::Local<v8::Context> env = v8::Context::New(isolate); 166 env->Enter(); 167 168 SanityCheck(isolate); 169 } 170 isolate->Dispose(); 171 } 172 173 UNINITIALIZED_TEST(StartupSerializerTwice) { 174 DisableTurbofan(); 175 v8::Isolate* isolate = TestIsolate::NewInitialized(true); 176 Vector<const byte> blob1 = Serialize(isolate); 177 Vector<const byte> blob2 = Serialize(isolate); 178 blob1.Dispose(); 179 isolate = Deserialize(blob2); 180 blob2.Dispose(); 181 { 182 v8::Isolate::Scope isolate_scope(isolate); 183 v8::HandleScope handle_scope(isolate); 184 185 v8::Local<v8::Context> env = v8::Context::New(isolate); 186 env->Enter(); 187 188 SanityCheck(isolate); 189 } 190 isolate->Dispose(); 191 } 192 193 UNINITIALIZED_TEST(StartupSerializerOnceRunScript) { 194 DisableTurbofan(); 195 v8::Isolate* isolate = TestIsolate::NewInitialized(true); 196 Vector<const byte> blob = Serialize(isolate); 197 isolate = Deserialize(blob); 198 blob.Dispose(); 199 { 200 v8::Isolate::Scope isolate_scope(isolate); 201 v8::HandleScope handle_scope(isolate); 202 203 204 v8::Local<v8::Context> env = v8::Context::New(isolate); 205 env->Enter(); 206 207 const char* c_source = "\"1234\".length"; 208 v8::Local<v8::Script> script = v8_compile(c_source); 209 v8::Maybe<int32_t> result = script->Run(isolate->GetCurrentContext()) 210 .ToLocalChecked() 211 ->Int32Value(isolate->GetCurrentContext()); 212 CHECK_EQ(4, result.FromJust()); 213 } 214 isolate->Dispose(); 215 } 216 217 UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) { 218 DisableTurbofan(); 219 v8::Isolate* isolate = TestIsolate::NewInitialized(true); 220 Vector<const byte> blob1 = Serialize(isolate); 221 Vector<const byte> blob2 = Serialize(isolate); 222 blob1.Dispose(); 223 isolate = Deserialize(blob2); 224 blob2.Dispose(); 225 { 226 v8::Isolate::Scope isolate_scope(isolate); 227 v8::HandleScope handle_scope(isolate); 228 229 v8::Local<v8::Context> env = v8::Context::New(isolate); 230 env->Enter(); 231 232 const char* c_source = "\"1234\".length"; 233 v8::Local<v8::Script> script = v8_compile(c_source); 234 v8::Maybe<int32_t> result = script->Run(isolate->GetCurrentContext()) 235 .ToLocalChecked() 236 ->Int32Value(isolate->GetCurrentContext()); 237 CHECK_EQ(4, result.FromJust()); 238 } 239 isolate->Dispose(); 240 } 241 242 static void PartiallySerializeObject(Vector<const byte>* startup_blob_out, 243 Vector<const byte>* partial_blob_out) { 244 v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); 245 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 246 v8_isolate->Enter(); 247 { 248 Heap* heap = isolate->heap(); 249 250 v8::Persistent<v8::Context> env; 251 { 252 HandleScope scope(isolate); 253 env.Reset(v8_isolate, v8::Context::New(v8_isolate)); 254 } 255 CHECK(!env.IsEmpty()); 256 { 257 v8::HandleScope handle_scope(v8_isolate); 258 v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); 259 } 260 // Make sure all builtin scripts are cached. 261 { 262 HandleScope scope(isolate); 263 for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { 264 isolate->bootstrapper()->SourceLookup<Natives>(i); 265 } 266 } 267 heap->CollectAllGarbage(); 268 heap->CollectAllGarbage(); 269 270 Object* raw_foo; 271 { 272 v8::HandleScope handle_scope(v8_isolate); 273 v8::Local<v8::String> foo = v8_str("foo"); 274 CHECK(!foo.IsEmpty()); 275 raw_foo = *(v8::Utils::OpenHandle(*foo)); 276 } 277 278 { 279 v8::HandleScope handle_scope(v8_isolate); 280 v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); 281 } 282 env.Reset(); 283 284 StartupSerializer startup_serializer( 285 isolate, v8::SnapshotCreator::FunctionCodeHandling::kClear); 286 startup_serializer.SerializeStrongReferences(); 287 288 PartialSerializer partial_serializer(isolate, &startup_serializer); 289 partial_serializer.Serialize(&raw_foo); 290 291 startup_serializer.SerializeWeakReferencesAndDeferred(); 292 293 SnapshotData startup_snapshot(&startup_serializer); 294 SnapshotData partial_snapshot(&partial_serializer); 295 296 *partial_blob_out = WritePayload(partial_snapshot.RawData()); 297 *startup_blob_out = WritePayload(startup_snapshot.RawData()); 298 } 299 v8_isolate->Exit(); 300 v8_isolate->Dispose(); 301 } 302 303 UNINITIALIZED_TEST(PartialSerializerObject) { 304 DisableTurbofan(); 305 Vector<const byte> startup_blob; 306 Vector<const byte> partial_blob; 307 PartiallySerializeObject(&startup_blob, &partial_blob); 308 309 v8::Isolate* v8_isolate = InitializeFromBlob(startup_blob); 310 startup_blob.Dispose(); 311 CHECK(v8_isolate); 312 { 313 v8::Isolate::Scope isolate_scope(v8_isolate); 314 315 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 316 HandleScope handle_scope(isolate); 317 Handle<Object> root; 318 // Intentionally empty handle. The deserializer should not come across 319 // any references to the global proxy in this test. 320 Handle<JSGlobalProxy> global_proxy = Handle<JSGlobalProxy>::null(); 321 { 322 SnapshotData snapshot_data(partial_blob); 323 Deserializer deserializer(&snapshot_data); 324 root = deserializer.DeserializePartial(isolate, global_proxy) 325 .ToHandleChecked(); 326 CHECK(root->IsString()); 327 } 328 329 Handle<Object> root2; 330 { 331 SnapshotData snapshot_data(partial_blob); 332 Deserializer deserializer(&snapshot_data); 333 root2 = deserializer.DeserializePartial(isolate, global_proxy) 334 .ToHandleChecked(); 335 CHECK(root2->IsString()); 336 CHECK(root.is_identical_to(root2)); 337 } 338 partial_blob.Dispose(); 339 } 340 v8_isolate->Dispose(); 341 } 342 343 static void PartiallySerializeContext(Vector<const byte>* startup_blob_out, 344 Vector<const byte>* partial_blob_out) { 345 v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); 346 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 347 Heap* heap = isolate->heap(); 348 { 349 v8::Isolate::Scope isolate_scope(v8_isolate); 350 351 v8::Persistent<v8::Context> env; 352 { 353 HandleScope scope(isolate); 354 env.Reset(v8_isolate, v8::Context::New(v8_isolate)); 355 } 356 CHECK(!env.IsEmpty()); 357 { 358 v8::HandleScope handle_scope(v8_isolate); 359 v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); 360 } 361 // Make sure all builtin scripts are cached. 362 { 363 HandleScope scope(isolate); 364 for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { 365 isolate->bootstrapper()->SourceLookup<Natives>(i); 366 } 367 } 368 // If we don't do this then we end up with a stray root pointing at the 369 // context even after we have disposed of env. 370 heap->CollectAllGarbage(); 371 372 { 373 v8::HandleScope handle_scope(v8_isolate); 374 v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); 375 } 376 377 i::Object* raw_context = *v8::Utils::OpenPersistent(env); 378 379 env.Reset(); 380 381 SnapshotByteSink startup_sink; 382 StartupSerializer startup_serializer( 383 isolate, v8::SnapshotCreator::FunctionCodeHandling::kClear); 384 startup_serializer.SerializeStrongReferences(); 385 386 SnapshotByteSink partial_sink; 387 PartialSerializer partial_serializer(isolate, &startup_serializer); 388 partial_serializer.Serialize(&raw_context); 389 startup_serializer.SerializeWeakReferencesAndDeferred(); 390 391 SnapshotData startup_snapshot(&startup_serializer); 392 SnapshotData partial_snapshot(&partial_serializer); 393 394 *partial_blob_out = WritePayload(partial_snapshot.RawData()); 395 *startup_blob_out = WritePayload(startup_snapshot.RawData()); 396 } 397 v8_isolate->Dispose(); 398 } 399 400 UNINITIALIZED_TEST(PartialSerializerContext) { 401 DisableTurbofan(); 402 Vector<const byte> startup_blob; 403 Vector<const byte> partial_blob; 404 PartiallySerializeContext(&startup_blob, &partial_blob); 405 406 v8::Isolate* v8_isolate = InitializeFromBlob(startup_blob); 407 CHECK(v8_isolate); 408 startup_blob.Dispose(); 409 { 410 v8::Isolate::Scope isolate_scope(v8_isolate); 411 412 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 413 HandleScope handle_scope(isolate); 414 Handle<Object> root; 415 Handle<JSGlobalProxy> global_proxy = 416 isolate->factory()->NewUninitializedJSGlobalProxy(); 417 { 418 SnapshotData snapshot_data(partial_blob); 419 Deserializer deserializer(&snapshot_data); 420 root = deserializer.DeserializePartial(isolate, global_proxy) 421 .ToHandleChecked(); 422 CHECK(root->IsContext()); 423 CHECK(Handle<Context>::cast(root)->global_proxy() == *global_proxy); 424 } 425 426 Handle<Object> root2; 427 { 428 SnapshotData snapshot_data(partial_blob); 429 Deserializer deserializer(&snapshot_data); 430 root2 = deserializer.DeserializePartial(isolate, global_proxy) 431 .ToHandleChecked(); 432 CHECK(root2->IsContext()); 433 CHECK(!root.is_identical_to(root2)); 434 } 435 partial_blob.Dispose(); 436 } 437 v8_isolate->Dispose(); 438 } 439 440 static void PartiallySerializeCustomContext( 441 Vector<const byte>* startup_blob_out, 442 Vector<const byte>* partial_blob_out) { 443 v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); 444 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 445 { 446 v8::Isolate::Scope isolate_scope(v8_isolate); 447 448 v8::Persistent<v8::Context> env; 449 { 450 HandleScope scope(isolate); 451 env.Reset(v8_isolate, v8::Context::New(v8_isolate)); 452 } 453 CHECK(!env.IsEmpty()); 454 { 455 v8::HandleScope handle_scope(v8_isolate); 456 v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); 457 // After execution, e's function context refers to the global object. 458 CompileRun( 459 "var e;" 460 "(function() {" 461 " e = function(s) { return eval (s); }" 462 "})();" 463 "var o = this;" 464 "var r = Math.random();" 465 "var c = Math.sin(0) + Math.cos(0);" 466 "var f = (function(a, b) { return a + b; }).bind(1, 2, 3);" 467 "var s = parseInt('12345');"); 468 469 Vector<const uint8_t> source = ConstructSource( 470 STATIC_CHAR_VECTOR("function g() { return [,"), 471 STATIC_CHAR_VECTOR("1,"), 472 STATIC_CHAR_VECTOR("];} a = g(); b = g(); b.push(1);"), 100000); 473 v8::MaybeLocal<v8::String> source_str = v8::String::NewFromOneByte( 474 v8_isolate, source.start(), v8::NewStringType::kNormal, 475 source.length()); 476 CompileRun(source_str.ToLocalChecked()); 477 source.Dispose(); 478 } 479 // Make sure all builtin scripts are cached. 480 { 481 HandleScope scope(isolate); 482 for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { 483 isolate->bootstrapper()->SourceLookup<Natives>(i); 484 } 485 } 486 // If we don't do this then we end up with a stray root pointing at the 487 // context even after we have disposed of env. 488 isolate->heap()->CollectAllAvailableGarbage("snapshotting"); 489 490 { 491 v8::HandleScope handle_scope(v8_isolate); 492 v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); 493 } 494 495 i::Object* raw_context = *v8::Utils::OpenPersistent(env); 496 497 env.Reset(); 498 499 SnapshotByteSink startup_sink; 500 StartupSerializer startup_serializer( 501 isolate, v8::SnapshotCreator::FunctionCodeHandling::kClear); 502 startup_serializer.SerializeStrongReferences(); 503 504 SnapshotByteSink partial_sink; 505 PartialSerializer partial_serializer(isolate, &startup_serializer); 506 partial_serializer.Serialize(&raw_context); 507 startup_serializer.SerializeWeakReferencesAndDeferred(); 508 509 SnapshotData startup_snapshot(&startup_serializer); 510 SnapshotData partial_snapshot(&partial_serializer); 511 512 *partial_blob_out = WritePayload(partial_snapshot.RawData()); 513 *startup_blob_out = WritePayload(startup_snapshot.RawData()); 514 } 515 v8_isolate->Dispose(); 516 } 517 518 UNINITIALIZED_TEST(PartialSerializerCustomContext) { 519 DisableTurbofan(); 520 Vector<const byte> startup_blob; 521 Vector<const byte> partial_blob; 522 PartiallySerializeCustomContext(&startup_blob, &partial_blob); 523 524 v8::Isolate* v8_isolate = InitializeFromBlob(startup_blob); 525 CHECK(v8_isolate); 526 startup_blob.Dispose(); 527 { 528 v8::Isolate::Scope isolate_scope(v8_isolate); 529 530 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 531 HandleScope handle_scope(isolate); 532 Handle<Object> root; 533 Handle<JSGlobalProxy> global_proxy = 534 isolate->factory()->NewUninitializedJSGlobalProxy(); 535 { 536 SnapshotData snapshot_data(partial_blob); 537 Deserializer deserializer(&snapshot_data); 538 root = deserializer.DeserializePartial(isolate, global_proxy) 539 .ToHandleChecked(); 540 CHECK(root->IsContext()); 541 Handle<Context> context = Handle<Context>::cast(root); 542 543 // Add context to the weak native context list 544 context->set(Context::NEXT_CONTEXT_LINK, 545 isolate->heap()->native_contexts_list(), 546 UPDATE_WEAK_WRITE_BARRIER); 547 isolate->heap()->set_native_contexts_list(*context); 548 549 CHECK(context->global_proxy() == *global_proxy); 550 Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o"); 551 Handle<JSObject> global_object(context->global_object(), isolate); 552 Handle<Object> property = JSReceiver::GetDataProperty(global_object, o); 553 CHECK(property.is_identical_to(global_proxy)); 554 555 v8::Local<v8::Context> v8_context = v8::Utils::ToLocal(context); 556 v8::Context::Scope context_scope(v8_context); 557 double r = CompileRun("r") 558 ->ToNumber(v8_isolate->GetCurrentContext()) 559 .ToLocalChecked() 560 ->Value(); 561 CHECK(0.0 <= r && r < 1.0); 562 // Math.random still works. 563 double random = CompileRun("Math.random()") 564 ->ToNumber(v8_isolate->GetCurrentContext()) 565 .ToLocalChecked() 566 ->Value(); 567 CHECK(0.0 <= random && random < 1.0); 568 double c = CompileRun("c") 569 ->ToNumber(v8_isolate->GetCurrentContext()) 570 .ToLocalChecked() 571 ->Value(); 572 CHECK_EQ(1, c); 573 int f = CompileRun("f()") 574 ->ToNumber(v8_isolate->GetCurrentContext()) 575 .ToLocalChecked() 576 ->Int32Value(v8_isolate->GetCurrentContext()) 577 .FromJust(); 578 CHECK_EQ(5, f); 579 f = CompileRun("e('f()')") 580 ->ToNumber(v8_isolate->GetCurrentContext()) 581 .ToLocalChecked() 582 ->Int32Value(v8_isolate->GetCurrentContext()) 583 .FromJust(); 584 CHECK_EQ(5, f); 585 v8::Local<v8::String> s = CompileRun("s") 586 ->ToString(v8_isolate->GetCurrentContext()) 587 .ToLocalChecked(); 588 CHECK(s->Equals(v8_isolate->GetCurrentContext(), v8_str("12345")) 589 .FromJust()); 590 int a = CompileRun("a.length") 591 ->ToNumber(v8_isolate->GetCurrentContext()) 592 .ToLocalChecked() 593 ->Int32Value(v8_isolate->GetCurrentContext()) 594 .FromJust(); 595 CHECK_EQ(100001, a); 596 int b = CompileRun("b.length") 597 ->ToNumber(v8_isolate->GetCurrentContext()) 598 .ToLocalChecked() 599 ->Int32Value(v8_isolate->GetCurrentContext()) 600 .FromJust(); 601 CHECK_EQ(100002, b); 602 } 603 partial_blob.Dispose(); 604 } 605 v8_isolate->Dispose(); 606 } 607 608 TEST(CustomSnapshotDataBlob) { 609 DisableTurbofan(); 610 const char* source1 = "function f() { return 42; }"; 611 const char* source2 = 612 "function f() { return g() * 2; }" 613 "function g() { return 43; }" 614 "/./.test('a')"; 615 616 v8::StartupData data1 = v8::V8::CreateSnapshotDataBlob(source1); 617 v8::StartupData data2 = v8::V8::CreateSnapshotDataBlob(source2); 618 619 v8::Isolate::CreateParams params1; 620 params1.snapshot_blob = &data1; 621 params1.array_buffer_allocator = CcTest::array_buffer_allocator(); 622 623 v8::Isolate* isolate1 = v8::Isolate::New(params1); 624 { 625 v8::Isolate::Scope i_scope(isolate1); 626 v8::HandleScope h_scope(isolate1); 627 v8::Local<v8::Context> context = v8::Context::New(isolate1); 628 delete[] data1.data; // We can dispose of the snapshot blob now. 629 v8::Context::Scope c_scope(context); 630 v8::Maybe<int32_t> result = 631 CompileRun("f()")->Int32Value(isolate1->GetCurrentContext()); 632 CHECK_EQ(42, result.FromJust()); 633 CHECK(CompileRun("this.g")->IsUndefined()); 634 } 635 isolate1->Dispose(); 636 637 v8::Isolate::CreateParams params2; 638 params2.snapshot_blob = &data2; 639 params2.array_buffer_allocator = CcTest::array_buffer_allocator(); 640 v8::Isolate* isolate2 = v8::Isolate::New(params2); 641 { 642 v8::Isolate::Scope i_scope(isolate2); 643 v8::HandleScope h_scope(isolate2); 644 v8::Local<v8::Context> context = v8::Context::New(isolate2); 645 delete[] data2.data; // We can dispose of the snapshot blob now. 646 v8::Context::Scope c_scope(context); 647 v8::Maybe<int32_t> result = 648 CompileRun("f()")->Int32Value(isolate2->GetCurrentContext()); 649 CHECK_EQ(86, result.FromJust()); 650 result = CompileRun("g()")->Int32Value(isolate2->GetCurrentContext()); 651 CHECK_EQ(43, result.FromJust()); 652 } 653 isolate2->Dispose(); 654 } 655 656 657 static void SerializationFunctionTemplate( 658 const v8::FunctionCallbackInfo<v8::Value>& args) { 659 args.GetReturnValue().Set(args[0]); 660 } 661 662 TEST(CustomSnapshotDataBlobOutdatedContextWithOverflow) { 663 DisableTurbofan(); 664 665 const char* source1 = 666 "var o = {};" 667 "(function() {" 668 " function f1(x) { return f2(x) instanceof Array; }" 669 " function f2(x) { return foo.bar(x); }" 670 " o.a = f2.bind(null);" 671 " o.b = 1;" 672 " o.c = 2;" 673 " o.d = 3;" 674 " o.e = 4;" 675 "})();\n"; 676 677 const char* source2 = "o.a(42)"; 678 679 v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source1); 680 681 v8::Isolate::CreateParams params; 682 params.snapshot_blob = &data; 683 params.array_buffer_allocator = CcTest::array_buffer_allocator(); 684 685 v8::Isolate* isolate = v8::Isolate::New(params); 686 { 687 v8::Isolate::Scope i_scope(isolate); 688 v8::HandleScope h_scope(isolate); 689 690 v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); 691 v8::Local<v8::ObjectTemplate> property = v8::ObjectTemplate::New(isolate); 692 v8::Local<v8::FunctionTemplate> function = 693 v8::FunctionTemplate::New(isolate, SerializationFunctionTemplate); 694 property->Set(isolate, "bar", function); 695 global->Set(isolate, "foo", property); 696 697 v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global); 698 delete[] data.data; // We can dispose of the snapshot blob now. 699 v8::Context::Scope c_scope(context); 700 v8::Local<v8::Value> result = CompileRun(source2); 701 v8::Maybe<bool> compare = v8_str("42")->Equals( 702 v8::Isolate::GetCurrent()->GetCurrentContext(), result); 703 CHECK(compare.FromJust()); 704 } 705 isolate->Dispose(); 706 } 707 708 TEST(CustomSnapshotDataBlobWithLocker) { 709 DisableTurbofan(); 710 v8::Isolate::CreateParams create_params; 711 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 712 v8::Isolate* isolate0 = v8::Isolate::New(create_params); 713 { 714 v8::Locker locker(isolate0); 715 v8::Isolate::Scope i_scope(isolate0); 716 v8::HandleScope h_scope(isolate0); 717 v8::Local<v8::Context> context = v8::Context::New(isolate0); 718 v8::Context::Scope c_scope(context); 719 v8::Maybe<int32_t> result = 720 CompileRun("Math.cos(0)")->Int32Value(isolate0->GetCurrentContext()); 721 CHECK_EQ(1, result.FromJust()); 722 } 723 isolate0->Dispose(); 724 725 const char* source1 = "function f() { return 42; }"; 726 727 v8::StartupData data1 = v8::V8::CreateSnapshotDataBlob(source1); 728 729 v8::Isolate::CreateParams params1; 730 params1.snapshot_blob = &data1; 731 params1.array_buffer_allocator = CcTest::array_buffer_allocator(); 732 v8::Isolate* isolate1 = v8::Isolate::New(params1); 733 { 734 v8::Locker locker(isolate1); 735 v8::Isolate::Scope i_scope(isolate1); 736 v8::HandleScope h_scope(isolate1); 737 v8::Local<v8::Context> context = v8::Context::New(isolate1); 738 delete[] data1.data; // We can dispose of the snapshot blob now. 739 v8::Context::Scope c_scope(context); 740 v8::Maybe<int32_t> result = CompileRun("f()")->Int32Value(context); 741 CHECK_EQ(42, result.FromJust()); 742 } 743 isolate1->Dispose(); 744 } 745 746 TEST(CustomSnapshotDataBlobStackOverflow) { 747 DisableTurbofan(); 748 const char* source = 749 "var a = [0];" 750 "var b = a;" 751 "for (var i = 0; i < 10000; i++) {" 752 " var c = [i];" 753 " b.push(c);" 754 " b.push(c);" 755 " b = c;" 756 "}"; 757 758 v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source); 759 760 v8::Isolate::CreateParams params; 761 params.snapshot_blob = &data; 762 params.array_buffer_allocator = CcTest::array_buffer_allocator(); 763 764 v8::Isolate* isolate = v8::Isolate::New(params); 765 { 766 v8::Isolate::Scope i_scope(isolate); 767 v8::HandleScope h_scope(isolate); 768 v8::Local<v8::Context> context = v8::Context::New(isolate); 769 delete[] data.data; // We can dispose of the snapshot blob now. 770 v8::Context::Scope c_scope(context); 771 const char* test = 772 "var sum = 0;" 773 "while (a) {" 774 " sum += a[0];" 775 " a = a[1];" 776 "}" 777 "sum"; 778 v8::Maybe<int32_t> result = 779 CompileRun(test)->Int32Value(isolate->GetCurrentContext()); 780 CHECK_EQ(9999 * 5000, result.FromJust()); 781 } 782 isolate->Dispose(); 783 } 784 785 bool IsCompiled(const char* name) { 786 return i::Handle<i::JSFunction>::cast( 787 v8::Utils::OpenHandle(*CompileRun(name))) 788 ->shared() 789 ->is_compiled(); 790 } 791 792 TEST(SnapshotDataBlobWithWarmup) { 793 DisableTurbofan(); 794 const char* warmup = "Math.tanh(1); Math.sinh = 1;"; 795 796 v8::StartupData cold = v8::V8::CreateSnapshotDataBlob(); 797 v8::StartupData warm = v8::V8::WarmUpSnapshotDataBlob(cold, warmup); 798 delete[] cold.data; 799 800 v8::Isolate::CreateParams params; 801 params.snapshot_blob = &warm; 802 params.array_buffer_allocator = CcTest::array_buffer_allocator(); 803 804 v8::Isolate* isolate = v8::Isolate::New(params); 805 { 806 v8::Isolate::Scope i_scope(isolate); 807 v8::HandleScope h_scope(isolate); 808 v8::Local<v8::Context> context = v8::Context::New(isolate); 809 delete[] warm.data; 810 v8::Context::Scope c_scope(context); 811 // Running the warmup script has effect on whether functions are 812 // pre-compiled, but does not pollute the context. 813 CHECK(IsCompiled("Math.tanh")); 814 CHECK(!IsCompiled("Math.cosh")); 815 CHECK(CompileRun("Math.sinh")->IsFunction()); 816 } 817 isolate->Dispose(); 818 } 819 820 TEST(CustomSnapshotDataBlobWithWarmup) { 821 DisableTurbofan(); 822 const char* source = 823 "function f() { return Math.sinh(1); }\n" 824 "function g() { return Math.cosh(1); }\n" 825 "Math.tanh(1);" 826 "var a = 5"; 827 const char* warmup = "a = f()"; 828 829 v8::StartupData cold = v8::V8::CreateSnapshotDataBlob(source); 830 v8::StartupData warm = v8::V8::WarmUpSnapshotDataBlob(cold, warmup); 831 delete[] cold.data; 832 833 v8::Isolate::CreateParams params; 834 params.snapshot_blob = &warm; 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[] warm.data; 843 v8::Context::Scope c_scope(context); 844 // Running the warmup script has effect on whether functions are 845 // pre-compiled, but does not pollute the context. 846 CHECK(IsCompiled("f")); 847 CHECK(IsCompiled("Math.sinh")); 848 CHECK(!IsCompiled("g")); 849 CHECK(!IsCompiled("Math.cosh")); 850 CHECK(!IsCompiled("Math.tanh")); 851 CHECK_EQ(5, CompileRun("a")->Int32Value(context).FromJust()); 852 } 853 isolate->Dispose(); 854 } 855 856 TEST(CustomSnapshotDataBlobImmortalImmovableRoots) { 857 DisableTurbofan(); 858 // Flood the startup snapshot with shared function infos. If they are 859 // serialized before the immortal immovable root, the root will no longer end 860 // up on the first page. 861 Vector<const uint8_t> source = 862 ConstructSource(STATIC_CHAR_VECTOR("var a = [];"), 863 STATIC_CHAR_VECTOR("a.push(function() {return 7});"), 864 STATIC_CHAR_VECTOR("\0"), 10000); 865 866 v8::StartupData data = v8::V8::CreateSnapshotDataBlob( 867 reinterpret_cast<const char*>(source.start())); 868 869 v8::Isolate::CreateParams params; 870 params.snapshot_blob = &data; 871 params.array_buffer_allocator = CcTest::array_buffer_allocator(); 872 873 v8::Isolate* isolate = v8::Isolate::New(params); 874 { 875 v8::Isolate::Scope i_scope(isolate); 876 v8::HandleScope h_scope(isolate); 877 v8::Local<v8::Context> context = v8::Context::New(isolate); 878 delete[] data.data; // We can dispose of the snapshot blob now. 879 v8::Context::Scope c_scope(context); 880 CHECK_EQ(7, CompileRun("a[0]()")->Int32Value(context).FromJust()); 881 } 882 isolate->Dispose(); 883 source.Dispose(); 884 } 885 886 TEST(TestThatAlwaysSucceeds) { 887 } 888 889 890 TEST(TestThatAlwaysFails) { 891 bool ArtificialFailure = false; 892 CHECK(ArtificialFailure); 893 } 894 895 896 int CountBuiltins() { 897 // Check that we have not deserialized any additional builtin. 898 HeapIterator iterator(CcTest::heap()); 899 DisallowHeapAllocation no_allocation; 900 int counter = 0; 901 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { 902 if (obj->IsCode() && Code::cast(obj)->kind() == Code::BUILTIN) counter++; 903 } 904 return counter; 905 } 906 907 908 static Handle<SharedFunctionInfo> CompileScript( 909 Isolate* isolate, Handle<String> source, Handle<String> name, 910 ScriptData** cached_data, v8::ScriptCompiler::CompileOptions options) { 911 return Compiler::GetSharedFunctionInfoForScript( 912 source, name, 0, 0, v8::ScriptOriginOptions(), Handle<Object>(), 913 Handle<Context>(isolate->native_context()), NULL, cached_data, options, 914 NOT_NATIVES_CODE, false); 915 } 916 917 TEST(CodeSerializerOnePlusOne) { 918 FLAG_serialize_toplevel = true; 919 LocalContext context; 920 Isolate* isolate = CcTest::i_isolate(); 921 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 922 923 v8::HandleScope scope(CcTest::isolate()); 924 925 const char* source = "1 + 1"; 926 927 Handle<String> orig_source = isolate->factory() 928 ->NewStringFromUtf8(CStrVector(source)) 929 .ToHandleChecked(); 930 Handle<String> copy_source = isolate->factory() 931 ->NewStringFromUtf8(CStrVector(source)) 932 .ToHandleChecked(); 933 CHECK(!orig_source.is_identical_to(copy_source)); 934 CHECK(orig_source->Equals(*copy_source)); 935 936 ScriptData* cache = NULL; 937 938 Handle<SharedFunctionInfo> orig = 939 CompileScript(isolate, orig_source, Handle<String>(), &cache, 940 v8::ScriptCompiler::kProduceCodeCache); 941 942 int builtins_count = CountBuiltins(); 943 944 Handle<SharedFunctionInfo> copy; 945 { 946 DisallowCompilation no_compile_expected(isolate); 947 copy = CompileScript(isolate, copy_source, Handle<String>(), &cache, 948 v8::ScriptCompiler::kConsumeCodeCache); 949 } 950 951 CHECK_NE(*orig, *copy); 952 CHECK(Script::cast(copy->script())->source() == *copy_source); 953 954 Handle<JSFunction> copy_fun = 955 isolate->factory()->NewFunctionFromSharedFunctionInfo( 956 copy, isolate->native_context()); 957 Handle<JSObject> global(isolate->context()->global_object()); 958 Handle<Object> copy_result = 959 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 960 CHECK_EQ(2, Handle<Smi>::cast(copy_result)->value()); 961 962 CHECK_EQ(builtins_count, CountBuiltins()); 963 964 delete cache; 965 } 966 967 TEST(CodeSerializerPromotedToCompilationCache) { 968 FLAG_serialize_toplevel = true; 969 LocalContext context; 970 Isolate* isolate = CcTest::i_isolate(); 971 972 v8::HandleScope scope(CcTest::isolate()); 973 974 const char* source = "1 + 1"; 975 976 Handle<String> src = isolate->factory() 977 ->NewStringFromUtf8(CStrVector(source)) 978 .ToHandleChecked(); 979 ScriptData* cache = NULL; 980 981 CompileScript(isolate, src, src, &cache, 982 v8::ScriptCompiler::kProduceCodeCache); 983 984 DisallowCompilation no_compile_expected(isolate); 985 Handle<SharedFunctionInfo> copy = CompileScript( 986 isolate, src, src, &cache, v8::ScriptCompiler::kConsumeCodeCache); 987 988 CHECK(isolate->compilation_cache() 989 ->LookupScript(src, src, 0, 0, v8::ScriptOriginOptions(), 990 isolate->native_context(), SLOPPY) 991 .ToHandleChecked() 992 .is_identical_to(copy)); 993 994 delete cache; 995 } 996 997 TEST(CodeSerializerInternalizedString) { 998 FLAG_serialize_toplevel = true; 999 LocalContext context; 1000 Isolate* isolate = CcTest::i_isolate(); 1001 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1002 1003 v8::HandleScope scope(CcTest::isolate()); 1004 1005 const char* source = "'string1'"; 1006 1007 Handle<String> orig_source = isolate->factory() 1008 ->NewStringFromUtf8(CStrVector(source)) 1009 .ToHandleChecked(); 1010 Handle<String> copy_source = isolate->factory() 1011 ->NewStringFromUtf8(CStrVector(source)) 1012 .ToHandleChecked(); 1013 CHECK(!orig_source.is_identical_to(copy_source)); 1014 CHECK(orig_source->Equals(*copy_source)); 1015 1016 Handle<JSObject> global(isolate->context()->global_object()); 1017 ScriptData* cache = NULL; 1018 1019 Handle<SharedFunctionInfo> orig = 1020 CompileScript(isolate, orig_source, Handle<String>(), &cache, 1021 v8::ScriptCompiler::kProduceCodeCache); 1022 Handle<JSFunction> orig_fun = 1023 isolate->factory()->NewFunctionFromSharedFunctionInfo( 1024 orig, isolate->native_context()); 1025 Handle<Object> orig_result = 1026 Execution::Call(isolate, orig_fun, global, 0, NULL).ToHandleChecked(); 1027 CHECK(orig_result->IsInternalizedString()); 1028 1029 int builtins_count = CountBuiltins(); 1030 1031 Handle<SharedFunctionInfo> copy; 1032 { 1033 DisallowCompilation no_compile_expected(isolate); 1034 copy = CompileScript(isolate, copy_source, Handle<String>(), &cache, 1035 v8::ScriptCompiler::kConsumeCodeCache); 1036 } 1037 CHECK_NE(*orig, *copy); 1038 CHECK(Script::cast(copy->script())->source() == *copy_source); 1039 1040 Handle<JSFunction> copy_fun = 1041 isolate->factory()->NewFunctionFromSharedFunctionInfo( 1042 copy, isolate->native_context()); 1043 CHECK_NE(*orig_fun, *copy_fun); 1044 Handle<Object> copy_result = 1045 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 1046 CHECK(orig_result.is_identical_to(copy_result)); 1047 Handle<String> expected = 1048 isolate->factory()->NewStringFromAsciiChecked("string1"); 1049 1050 CHECK(Handle<String>::cast(copy_result)->Equals(*expected)); 1051 CHECK_EQ(builtins_count, CountBuiltins()); 1052 1053 delete cache; 1054 } 1055 1056 TEST(CodeSerializerLargeCodeObject) { 1057 FLAG_serialize_toplevel = true; 1058 LocalContext context; 1059 Isolate* isolate = CcTest::i_isolate(); 1060 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1061 1062 v8::HandleScope scope(CcTest::isolate()); 1063 1064 Vector<const uint8_t> source = 1065 ConstructSource(STATIC_CHAR_VECTOR("var j=1; try { if (j) throw 1;"), 1066 STATIC_CHAR_VECTOR("for(var i=0;i<1;i++)j++;"), 1067 STATIC_CHAR_VECTOR("} catch (e) { j=7; } j"), 10000); 1068 Handle<String> source_str = 1069 isolate->factory()->NewStringFromOneByte(source).ToHandleChecked(); 1070 1071 Handle<JSObject> global(isolate->context()->global_object()); 1072 ScriptData* cache = NULL; 1073 1074 Handle<SharedFunctionInfo> orig = 1075 CompileScript(isolate, source_str, Handle<String>(), &cache, 1076 v8::ScriptCompiler::kProduceCodeCache); 1077 1078 CHECK(isolate->heap()->InSpace(orig->code(), LO_SPACE)); 1079 1080 Handle<SharedFunctionInfo> copy; 1081 { 1082 DisallowCompilation no_compile_expected(isolate); 1083 copy = CompileScript(isolate, source_str, Handle<String>(), &cache, 1084 v8::ScriptCompiler::kConsumeCodeCache); 1085 } 1086 CHECK_NE(*orig, *copy); 1087 1088 Handle<JSFunction> copy_fun = 1089 isolate->factory()->NewFunctionFromSharedFunctionInfo( 1090 copy, isolate->native_context()); 1091 1092 Handle<Object> copy_result = 1093 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 1094 1095 int result_int; 1096 CHECK(copy_result->ToInt32(&result_int)); 1097 CHECK_EQ(7, result_int); 1098 1099 delete cache; 1100 source.Dispose(); 1101 } 1102 1103 TEST(CodeSerializerLargeStrings) { 1104 FLAG_serialize_toplevel = true; 1105 LocalContext context; 1106 Isolate* isolate = CcTest::i_isolate(); 1107 Factory* f = isolate->factory(); 1108 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1109 1110 v8::HandleScope scope(CcTest::isolate()); 1111 1112 Vector<const uint8_t> source_s = ConstructSource( 1113 STATIC_CHAR_VECTOR("var s = \""), STATIC_CHAR_VECTOR("abcdef"), 1114 STATIC_CHAR_VECTOR("\";"), 1000000); 1115 Vector<const uint8_t> source_t = ConstructSource( 1116 STATIC_CHAR_VECTOR("var t = \""), STATIC_CHAR_VECTOR("uvwxyz"), 1117 STATIC_CHAR_VECTOR("\"; s + t"), 999999); 1118 Handle<String> source_str = 1119 f->NewConsString(f->NewStringFromOneByte(source_s).ToHandleChecked(), 1120 f->NewStringFromOneByte(source_t).ToHandleChecked()) 1121 .ToHandleChecked(); 1122 1123 Handle<JSObject> global(isolate->context()->global_object()); 1124 ScriptData* cache = NULL; 1125 1126 Handle<SharedFunctionInfo> orig = 1127 CompileScript(isolate, source_str, Handle<String>(), &cache, 1128 v8::ScriptCompiler::kProduceCodeCache); 1129 1130 Handle<SharedFunctionInfo> copy; 1131 { 1132 DisallowCompilation no_compile_expected(isolate); 1133 copy = CompileScript(isolate, source_str, Handle<String>(), &cache, 1134 v8::ScriptCompiler::kConsumeCodeCache); 1135 } 1136 CHECK_NE(*orig, *copy); 1137 1138 Handle<JSFunction> copy_fun = 1139 isolate->factory()->NewFunctionFromSharedFunctionInfo( 1140 copy, isolate->native_context()); 1141 1142 Handle<Object> copy_result = 1143 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 1144 1145 CHECK_EQ(6 * 1999999, Handle<String>::cast(copy_result)->length()); 1146 Handle<Object> property = JSReceiver::GetDataProperty( 1147 isolate->global_object(), f->NewStringFromAsciiChecked("s")); 1148 CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE)); 1149 property = JSReceiver::GetDataProperty(isolate->global_object(), 1150 f->NewStringFromAsciiChecked("t")); 1151 CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE)); 1152 // Make sure we do not serialize too much, e.g. include the source string. 1153 CHECK_LT(cache->length(), 13000000); 1154 1155 delete cache; 1156 source_s.Dispose(); 1157 source_t.Dispose(); 1158 } 1159 1160 TEST(CodeSerializerThreeBigStrings) { 1161 FLAG_serialize_toplevel = true; 1162 LocalContext context; 1163 Isolate* isolate = CcTest::i_isolate(); 1164 Factory* f = isolate->factory(); 1165 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1166 1167 v8::HandleScope scope(CcTest::isolate()); 1168 1169 Vector<const uint8_t> source_a = 1170 ConstructSource(STATIC_CHAR_VECTOR("var a = \""), STATIC_CHAR_VECTOR("a"), 1171 STATIC_CHAR_VECTOR("\";"), 700000); 1172 Handle<String> source_a_str = 1173 f->NewStringFromOneByte(source_a).ToHandleChecked(); 1174 1175 Vector<const uint8_t> source_b = 1176 ConstructSource(STATIC_CHAR_VECTOR("var b = \""), STATIC_CHAR_VECTOR("b"), 1177 STATIC_CHAR_VECTOR("\";"), 600000); 1178 Handle<String> source_b_str = 1179 f->NewStringFromOneByte(source_b).ToHandleChecked(); 1180 1181 Vector<const uint8_t> source_c = 1182 ConstructSource(STATIC_CHAR_VECTOR("var c = \""), STATIC_CHAR_VECTOR("c"), 1183 STATIC_CHAR_VECTOR("\";"), 500000); 1184 Handle<String> source_c_str = 1185 f->NewStringFromOneByte(source_c).ToHandleChecked(); 1186 1187 Handle<String> source_str = 1188 f->NewConsString( 1189 f->NewConsString(source_a_str, source_b_str).ToHandleChecked(), 1190 source_c_str).ToHandleChecked(); 1191 1192 Handle<JSObject> global(isolate->context()->global_object()); 1193 ScriptData* cache = NULL; 1194 1195 Handle<SharedFunctionInfo> orig = 1196 CompileScript(isolate, source_str, Handle<String>(), &cache, 1197 v8::ScriptCompiler::kProduceCodeCache); 1198 1199 Handle<SharedFunctionInfo> copy; 1200 { 1201 DisallowCompilation no_compile_expected(isolate); 1202 copy = CompileScript(isolate, source_str, Handle<String>(), &cache, 1203 v8::ScriptCompiler::kConsumeCodeCache); 1204 } 1205 CHECK_NE(*orig, *copy); 1206 1207 Handle<JSFunction> copy_fun = 1208 isolate->factory()->NewFunctionFromSharedFunctionInfo( 1209 copy, isolate->native_context()); 1210 1211 USE(Execution::Call(isolate, copy_fun, global, 0, NULL)); 1212 1213 v8::Maybe<int32_t> result = 1214 CompileRun("(a + b).length") 1215 ->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext()); 1216 CHECK_EQ(600000 + 700000, result.FromJust()); 1217 result = CompileRun("(b + c).length") 1218 ->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext()); 1219 CHECK_EQ(500000 + 600000, result.FromJust()); 1220 Heap* heap = isolate->heap(); 1221 v8::Local<v8::String> result_str = 1222 CompileRun("a") 1223 ->ToString(CcTest::isolate()->GetCurrentContext()) 1224 .ToLocalChecked(); 1225 CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), LO_SPACE)); 1226 result_str = CompileRun("b") 1227 ->ToString(CcTest::isolate()->GetCurrentContext()) 1228 .ToLocalChecked(); 1229 CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), OLD_SPACE)); 1230 result_str = CompileRun("c") 1231 ->ToString(CcTest::isolate()->GetCurrentContext()) 1232 .ToLocalChecked(); 1233 CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), OLD_SPACE)); 1234 1235 delete cache; 1236 source_a.Dispose(); 1237 source_b.Dispose(); 1238 source_c.Dispose(); 1239 } 1240 1241 1242 class SerializerOneByteResource 1243 : public v8::String::ExternalOneByteStringResource { 1244 public: 1245 SerializerOneByteResource(const char* data, size_t length) 1246 : data_(data), length_(length) {} 1247 virtual const char* data() const { return data_; } 1248 virtual size_t length() const { return length_; } 1249 1250 private: 1251 const char* data_; 1252 size_t length_; 1253 }; 1254 1255 1256 class SerializerTwoByteResource : public v8::String::ExternalStringResource { 1257 public: 1258 SerializerTwoByteResource(const char* data, size_t length) 1259 : data_(AsciiToTwoByteString(data)), length_(length) {} 1260 ~SerializerTwoByteResource() { DeleteArray<const uint16_t>(data_); } 1261 1262 virtual const uint16_t* data() const { return data_; } 1263 virtual size_t length() const { return length_; } 1264 1265 private: 1266 const uint16_t* data_; 1267 size_t length_; 1268 }; 1269 1270 TEST(CodeSerializerExternalString) { 1271 FLAG_serialize_toplevel = true; 1272 LocalContext context; 1273 Isolate* isolate = CcTest::i_isolate(); 1274 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1275 1276 v8::HandleScope scope(CcTest::isolate()); 1277 1278 // Obtain external internalized one-byte string. 1279 SerializerOneByteResource one_byte_resource("one_byte", 8); 1280 Handle<String> one_byte_string = 1281 isolate->factory()->NewStringFromAsciiChecked("one_byte"); 1282 one_byte_string = isolate->factory()->InternalizeString(one_byte_string); 1283 one_byte_string->MakeExternal(&one_byte_resource); 1284 CHECK(one_byte_string->IsExternalOneByteString()); 1285 CHECK(one_byte_string->IsInternalizedString()); 1286 1287 // Obtain external internalized two-byte string. 1288 SerializerTwoByteResource two_byte_resource("two_byte", 8); 1289 Handle<String> two_byte_string = 1290 isolate->factory()->NewStringFromAsciiChecked("two_byte"); 1291 two_byte_string = isolate->factory()->InternalizeString(two_byte_string); 1292 two_byte_string->MakeExternal(&two_byte_resource); 1293 CHECK(two_byte_string->IsExternalTwoByteString()); 1294 CHECK(two_byte_string->IsInternalizedString()); 1295 1296 const char* source = 1297 "var o = {} \n" 1298 "o.one_byte = 7; \n" 1299 "o.two_byte = 8; \n" 1300 "o.one_byte + o.two_byte; \n"; 1301 Handle<String> source_string = isolate->factory() 1302 ->NewStringFromUtf8(CStrVector(source)) 1303 .ToHandleChecked(); 1304 1305 Handle<JSObject> global(isolate->context()->global_object()); 1306 ScriptData* cache = NULL; 1307 1308 Handle<SharedFunctionInfo> orig = 1309 CompileScript(isolate, source_string, Handle<String>(), &cache, 1310 v8::ScriptCompiler::kProduceCodeCache); 1311 1312 Handle<SharedFunctionInfo> copy; 1313 { 1314 DisallowCompilation no_compile_expected(isolate); 1315 copy = CompileScript(isolate, source_string, Handle<String>(), &cache, 1316 v8::ScriptCompiler::kConsumeCodeCache); 1317 } 1318 CHECK_NE(*orig, *copy); 1319 1320 Handle<JSFunction> copy_fun = 1321 isolate->factory()->NewFunctionFromSharedFunctionInfo( 1322 copy, isolate->native_context()); 1323 1324 Handle<Object> copy_result = 1325 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 1326 1327 CHECK_EQ(15.0, copy_result->Number()); 1328 1329 delete cache; 1330 } 1331 1332 TEST(CodeSerializerLargeExternalString) { 1333 FLAG_serialize_toplevel = true; 1334 LocalContext context; 1335 Isolate* isolate = CcTest::i_isolate(); 1336 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1337 1338 Factory* f = isolate->factory(); 1339 1340 v8::HandleScope scope(CcTest::isolate()); 1341 1342 // Create a huge external internalized string to use as variable name. 1343 Vector<const uint8_t> string = 1344 ConstructSource(STATIC_CHAR_VECTOR(""), STATIC_CHAR_VECTOR("abcdef"), 1345 STATIC_CHAR_VECTOR(""), 999999); 1346 Handle<String> name = f->NewStringFromOneByte(string).ToHandleChecked(); 1347 SerializerOneByteResource one_byte_resource( 1348 reinterpret_cast<const char*>(string.start()), string.length()); 1349 name = f->InternalizeString(name); 1350 name->MakeExternal(&one_byte_resource); 1351 CHECK(name->IsExternalOneByteString()); 1352 CHECK(name->IsInternalizedString()); 1353 CHECK(isolate->heap()->InSpace(*name, LO_SPACE)); 1354 1355 // Create the source, which is "var <literal> = 42; <literal>". 1356 Handle<String> source_str = 1357 f->NewConsString( 1358 f->NewConsString(f->NewStringFromAsciiChecked("var "), name) 1359 .ToHandleChecked(), 1360 f->NewConsString(f->NewStringFromAsciiChecked(" = 42; "), name) 1361 .ToHandleChecked()).ToHandleChecked(); 1362 1363 Handle<JSObject> global(isolate->context()->global_object()); 1364 ScriptData* cache = NULL; 1365 1366 Handle<SharedFunctionInfo> orig = 1367 CompileScript(isolate, source_str, Handle<String>(), &cache, 1368 v8::ScriptCompiler::kProduceCodeCache); 1369 1370 Handle<SharedFunctionInfo> copy; 1371 { 1372 DisallowCompilation no_compile_expected(isolate); 1373 copy = CompileScript(isolate, source_str, Handle<String>(), &cache, 1374 v8::ScriptCompiler::kConsumeCodeCache); 1375 } 1376 CHECK_NE(*orig, *copy); 1377 1378 Handle<JSFunction> copy_fun = 1379 f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context()); 1380 1381 Handle<Object> copy_result = 1382 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 1383 1384 CHECK_EQ(42.0, copy_result->Number()); 1385 1386 delete cache; 1387 string.Dispose(); 1388 } 1389 1390 TEST(CodeSerializerExternalScriptName) { 1391 FLAG_serialize_toplevel = true; 1392 LocalContext context; 1393 Isolate* isolate = CcTest::i_isolate(); 1394 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1395 1396 Factory* f = isolate->factory(); 1397 1398 v8::HandleScope scope(CcTest::isolate()); 1399 1400 const char* source = 1401 "var a = [1, 2, 3, 4];" 1402 "a.reduce(function(x, y) { return x + y }, 0)"; 1403 1404 Handle<String> source_string = 1405 f->NewStringFromUtf8(CStrVector(source)).ToHandleChecked(); 1406 1407 const SerializerOneByteResource one_byte_resource("one_byte", 8); 1408 Handle<String> name = 1409 f->NewExternalStringFromOneByte(&one_byte_resource).ToHandleChecked(); 1410 CHECK(name->IsExternalOneByteString()); 1411 CHECK(!name->IsInternalizedString()); 1412 1413 Handle<JSObject> global(isolate->context()->global_object()); 1414 ScriptData* cache = NULL; 1415 1416 Handle<SharedFunctionInfo> orig = 1417 CompileScript(isolate, source_string, name, &cache, 1418 v8::ScriptCompiler::kProduceCodeCache); 1419 1420 Handle<SharedFunctionInfo> copy; 1421 { 1422 DisallowCompilation no_compile_expected(isolate); 1423 copy = CompileScript(isolate, source_string, name, &cache, 1424 v8::ScriptCompiler::kConsumeCodeCache); 1425 } 1426 CHECK_NE(*orig, *copy); 1427 1428 Handle<JSFunction> copy_fun = 1429 f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context()); 1430 1431 Handle<Object> copy_result = 1432 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); 1433 1434 CHECK_EQ(10.0, copy_result->Number()); 1435 1436 delete cache; 1437 } 1438 1439 1440 static bool toplevel_test_code_event_found = false; 1441 1442 1443 static void SerializerCodeEventListener(const v8::JitCodeEvent* event) { 1444 if (event->type == v8::JitCodeEvent::CODE_ADDED && 1445 memcmp(event->name.str, "Script:~test", 12) == 0) { 1446 toplevel_test_code_event_found = true; 1447 } 1448 } 1449 1450 1451 v8::ScriptCompiler::CachedData* ProduceCache(const char* source) { 1452 v8::ScriptCompiler::CachedData* cache; 1453 v8::Isolate::CreateParams create_params; 1454 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1455 v8::Isolate* isolate1 = v8::Isolate::New(create_params); 1456 { 1457 v8::Isolate::Scope iscope(isolate1); 1458 v8::HandleScope scope(isolate1); 1459 v8::Local<v8::Context> context = v8::Context::New(isolate1); 1460 v8::Context::Scope context_scope(context); 1461 1462 v8::Local<v8::String> source_str = v8_str(source); 1463 v8::ScriptOrigin origin(v8_str("test")); 1464 v8::ScriptCompiler::Source source(source_str, origin); 1465 v8::Local<v8::UnboundScript> script = 1466 v8::ScriptCompiler::CompileUnboundScript( 1467 isolate1, &source, v8::ScriptCompiler::kProduceCodeCache) 1468 .ToLocalChecked(); 1469 const v8::ScriptCompiler::CachedData* data = source.GetCachedData(); 1470 CHECK(data); 1471 // Persist cached data. 1472 uint8_t* buffer = NewArray<uint8_t>(data->length); 1473 MemCopy(buffer, data->data, data->length); 1474 cache = new v8::ScriptCompiler::CachedData( 1475 buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned); 1476 1477 v8::Local<v8::Value> result = script->BindToCurrentContext() 1478 ->Run(isolate1->GetCurrentContext()) 1479 .ToLocalChecked(); 1480 v8::Local<v8::String> result_string = 1481 result->ToString(isolate1->GetCurrentContext()).ToLocalChecked(); 1482 CHECK(result_string->Equals(isolate1->GetCurrentContext(), v8_str("abcdef")) 1483 .FromJust()); 1484 } 1485 isolate1->Dispose(); 1486 return cache; 1487 } 1488 1489 TEST(CodeSerializerIsolates) { 1490 FLAG_serialize_toplevel = true; 1491 1492 const char* source = "function f() { return 'abc'; }; f() + 'def'"; 1493 v8::ScriptCompiler::CachedData* cache = ProduceCache(source); 1494 1495 v8::Isolate::CreateParams create_params; 1496 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1497 v8::Isolate* isolate2 = v8::Isolate::New(create_params); 1498 isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault, 1499 SerializerCodeEventListener); 1500 toplevel_test_code_event_found = false; 1501 { 1502 v8::Isolate::Scope iscope(isolate2); 1503 v8::HandleScope scope(isolate2); 1504 v8::Local<v8::Context> context = v8::Context::New(isolate2); 1505 v8::Context::Scope context_scope(context); 1506 1507 v8::Local<v8::String> source_str = v8_str(source); 1508 v8::ScriptOrigin origin(v8_str("test")); 1509 v8::ScriptCompiler::Source source(source_str, origin, cache); 1510 v8::Local<v8::UnboundScript> script; 1511 { 1512 DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2)); 1513 script = v8::ScriptCompiler::CompileUnboundScript( 1514 isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache) 1515 .ToLocalChecked(); 1516 } 1517 CHECK(!cache->rejected); 1518 v8::Local<v8::Value> result = script->BindToCurrentContext() 1519 ->Run(isolate2->GetCurrentContext()) 1520 .ToLocalChecked(); 1521 CHECK(result->ToString(isolate2->GetCurrentContext()) 1522 .ToLocalChecked() 1523 ->Equals(isolate2->GetCurrentContext(), v8_str("abcdef")) 1524 .FromJust()); 1525 } 1526 CHECK(toplevel_test_code_event_found); 1527 isolate2->Dispose(); 1528 } 1529 1530 TEST(CodeSerializerFlagChange) { 1531 FLAG_serialize_toplevel = true; 1532 1533 const char* source = "function f() { return 'abc'; }; f() + 'def'"; 1534 v8::ScriptCompiler::CachedData* cache = ProduceCache(source); 1535 1536 v8::Isolate::CreateParams create_params; 1537 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1538 v8::Isolate* isolate2 = v8::Isolate::New(create_params); 1539 1540 FLAG_allow_natives_syntax = true; // Flag change should trigger cache reject. 1541 FlagList::EnforceFlagImplications(); 1542 { 1543 v8::Isolate::Scope iscope(isolate2); 1544 v8::HandleScope scope(isolate2); 1545 v8::Local<v8::Context> context = v8::Context::New(isolate2); 1546 v8::Context::Scope context_scope(context); 1547 1548 v8::Local<v8::String> source_str = v8_str(source); 1549 v8::ScriptOrigin origin(v8_str("test")); 1550 v8::ScriptCompiler::Source source(source_str, origin, cache); 1551 v8::ScriptCompiler::CompileUnboundScript( 1552 isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache) 1553 .ToLocalChecked(); 1554 CHECK(cache->rejected); 1555 } 1556 isolate2->Dispose(); 1557 } 1558 1559 TEST(CodeSerializerBitFlip) { 1560 FLAG_serialize_toplevel = true; 1561 1562 const char* source = "function f() { return 'abc'; }; f() + 'def'"; 1563 v8::ScriptCompiler::CachedData* cache = ProduceCache(source); 1564 1565 // Random bit flip. 1566 const_cast<uint8_t*>(cache->data)[337] ^= 0x40; 1567 1568 v8::Isolate::CreateParams create_params; 1569 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1570 v8::Isolate* isolate2 = v8::Isolate::New(create_params); 1571 { 1572 v8::Isolate::Scope iscope(isolate2); 1573 v8::HandleScope scope(isolate2); 1574 v8::Local<v8::Context> context = v8::Context::New(isolate2); 1575 v8::Context::Scope context_scope(context); 1576 1577 v8::Local<v8::String> source_str = v8_str(source); 1578 v8::ScriptOrigin origin(v8_str("test")); 1579 v8::ScriptCompiler::Source source(source_str, origin, cache); 1580 v8::ScriptCompiler::CompileUnboundScript( 1581 isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache) 1582 .ToLocalChecked(); 1583 CHECK(cache->rejected); 1584 } 1585 isolate2->Dispose(); 1586 } 1587 1588 TEST(CodeSerializerWithHarmonyScoping) { 1589 FLAG_serialize_toplevel = true; 1590 1591 const char* source1 = "'use strict'; let x = 'X'"; 1592 const char* source2 = "'use strict'; let y = 'Y'"; 1593 const char* source3 = "'use strict'; x + y"; 1594 1595 v8::ScriptCompiler::CachedData* cache; 1596 1597 v8::Isolate::CreateParams create_params; 1598 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1599 v8::Isolate* isolate1 = v8::Isolate::New(create_params); 1600 { 1601 v8::Isolate::Scope iscope(isolate1); 1602 v8::HandleScope scope(isolate1); 1603 v8::Local<v8::Context> context = v8::Context::New(isolate1); 1604 v8::Context::Scope context_scope(context); 1605 1606 CompileRun(source1); 1607 CompileRun(source2); 1608 1609 v8::Local<v8::String> source_str = v8_str(source3); 1610 v8::ScriptOrigin origin(v8_str("test")); 1611 v8::ScriptCompiler::Source source(source_str, origin); 1612 v8::Local<v8::UnboundScript> script = 1613 v8::ScriptCompiler::CompileUnboundScript( 1614 isolate1, &source, v8::ScriptCompiler::kProduceCodeCache) 1615 .ToLocalChecked(); 1616 const v8::ScriptCompiler::CachedData* data = source.GetCachedData(); 1617 CHECK(data); 1618 // Persist cached data. 1619 uint8_t* buffer = NewArray<uint8_t>(data->length); 1620 MemCopy(buffer, data->data, data->length); 1621 cache = new v8::ScriptCompiler::CachedData( 1622 buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned); 1623 1624 v8::Local<v8::Value> result = script->BindToCurrentContext() 1625 ->Run(isolate1->GetCurrentContext()) 1626 .ToLocalChecked(); 1627 v8::Local<v8::String> result_str = 1628 result->ToString(isolate1->GetCurrentContext()).ToLocalChecked(); 1629 CHECK(result_str->Equals(isolate1->GetCurrentContext(), v8_str("XY")) 1630 .FromJust()); 1631 } 1632 isolate1->Dispose(); 1633 1634 v8::Isolate* isolate2 = v8::Isolate::New(create_params); 1635 { 1636 v8::Isolate::Scope iscope(isolate2); 1637 v8::HandleScope scope(isolate2); 1638 v8::Local<v8::Context> context = v8::Context::New(isolate2); 1639 v8::Context::Scope context_scope(context); 1640 1641 // Reverse order of prior running scripts. 1642 CompileRun(source2); 1643 CompileRun(source1); 1644 1645 v8::Local<v8::String> source_str = v8_str(source3); 1646 v8::ScriptOrigin origin(v8_str("test")); 1647 v8::ScriptCompiler::Source source(source_str, origin, cache); 1648 v8::Local<v8::UnboundScript> script; 1649 { 1650 DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2)); 1651 script = v8::ScriptCompiler::CompileUnboundScript( 1652 isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache) 1653 .ToLocalChecked(); 1654 } 1655 v8::Local<v8::Value> result = script->BindToCurrentContext() 1656 ->Run(isolate2->GetCurrentContext()) 1657 .ToLocalChecked(); 1658 v8::Local<v8::String> result_str = 1659 result->ToString(isolate2->GetCurrentContext()).ToLocalChecked(); 1660 CHECK(result_str->Equals(isolate2->GetCurrentContext(), v8_str("XY")) 1661 .FromJust()); 1662 } 1663 isolate2->Dispose(); 1664 } 1665 1666 TEST(CodeSerializerInternalReference) { 1667 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 1668 return; 1669 #endif 1670 // In ignition there are only relative jumps, so the following code 1671 // would not have any internal references. This test is not relevant 1672 // for ignition. 1673 if (FLAG_ignition) { 1674 return; 1675 } 1676 // Disable experimental natives that are loaded after deserialization. 1677 FLAG_function_context_specialization = false; 1678 FLAG_always_opt = true; 1679 const char* flag = "--turbo-filter=foo"; 1680 FlagList::SetFlagsFromString(flag, StrLength(flag)); 1681 1682 const char* source = 1683 "var foo = (function(stdlib, foreign, heap) {" 1684 " function foo(i) {" 1685 " i = i|0;" 1686 " var j = 0;" 1687 " switch (i) {" 1688 " case 0:" 1689 " case 1: j = 1; break;" 1690 " case 2:" 1691 " case 3: j = 2; break;" 1692 " case 4:" 1693 " case 5: j = foo(3) + 1; break;" 1694 " default: j = 0; break;" 1695 " }" 1696 " return j + 10;" 1697 " }" 1698 " return { foo: foo };" 1699 "})(this, {}, undefined).foo;" 1700 "foo(1);"; 1701 1702 v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source); 1703 CHECK(data.data); 1704 1705 v8::Isolate::CreateParams params; 1706 params.snapshot_blob = &data; 1707 params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1708 v8::Isolate* isolate = v8::Isolate::New(params); 1709 { 1710 v8::Isolate::Scope i_scope(isolate); 1711 v8::HandleScope h_scope(isolate); 1712 v8::Local<v8::Context> context = v8::Context::New(isolate); 1713 delete[] data.data; // We can dispose of the snapshot blob now. 1714 v8::Context::Scope c_scope(context); 1715 v8::Local<v8::Function> foo = 1716 v8::Local<v8::Function>::Cast(CompileRun("foo")); 1717 1718 // There are at least 6 internal references. 1719 int mask = RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | 1720 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED); 1721 RelocIterator it( 1722 Handle<JSFunction>::cast(v8::Utils::OpenHandle(*foo))->code(), mask); 1723 for (int i = 0; i < 6; ++i) { 1724 CHECK(!it.done()); 1725 it.next(); 1726 } 1727 1728 CHECK(Handle<JSFunction>::cast(v8::Utils::OpenHandle(*foo)) 1729 ->code() 1730 ->is_turbofanned()); 1731 CHECK_EQ(11, CompileRun("foo(0)") 1732 ->Int32Value(isolate->GetCurrentContext()) 1733 .FromJust()); 1734 CHECK_EQ(11, CompileRun("foo(1)") 1735 ->Int32Value(isolate->GetCurrentContext()) 1736 .FromJust()); 1737 CHECK_EQ(12, CompileRun("foo(2)") 1738 ->Int32Value(isolate->GetCurrentContext()) 1739 .FromJust()); 1740 CHECK_EQ(12, CompileRun("foo(3)") 1741 ->Int32Value(isolate->GetCurrentContext()) 1742 .FromJust()); 1743 CHECK_EQ(23, CompileRun("foo(4)") 1744 ->Int32Value(isolate->GetCurrentContext()) 1745 .FromJust()); 1746 CHECK_EQ(23, CompileRun("foo(5)") 1747 ->Int32Value(isolate->GetCurrentContext()) 1748 .FromJust()); 1749 CHECK_EQ(10, CompileRun("foo(6)") 1750 ->Int32Value(isolate->GetCurrentContext()) 1751 .FromJust()); 1752 } 1753 isolate->Dispose(); 1754 } 1755 1756 TEST(CodeSerializerEagerCompilationAndPreAge) { 1757 if (FLAG_ignition) return; 1758 1759 FLAG_lazy = true; 1760 FLAG_serialize_toplevel = true; 1761 FLAG_serialize_age_code = true; 1762 FLAG_serialize_eager = true; 1763 FLAG_min_preparse_length = 1; 1764 1765 static const char* source = 1766 "function f() {" 1767 " function g() {" 1768 " return 1;" 1769 " }" 1770 " return g();" 1771 "}" 1772 "'abcdef';"; 1773 1774 v8::ScriptCompiler::CachedData* cache = ProduceCache(source); 1775 1776 v8::Isolate::CreateParams create_params; 1777 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1778 v8::Isolate* isolate2 = v8::Isolate::New(create_params); 1779 { 1780 v8::Isolate::Scope iscope(isolate2); 1781 v8::HandleScope scope(isolate2); 1782 v8::Local<v8::Context> context = v8::Context::New(isolate2); 1783 v8::Context::Scope context_scope(context); 1784 1785 v8::Local<v8::String> source_str = v8_str(source); 1786 v8::ScriptOrigin origin(v8_str("test")); 1787 v8::ScriptCompiler::Source source(source_str, origin, cache); 1788 v8::Local<v8::UnboundScript> unbound = 1789 v8::ScriptCompiler::CompileUnboundScript( 1790 isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache) 1791 .ToLocalChecked(); 1792 1793 CHECK(!cache->rejected); 1794 1795 Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate2); 1796 HandleScope i_scope(i_isolate); 1797 Handle<SharedFunctionInfo> toplevel = v8::Utils::OpenHandle(*unbound); 1798 Handle<Script> script(Script::cast(toplevel->script())); 1799 WeakFixedArray::Iterator iterator(script->shared_function_infos()); 1800 // Every function has been pre-compiled from the code cache. 1801 int count = 0; 1802 while (SharedFunctionInfo* shared = iterator.Next<SharedFunctionInfo>()) { 1803 CHECK(shared->is_compiled()); 1804 CHECK_EQ(Code::kPreAgedCodeAge, shared->code()->GetAge()); 1805 count++; 1806 } 1807 CHECK_EQ(3, count); 1808 } 1809 isolate2->Dispose(); 1810 } 1811 1812 TEST(Regress503552) { 1813 // Test that the code serializer can deal with weak cells that form a linked 1814 // list during incremental marking. 1815 CcTest::InitializeVM(); 1816 Isolate* isolate = CcTest::i_isolate(); 1817 1818 HandleScope scope(isolate); 1819 Handle<String> source = isolate->factory()->NewStringFromAsciiChecked( 1820 "function f() {} function g() {}"); 1821 ScriptData* script_data = NULL; 1822 Handle<SharedFunctionInfo> shared = Compiler::GetSharedFunctionInfoForScript( 1823 source, Handle<String>(), 0, 0, v8::ScriptOriginOptions(), 1824 Handle<Object>(), Handle<Context>(isolate->native_context()), NULL, 1825 &script_data, v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE, 1826 false); 1827 delete script_data; 1828 1829 heap::SimulateIncrementalMarking(isolate->heap()); 1830 1831 script_data = CodeSerializer::Serialize(isolate, shared, source); 1832 delete script_data; 1833 } 1834 1835 #if V8_TARGET_ARCH_X64 1836 TEST(CodeSerializerCell) { 1837 FLAG_serialize_toplevel = true; 1838 LocalContext context; 1839 Isolate* isolate = CcTest::i_isolate(); 1840 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. 1841 1842 v8::HandleScope scope(CcTest::isolate()); 1843 1844 size_t actual_size; 1845 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( 1846 Assembler::kMinimalBufferSize, &actual_size, true)); 1847 CHECK(buffer); 1848 HandleScope handles(isolate); 1849 1850 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size), 1851 v8::internal::CodeObjectRequired::kYes); 1852 assembler.enable_serializer(); 1853 Handle<HeapNumber> number = isolate->factory()->NewHeapNumber(0.3); 1854 CHECK(isolate->heap()->InNewSpace(*number)); 1855 MacroAssembler* masm = &assembler; 1856 masm->MoveHeapObject(rax, number); 1857 masm->ret(0); 1858 CodeDesc desc; 1859 masm->GetCode(&desc); 1860 Handle<Code> code = isolate->factory()->NewCode( 1861 desc, Code::ComputeFlags(Code::FUNCTION), masm->CodeObject()); 1862 code->set_has_reloc_info_for_serialization(true); 1863 1864 RelocIterator rit1(*code, 1 << RelocInfo::CELL); 1865 CHECK_EQ(*number, rit1.rinfo()->target_cell()->value()); 1866 1867 Handle<String> source = isolate->factory()->empty_string(); 1868 Handle<SharedFunctionInfo> sfi = 1869 isolate->factory()->NewSharedFunctionInfo(source, code, false); 1870 ScriptData* script_data = CodeSerializer::Serialize(isolate, sfi, source); 1871 1872 Handle<SharedFunctionInfo> copy = 1873 CodeSerializer::Deserialize(isolate, script_data, source) 1874 .ToHandleChecked(); 1875 RelocIterator rit2(copy->code(), 1 << RelocInfo::CELL); 1876 CHECK(rit2.rinfo()->target_cell()->IsCell()); 1877 Handle<Cell> cell(rit2.rinfo()->target_cell()); 1878 CHECK(cell->value()->IsHeapNumber()); 1879 CHECK_EQ(0.3, HeapNumber::cast(cell->value())->value()); 1880 1881 delete script_data; 1882 } 1883 #endif // V8_TARGET_ARCH_X64 1884 1885 TEST(SnapshotCreatorMultipleContexts) { 1886 DisableTurbofan(); 1887 v8::StartupData blob; 1888 { 1889 v8::SnapshotCreator creator; 1890 v8::Isolate* isolate = creator.GetIsolate(); 1891 { 1892 v8::HandleScope handle_scope(isolate); 1893 v8::Local<v8::Context> context = v8::Context::New(isolate); 1894 v8::Context::Scope context_scope(context); 1895 CompileRun("var f = function() { return 1; }"); 1896 CHECK_EQ(0, creator.AddContext(context)); 1897 } 1898 { 1899 v8::HandleScope handle_scope(isolate); 1900 v8::Local<v8::Context> context = v8::Context::New(isolate); 1901 v8::Context::Scope context_scope(context); 1902 CompileRun("var f = function() { return 2; }"); 1903 CHECK_EQ(1, creator.AddContext(context)); 1904 } 1905 { 1906 v8::HandleScope handle_scope(isolate); 1907 v8::Local<v8::Context> context = v8::Context::New(isolate); 1908 CHECK_EQ(2, creator.AddContext(context)); 1909 } 1910 blob = 1911 creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear); 1912 } 1913 1914 v8::Isolate::CreateParams params; 1915 params.snapshot_blob = &blob; 1916 params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1917 v8::Isolate* isolate = v8::Isolate::New(params); 1918 { 1919 v8::Isolate::Scope isolate_scope(isolate); 1920 v8::ExtensionConfiguration* no_extension = nullptr; 1921 v8::Local<v8::ObjectTemplate> no_template = v8::Local<v8::ObjectTemplate>(); 1922 v8::Local<v8::Value> no_object = v8::Local<v8::Value>(); 1923 { 1924 v8::HandleScope handle_scope(isolate); 1925 v8::Local<v8::Context> context = 1926 v8::Context::New(isolate, no_extension, no_template, no_object, 0); 1927 v8::Context::Scope context_scope(context); 1928 ExpectInt32("f()", 1); 1929 } 1930 { 1931 v8::HandleScope handle_scope(isolate); 1932 v8::Local<v8::Context> context = 1933 v8::Context::New(isolate, no_extension, no_template, no_object, 1); 1934 v8::Context::Scope context_scope(context); 1935 ExpectInt32("f()", 2); 1936 } 1937 { 1938 v8::HandleScope handle_scope(isolate); 1939 v8::Local<v8::Context> context = 1940 v8::Context::New(isolate, no_extension, no_template, no_object, 2); 1941 v8::Context::Scope context_scope(context); 1942 ExpectUndefined("this.f"); 1943 } 1944 } 1945 1946 isolate->Dispose(); 1947 delete[] blob.data; 1948 } 1949 1950 static void SerializedCallback( 1951 const v8::FunctionCallbackInfo<v8::Value>& args) { 1952 args.GetReturnValue().Set(v8_num(42)); 1953 } 1954 1955 static void SerializedCallbackReplacement( 1956 const v8::FunctionCallbackInfo<v8::Value>& args) { 1957 args.GetReturnValue().Set(v8_num(1337)); 1958 } 1959 1960 intptr_t original_external_references[] = { 1961 reinterpret_cast<intptr_t>(SerializedCallback), 0}; 1962 1963 intptr_t replaced_external_references[] = { 1964 reinterpret_cast<intptr_t>(SerializedCallbackReplacement), 0}; 1965 1966 TEST(SnapshotCreatorExternalReferences) { 1967 DisableTurbofan(); 1968 v8::StartupData blob; 1969 { 1970 v8::SnapshotCreator creator(original_external_references); 1971 v8::Isolate* isolate = creator.GetIsolate(); 1972 { 1973 v8::HandleScope handle_scope(isolate); 1974 v8::Local<v8::Context> context = v8::Context::New(isolate); 1975 v8::Context::Scope context_scope(context); 1976 v8::Local<v8::FunctionTemplate> callback = 1977 v8::FunctionTemplate::New(isolate, SerializedCallback); 1978 v8::Local<v8::Value> function = 1979 callback->GetFunction(context).ToLocalChecked(); 1980 CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust()); 1981 ExpectInt32("f()", 42); 1982 CHECK_EQ(0, creator.AddContext(context)); 1983 } 1984 blob = 1985 creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear); 1986 } 1987 1988 // Deserialize with the original external reference. 1989 { 1990 v8::Isolate::CreateParams params; 1991 params.snapshot_blob = &blob; 1992 params.array_buffer_allocator = CcTest::array_buffer_allocator(); 1993 params.external_references = original_external_references; 1994 v8::Isolate* isolate = v8::Isolate::New(params); 1995 { 1996 v8::Isolate::Scope isolate_scope(isolate); 1997 v8::HandleScope handle_scope(isolate); 1998 v8::ExtensionConfiguration* no_extension = nullptr; 1999 v8::Local<v8::ObjectTemplate> no_template = 2000 v8::Local<v8::ObjectTemplate>(); 2001 v8::Local<v8::Value> no_object = v8::Local<v8::Value>(); 2002 v8::Local<v8::Context> context = 2003 v8::Context::New(isolate, no_extension, no_template, no_object, 0); 2004 v8::Context::Scope context_scope(context); 2005 ExpectInt32("f()", 42); 2006 } 2007 isolate->Dispose(); 2008 } 2009 2010 // Deserialize with the some other external reference. 2011 { 2012 v8::Isolate::CreateParams params; 2013 params.snapshot_blob = &blob; 2014 params.array_buffer_allocator = CcTest::array_buffer_allocator(); 2015 params.external_references = replaced_external_references; 2016 v8::Isolate* isolate = v8::Isolate::New(params); 2017 { 2018 v8::Isolate::Scope isolate_scope(isolate); 2019 v8::HandleScope handle_scope(isolate); 2020 v8::ExtensionConfiguration* no_extension = nullptr; 2021 v8::Local<v8::ObjectTemplate> no_template = 2022 v8::Local<v8::ObjectTemplate>(); 2023 v8::Local<v8::Value> no_object = v8::Local<v8::Value>(); 2024 v8::Local<v8::Context> context = 2025 v8::Context::New(isolate, no_extension, no_template, no_object, 0); 2026 v8::Context::Scope context_scope(context); 2027 ExpectInt32("f()", 1337); 2028 } 2029 isolate->Dispose(); 2030 } 2031 delete[] blob.data; 2032 } 2033 2034 TEST(SnapshotCreatorTemplates) { 2035 DisableTurbofan(); 2036 v8::StartupData blob; 2037 { 2038 v8::SnapshotCreator creator(original_external_references); 2039 v8::Isolate* isolate = creator.GetIsolate(); 2040 { 2041 v8::HandleScope handle_scope(isolate); 2042 v8::ExtensionConfiguration* no_extension = nullptr; 2043 v8::Local<v8::ObjectTemplate> global_template = 2044 v8::ObjectTemplate::New(isolate); 2045 v8::Local<v8::FunctionTemplate> callback = 2046 v8::FunctionTemplate::New(isolate, SerializedCallback); 2047 global_template->Set(v8_str("f"), callback); 2048 v8::Local<v8::Context> context = 2049 v8::Context::New(isolate, no_extension, global_template); 2050 v8::Context::Scope context_scope(context); 2051 ExpectInt32("f()", 42); 2052 CHECK_EQ(0, creator.AddContext(context)); 2053 CHECK_EQ(0, creator.AddTemplate(callback)); 2054 CHECK_EQ(1, creator.AddTemplate(global_template)); 2055 } 2056 blob = 2057 creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear); 2058 } 2059 2060 { 2061 v8::Isolate::CreateParams params; 2062 params.snapshot_blob = &blob; 2063 params.array_buffer_allocator = CcTest::array_buffer_allocator(); 2064 params.external_references = original_external_references; 2065 v8::Isolate* isolate = v8::Isolate::New(params); 2066 { 2067 v8::Isolate::Scope isolate_scope(isolate); 2068 { 2069 // Create a new context without a new object template. 2070 v8::HandleScope handle_scope(isolate); 2071 v8::ExtensionConfiguration* no_extension = nullptr; 2072 v8::Local<v8::ObjectTemplate> no_template = 2073 v8::Local<v8::ObjectTemplate>(); 2074 v8::Local<v8::Value> no_object = v8::Local<v8::Value>(); 2075 v8::Local<v8::Context> context = 2076 v8::Context::New(isolate, no_extension, no_template, no_object, 0); 2077 v8::Context::Scope context_scope(context); 2078 ExpectInt32("f()", 42); 2079 2080 // Retrieve the snapshotted object template. 2081 v8::Local<v8::ObjectTemplate> obj_template = 2082 v8::ObjectTemplate::FromSnapshot(isolate, 1); 2083 CHECK(!obj_template.IsEmpty()); 2084 v8::Local<v8::Object> object = 2085 obj_template->NewInstance(context).ToLocalChecked(); 2086 CHECK(context->Global()->Set(context, v8_str("o"), object).FromJust()); 2087 ExpectInt32("o.f()", 42); 2088 // Check that it instantiates to the same prototype. 2089 ExpectTrue("o.f.prototype === f.prototype"); 2090 2091 // Retrieve the snapshotted function template. 2092 v8::Local<v8::FunctionTemplate> fun_template = 2093 v8::FunctionTemplate::FromSnapshot(isolate, 0); 2094 CHECK(!fun_template.IsEmpty()); 2095 v8::Local<v8::Function> fun = 2096 fun_template->GetFunction(context).ToLocalChecked(); 2097 CHECK(context->Global()->Set(context, v8_str("g"), fun).FromJust()); 2098 ExpectInt32("g()", 42); 2099 // Check that it instantiates to the same prototype. 2100 ExpectTrue("g.prototype === f.prototype"); 2101 } 2102 2103 { 2104 // Create a context with a new object template. It is merged into the 2105 // deserialized global object. 2106 v8::HandleScope handle_scope(isolate); 2107 v8::ExtensionConfiguration* no_extension = nullptr; 2108 v8::Local<v8::ObjectTemplate> global_template = 2109 v8::ObjectTemplate::New(isolate); 2110 global_template->Set( 2111 v8_str("g"), 2112 v8::FunctionTemplate::New(isolate, SerializedCallbackReplacement)); 2113 v8::Local<v8::Value> no_object = v8::Local<v8::Value>(); 2114 v8::Local<v8::Context> context = v8::Context::New( 2115 isolate, no_extension, global_template, no_object, 0); 2116 v8::Context::Scope context_scope(context); 2117 ExpectInt32("g()", 1337); 2118 ExpectInt32("f()", 42); 2119 } 2120 } 2121 isolate->Dispose(); 2122 } 2123 delete[] blob.data; 2124 } 2125 2126 TEST(SerializationMemoryStats) { 2127 FLAG_profile_deserialization = true; 2128 FLAG_always_opt = false; 2129 v8::StartupData blob = v8::V8::CreateSnapshotDataBlob(); 2130 delete[] blob.data; 2131 } 2132