LCOV - code coverage report
Current view: top level - test/cctest - test-serialize.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1668 1719 97.0 %
Date: 2019-01-20 Functions: 116 125 92.8 %

          Line data    Source code
       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/api-inl.h"
      35             : #include "src/assembler-inl.h"
      36             : #include "src/bootstrapper.h"
      37             : #include "src/compilation-cache.h"
      38             : #include "src/compiler.h"
      39             : #include "src/debug/debug.h"
      40             : #include "src/heap/spaces.h"
      41             : #include "src/interpreter/interpreter.h"
      42             : #include "src/macro-assembler-inl.h"
      43             : #include "src/objects-inl.h"
      44             : #include "src/objects/js-array-buffer-inl.h"
      45             : #include "src/objects/js-array-inl.h"
      46             : #include "src/objects/js-regexp-inl.h"
      47             : #include "src/runtime/runtime.h"
      48             : #include "src/snapshot/code-serializer.h"
      49             : #include "src/snapshot/natives.h"
      50             : #include "src/snapshot/partial-deserializer.h"
      51             : #include "src/snapshot/partial-serializer.h"
      52             : #include "src/snapshot/read-only-serializer.h"
      53             : #include "src/snapshot/snapshot.h"
      54             : #include "src/snapshot/startup-deserializer.h"
      55             : #include "src/snapshot/startup-serializer.h"
      56             : #include "test/cctest/cctest.h"
      57             : #include "test/cctest/heap/heap-utils.h"
      58             : #include "test/cctest/setup-isolate-for-tests.h"
      59             : 
      60             : namespace v8 {
      61             : namespace internal {
      62             : 
      63             : enum CodeCacheType { kLazy, kEager, kAfterExecute };
      64             : 
      65           0 : void DisableAlwaysOpt() {
      66             :   // Isolates prepared for serialization do not optimize. The only exception is
      67             :   // with the flag --always-opt.
      68         220 :   FLAG_always_opt = false;
      69           0 : }
      70             : 
      71             : // A convenience struct to simplify management of the blobs required to
      72             : // deserialize an isolate.
      73             : struct StartupBlobs {
      74             :   Vector<const byte> startup;
      75             :   Vector<const byte> read_only;
      76             : 
      77          65 :   void Dispose() {
      78             :     startup.Dispose();
      79             :     read_only.Dispose();
      80          65 :   }
      81             : };
      82             : 
      83             : // TestSerializer is used for testing isolate serialization.
      84             : class TestSerializer {
      85             :  public:
      86          55 :   static v8::Isolate* NewIsolateInitialized() {
      87             :     const bool kEnableSerializer = true;
      88             :     const bool kGenerateHeap = true;
      89          55 :     DisableEmbeddedBlobRefcounting();
      90          55 :     v8::Isolate* v8_isolate = NewIsolate(kEnableSerializer, kGenerateHeap);
      91             :     v8::Isolate::Scope isolate_scope(v8_isolate);
      92             :     i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
      93          55 :     isolate->Init(nullptr);
      94          55 :     isolate->heap()->read_only_space()->ClearStringPaddingIfNeeded();
      95          55 :     return v8_isolate;
      96             :   }
      97             : 
      98          55 :   static v8::Isolate* NewIsolateFromBlob(StartupBlobs& blobs) {
      99             :     SnapshotData startup_snapshot(blobs.startup);
     100             :     SnapshotData read_only_snapshot(blobs.read_only);
     101             :     StartupDeserializer deserializer(&startup_snapshot, &read_only_snapshot);
     102             :     const bool kEnableSerializer = false;
     103             :     const bool kGenerateHeap = false;
     104          55 :     v8::Isolate* v8_isolate = NewIsolate(kEnableSerializer, kGenerateHeap);
     105             :     v8::Isolate::Scope isolate_scope(v8_isolate);
     106             :     i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
     107          55 :     isolate->Init(&deserializer);
     108          55 :     return v8_isolate;
     109             :   }
     110             : 
     111             :   // Wraps v8::Isolate::New, but with a test isolate under the hood.
     112             :   // Allows flexibility to bootstrap with or without snapshot even when
     113             :   // the production Isolate class has one or the other behavior baked in.
     114         150 :   static v8::Isolate* NewIsolate(const v8::Isolate::CreateParams& params) {
     115             :     const bool kEnableSerializer = false;
     116         150 :     const bool kGenerateHeap = params.snapshot_blob == nullptr;
     117         150 :     v8::Isolate* v8_isolate = NewIsolate(kEnableSerializer, kGenerateHeap);
     118         150 :     v8::Isolate::Initialize(v8_isolate, params);
     119         150 :     return v8_isolate;
     120             :   }
     121             : 
     122             :  private:
     123             :   // Creates an Isolate instance configured for testing.
     124         260 :   static v8::Isolate* NewIsolate(bool with_serializer, bool generate_heap) {
     125         260 :     i::Isolate* isolate = i::Isolate::New();
     126             :     v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     127             : 
     128         260 :     if (with_serializer) isolate->enable_serializer();
     129             :     isolate->set_array_buffer_allocator(CcTest::array_buffer_allocator());
     130         520 :     isolate->setup_delegate_ = new SetupIsolateDelegateForTests(generate_heap);
     131             : 
     132         260 :     return v8_isolate;
     133             :   }
     134             : };
     135             : 
     136         280 : static Vector<const byte> WritePayload(const Vector<const byte>& payload) {
     137             :   int length = payload.length();
     138         140 :   byte* blob = NewArray<byte>(length);
     139             :   memcpy(blob, payload.begin(), length);
     140         140 :   return Vector<const byte>(const_cast<const byte*>(blob), length);
     141             : }
     142             : 
     143             : namespace {
     144             : 
     145          70 : bool RunExtraCode(v8::Isolate* isolate, v8::Local<v8::Context> context,
     146             :                   const char* utf8_source, const char* name) {
     147             :   v8::Context::Scope context_scope(context);
     148         140 :   v8::TryCatch try_catch(isolate);
     149             :   v8::Local<v8::String> source_string;
     150          70 :   if (!v8::String::NewFromUtf8(isolate, utf8_source, v8::NewStringType::kNormal)
     151          70 :            .ToLocal(&source_string)) {
     152             :     return false;
     153             :   }
     154             :   v8::Local<v8::String> resource_name =
     155             :       v8::String::NewFromUtf8(isolate, name, v8::NewStringType::kNormal)
     156          70 :           .ToLocalChecked();
     157             :   v8::ScriptOrigin origin(resource_name);
     158             :   v8::ScriptCompiler::Source source(source_string, origin);
     159             :   v8::Local<v8::Script> script;
     160         140 :   if (!v8::ScriptCompiler::Compile(context, &source).ToLocal(&script))
     161             :     return false;
     162         140 :   if (script->Run(context).IsEmpty()) return false;
     163          70 :   CHECK(!try_catch.HasCaught());
     164             :   return true;
     165             : }
     166             : 
     167          70 : v8::StartupData CreateSnapshotDataBlob(
     168             :     v8::SnapshotCreator::FunctionCodeHandling function_code_handling,
     169             :     const char* embedded_source) {
     170             :   // Create a new isolate and a new context from scratch, optionally run
     171             :   // a script to embed, and serialize to create a snapshot blob.
     172          70 :   DisableEmbeddedBlobRefcounting();
     173             :   v8::StartupData result = {nullptr, 0};
     174             :   {
     175          70 :     v8::SnapshotCreator snapshot_creator;
     176          70 :     v8::Isolate* isolate = snapshot_creator.GetIsolate();
     177             :     {
     178          70 :       v8::HandleScope scope(isolate);
     179          70 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
     180         130 :       if (embedded_source != nullptr &&
     181          60 :           !RunExtraCode(isolate, context, embedded_source, "<embedded>")) {
     182           0 :         return result;
     183             :       }
     184          70 :       snapshot_creator.SetDefaultContext(context);
     185             :     }
     186          70 :     result = snapshot_creator.CreateBlob(function_code_handling);
     187             :   }
     188          70 :   return result;
     189             : }
     190             : 
     191             : v8::StartupData CreateSnapshotDataBlob(const char* embedded_source = nullptr) {
     192             :   return CreateSnapshotDataBlob(
     193          60 :       v8::SnapshotCreator::FunctionCodeHandling::kClear, embedded_source);
     194             : }
     195             : 
     196          10 : v8::StartupData WarmUpSnapshotDataBlob(v8::StartupData cold_snapshot_blob,
     197             :                                        const char* warmup_source) {
     198          10 :   CHECK(cold_snapshot_blob.raw_size > 0 && cold_snapshot_blob.data != nullptr);
     199          10 :   CHECK_NOT_NULL(warmup_source);
     200             :   // Use following steps to create a warmed up snapshot blob from a cold one:
     201             :   //  - Create a new isolate from the cold snapshot.
     202             :   //  - Create a new context to run the warmup script. This will trigger
     203             :   //    compilation of executed functions.
     204             :   //  - Create a new context. This context will be unpolluted.
     205             :   //  - Serialize the isolate and the second context into a new snapshot blob.
     206             :   v8::StartupData result = {nullptr, 0};
     207             :   {
     208          10 :     v8::SnapshotCreator snapshot_creator(nullptr, &cold_snapshot_blob);
     209          10 :     v8::Isolate* isolate = snapshot_creator.GetIsolate();
     210             :     {
     211          10 :       v8::HandleScope scope(isolate);
     212          10 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
     213          10 :       if (!RunExtraCode(isolate, context, warmup_source, "<warm-up>")) {
     214           0 :         return result;
     215          10 :       }
     216             :     }
     217             :     {
     218          10 :       v8::HandleScope handle_scope(isolate);
     219          10 :       isolate->ContextDisposedNotification(false);
     220          10 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
     221          10 :       snapshot_creator.SetDefaultContext(context);
     222             :     }
     223             :     result = snapshot_creator.CreateBlob(
     224          10 :         v8::SnapshotCreator::FunctionCodeHandling::kKeep);
     225             :   }
     226          10 :   return result;
     227             : }
     228             : 
     229             : }  // namespace
     230             : 
     231          55 : static StartupBlobs Serialize(v8::Isolate* isolate) {
     232             :   // We have to create one context.  One reason for this is so that the builtins
     233             :   // can be loaded from self hosted JS builtins and their addresses can be
     234             :   // processed.  This will clear the pending fixups array, which would otherwise
     235             :   // contain GC roots that would confuse the serialization/deserialization
     236             :   // process.
     237             :   v8::Isolate::Scope isolate_scope(isolate);
     238             :   {
     239          55 :     v8::HandleScope scope(isolate);
     240          55 :     v8::Context::New(isolate);
     241             :   }
     242             : 
     243             :   Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
     244             :   internal_isolate->heap()->CollectAllAvailableGarbage(
     245          55 :       i::GarbageCollectionReason::kTesting);
     246             : 
     247         110 :   ReadOnlySerializer read_only_serializer(internal_isolate);
     248          55 :   read_only_serializer.SerializeReadOnlyRoots();
     249             : 
     250         110 :   StartupSerializer ser(internal_isolate, &read_only_serializer);
     251          55 :   ser.SerializeStrongReferences();
     252             : 
     253          55 :   ser.SerializeWeakReferencesAndDeferred();
     254          55 :   read_only_serializer.FinalizeSerialization();
     255          55 :   SnapshotData startup_snapshot(&ser);
     256          55 :   SnapshotData read_only_snapshot(&read_only_serializer);
     257         165 :   return {WritePayload(startup_snapshot.RawData()),
     258         165 :           WritePayload(read_only_snapshot.RawData())};
     259             : }
     260             : 
     261             : 
     262          50 : Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head,
     263             :                                       Vector<const uint8_t> body,
     264             :                                       Vector<const uint8_t> tail, int repeats) {
     265         100 :   int source_length = head.length() + body.length() * repeats + tail.length();
     266          50 :   uint8_t* source = NewArray<uint8_t>(static_cast<size_t>(source_length));
     267          50 :   CopyChars(source, head.start(), head.length());
     268    23159990 :   for (int i = 0; i < repeats; i++) {
     269    23159990 :     CopyChars(source + head.length() + i * body.length(), body.start(),
     270    46319980 :               body.length());
     271             :   }
     272          50 :   CopyChars(source + head.length() + repeats * body.length(), tail.start(),
     273         100 :             tail.length());
     274             :   return Vector<const uint8_t>(const_cast<const uint8_t*>(source),
     275          50 :                                source_length);
     276             : }
     277             : 
     278             : 
     279          45 : static v8::Isolate* Deserialize(StartupBlobs& blobs) {
     280          45 :   v8::Isolate* isolate = TestSerializer::NewIsolateFromBlob(blobs);
     281          45 :   CHECK(isolate);
     282          45 :   return isolate;
     283             : }
     284             : 
     285             : 
     286          40 : static void SanityCheck(v8::Isolate* v8_isolate) {
     287             :   Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
     288          40 :   v8::HandleScope scope(v8_isolate);
     289             : #ifdef VERIFY_HEAP
     290             :   isolate->heap()->Verify();
     291             : #endif
     292         120 :   CHECK(isolate->global_object()->IsJSObject());
     293         120 :   CHECK(isolate->native_context()->IsContext());
     294          40 :   isolate->factory()->InternalizeOneByteString(StaticCharVector("Empty"));
     295          40 : }
     296             : 
     297          30 : void TestStartupSerializerOnceImpl() {
     298          30 :   v8::Isolate* isolate = TestSerializer::NewIsolateInitialized();
     299          30 :   StartupBlobs blobs = Serialize(isolate);
     300          30 :   isolate->Dispose();
     301          30 :   isolate = Deserialize(blobs);
     302             :   {
     303          30 :     v8::HandleScope handle_scope(isolate);
     304             :     v8::Isolate::Scope isolate_scope(isolate);
     305             : 
     306          30 :     v8::Local<v8::Context> env = v8::Context::New(isolate);
     307          30 :     env->Enter();
     308             : 
     309          60 :     SanityCheck(isolate);
     310             :   }
     311          30 :   isolate->Dispose();
     312          30 :   blobs.Dispose();
     313          30 :   FreeCurrentEmbeddedBlob();
     314          30 : }
     315             : 
     316       28342 : UNINITIALIZED_TEST(StartupSerializerOnce) {
     317             :   DisableAlwaysOpt();
     318           5 :   TestStartupSerializerOnceImpl();
     319           5 : }
     320             : 
     321       28342 : UNINITIALIZED_TEST(StartupSerializerOnce1) {
     322             :   DisableAlwaysOpt();
     323           5 :   FLAG_serialization_chunk_size = 1;
     324           5 :   TestStartupSerializerOnceImpl();
     325           5 : }
     326             : 
     327       28342 : UNINITIALIZED_TEST(StartupSerializerOnce32) {
     328             :   DisableAlwaysOpt();
     329           5 :   FLAG_serialization_chunk_size = 32;
     330           5 :   TestStartupSerializerOnceImpl();
     331           5 : }
     332             : 
     333       28342 : UNINITIALIZED_TEST(StartupSerializerOnce1K) {
     334             :   DisableAlwaysOpt();
     335           5 :   FLAG_serialization_chunk_size = 1 * KB;
     336           5 :   TestStartupSerializerOnceImpl();
     337           5 : }
     338             : 
     339       28342 : UNINITIALIZED_TEST(StartupSerializerOnce4K) {
     340             :   DisableAlwaysOpt();
     341           5 :   FLAG_serialization_chunk_size = 4 * KB;
     342           5 :   TestStartupSerializerOnceImpl();
     343           5 : }
     344             : 
     345       28342 : UNINITIALIZED_TEST(StartupSerializerOnce32K) {
     346             :   DisableAlwaysOpt();
     347           5 :   FLAG_serialization_chunk_size = 32 * KB;
     348           5 :   TestStartupSerializerOnceImpl();
     349           5 : }
     350             : 
     351       28342 : UNINITIALIZED_TEST(StartupSerializerRootMapDependencies) {
     352             :   DisableAlwaysOpt();
     353           5 :   v8::SnapshotCreator snapshot_creator;
     354           5 :   v8::Isolate* isolate = snapshot_creator.GetIsolate();
     355             :   {
     356             :     v8::Isolate::Scope isolate_scope(isolate);
     357          10 :     v8::HandleScope handle_scope(isolate);
     358             :     Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
     359             :     // Here is interesting retaining path:
     360             :     // - FreeSpaceMap
     361             :     // - Map for Map types itself
     362             :     // - NullValue
     363             :     // - Internalized one byte string
     364             :     // - Map for Internalized one byte string
     365             :     // - TheHoleValue
     366             :     // - HeapNumber
     367             :     // HeapNumber objects require kDoubleUnaligned on 32-bit
     368             :     // platforms. So, without special measures we're risking to serialize
     369             :     // object, requiring alignment before FreeSpaceMap is fully serialized.
     370             :     v8::internal::Handle<Map> map(
     371             :         ReadOnlyRoots(internal_isolate).one_byte_internalized_string_map(),
     372             :         internal_isolate);
     373             :     // Need to avoid DCHECKs inside SnapshotCreator.
     374           5 :     snapshot_creator.SetDefaultContext(v8::Context::New(isolate));
     375             :   }
     376             : 
     377             :   v8::StartupData startup_data = snapshot_creator.CreateBlob(
     378           5 :       v8::SnapshotCreator::FunctionCodeHandling::kKeep);
     379             : 
     380             :   v8::Isolate::CreateParams params;
     381           5 :   params.snapshot_blob = &startup_data;
     382           5 :   params.array_buffer_allocator = CcTest::array_buffer_allocator();
     383           5 :   isolate = v8::Isolate::New(params);
     384             : 
     385             :   {
     386           5 :     v8::HandleScope handle_scope(isolate);
     387             :     v8::Isolate::Scope isolate_scope(isolate);
     388             : 
     389           5 :     v8::Local<v8::Context> env = v8::Context::New(isolate);
     390           5 :     env->Enter();
     391             : 
     392          10 :     SanityCheck(isolate);
     393             :   }
     394           5 :   isolate->Dispose();
     395           5 :   delete[] startup_data.data;
     396           5 : }
     397             : 
     398       28342 : UNINITIALIZED_TEST(StartupSerializerTwice) {
     399             :   DisableAlwaysOpt();
     400           5 :   v8::Isolate* isolate = TestSerializer::NewIsolateInitialized();
     401           5 :   StartupBlobs blobs1 = Serialize(isolate);
     402           5 :   StartupBlobs blobs2 = Serialize(isolate);
     403           5 :   isolate->Dispose();
     404           5 :   blobs1.Dispose();
     405           5 :   isolate = Deserialize(blobs2);
     406             :   {
     407             :     v8::Isolate::Scope isolate_scope(isolate);
     408          10 :     v8::HandleScope handle_scope(isolate);
     409             : 
     410           5 :     v8::Local<v8::Context> env = v8::Context::New(isolate);
     411           5 :     env->Enter();
     412             : 
     413           5 :     SanityCheck(isolate);
     414             :   }
     415           5 :   isolate->Dispose();
     416           5 :   blobs2.Dispose();
     417           5 :   FreeCurrentEmbeddedBlob();
     418           5 : }
     419             : 
     420       28342 : UNINITIALIZED_TEST(StartupSerializerOnceRunScript) {
     421             :   DisableAlwaysOpt();
     422           5 :   v8::Isolate* isolate = TestSerializer::NewIsolateInitialized();
     423           5 :   StartupBlobs blobs = Serialize(isolate);
     424           5 :   isolate->Dispose();
     425           5 :   isolate = Deserialize(blobs);
     426             :   {
     427             :     v8::Isolate::Scope isolate_scope(isolate);
     428          10 :     v8::HandleScope handle_scope(isolate);
     429             : 
     430             : 
     431           5 :     v8::Local<v8::Context> env = v8::Context::New(isolate);
     432           5 :     env->Enter();
     433             : 
     434             :     const char* c_source = "\"1234\".length";
     435             :     v8::Local<v8::Script> script = v8_compile(c_source);
     436           5 :     v8::Maybe<int32_t> result = script->Run(isolate->GetCurrentContext())
     437           5 :                                     .ToLocalChecked()
     438          10 :                                     ->Int32Value(isolate->GetCurrentContext());
     439           5 :     CHECK_EQ(4, result.FromJust());
     440             :   }
     441           5 :   isolate->Dispose();
     442           5 :   blobs.Dispose();
     443           5 :   FreeCurrentEmbeddedBlob();
     444           5 : }
     445             : 
     446       28342 : UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) {
     447             :   DisableAlwaysOpt();
     448           5 :   v8::Isolate* isolate = TestSerializer::NewIsolateInitialized();
     449           5 :   StartupBlobs blobs1 = Serialize(isolate);
     450           5 :   StartupBlobs blobs2 = Serialize(isolate);
     451           5 :   isolate->Dispose();
     452           5 :   blobs1.Dispose();
     453           5 :   isolate = Deserialize(blobs2);
     454             :   {
     455             :     v8::Isolate::Scope isolate_scope(isolate);
     456          10 :     v8::HandleScope handle_scope(isolate);
     457             : 
     458           5 :     v8::Local<v8::Context> env = v8::Context::New(isolate);
     459           5 :     env->Enter();
     460             : 
     461             :     const char* c_source = "\"1234\".length";
     462             :     v8::Local<v8::Script> script = v8_compile(c_source);
     463           5 :     v8::Maybe<int32_t> result = script->Run(isolate->GetCurrentContext())
     464           5 :                                     .ToLocalChecked()
     465          10 :                                     ->Int32Value(isolate->GetCurrentContext());
     466           5 :     CHECK_EQ(4, result.FromJust());
     467             :   }
     468           5 :   isolate->Dispose();
     469           5 :   blobs2.Dispose();
     470           5 :   FreeCurrentEmbeddedBlob();
     471           5 : }
     472             : 
     473           5 : static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
     474             :                                       Vector<const byte>* read_only_blob_out,
     475             :                                       Vector<const byte>* partial_blob_out) {
     476           5 :   v8::Isolate* v8_isolate = TestSerializer::NewIsolateInitialized();
     477             :   Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
     478           5 :   Heap* heap = isolate->heap();
     479             :   {
     480             :     v8::Isolate::Scope isolate_scope(v8_isolate);
     481             : 
     482             :     v8::Persistent<v8::Context> env;
     483             :     {
     484             :       HandleScope scope(isolate);
     485          10 :       env.Reset(v8_isolate, v8::Context::New(v8_isolate));
     486             :     }
     487           5 :     CHECK(!env.IsEmpty());
     488             :     {
     489           5 :       v8::HandleScope handle_scope(v8_isolate);
     490           5 :       v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
     491             :     }
     492             : 
     493             :     // If we don't do this then we end up with a stray root pointing at the
     494             :     // context even after we have disposed of env.
     495           5 :     heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
     496             : 
     497             :     {
     498           5 :       v8::HandleScope handle_scope(v8_isolate);
     499           5 :       v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
     500             :     }
     501             : 
     502           5 :     i::Context raw_context = i::Context::cast(*v8::Utils::OpenPersistent(env));
     503             : 
     504             :     env.Reset();
     505             : 
     506             :     SnapshotByteSink read_only_sink;
     507          10 :     ReadOnlySerializer read_only_serializer(isolate);
     508           5 :     read_only_serializer.SerializeReadOnlyRoots();
     509             : 
     510             :     SnapshotByteSink startup_sink;
     511          10 :     StartupSerializer startup_serializer(isolate, &read_only_serializer);
     512           5 :     startup_serializer.SerializeStrongReferences();
     513             : 
     514             :     SnapshotByteSink partial_sink;
     515             :     PartialSerializer partial_serializer(isolate, &startup_serializer,
     516          10 :                                          v8::SerializeInternalFieldsCallback());
     517           5 :     partial_serializer.Serialize(&raw_context, false);
     518             : 
     519           5 :     startup_serializer.SerializeWeakReferencesAndDeferred();
     520             : 
     521           5 :     read_only_serializer.FinalizeSerialization();
     522             : 
     523           5 :     SnapshotData read_only_snapshot(&read_only_serializer);
     524           5 :     SnapshotData startup_snapshot(&startup_serializer);
     525           5 :     SnapshotData partial_snapshot(&partial_serializer);
     526             : 
     527          10 :     *partial_blob_out = WritePayload(partial_snapshot.RawData());
     528          10 :     *startup_blob_out = WritePayload(startup_snapshot.RawData());
     529          10 :     *read_only_blob_out = WritePayload(read_only_snapshot.RawData());
     530             :   }
     531           5 :   v8_isolate->Dispose();
     532           5 : }
     533             : 
     534       28342 : UNINITIALIZED_TEST(PartialSerializerContext) {
     535             :   DisableAlwaysOpt();
     536           5 :   Vector<const byte> startup_blob;
     537           5 :   Vector<const byte> read_only_blob;
     538           5 :   Vector<const byte> partial_blob;
     539           5 :   PartiallySerializeContext(&startup_blob, &read_only_blob, &partial_blob);
     540             : 
     541           5 :   StartupBlobs blobs = {startup_blob, read_only_blob};
     542           5 :   v8::Isolate* v8_isolate = TestSerializer::NewIsolateFromBlob(blobs);
     543           5 :   CHECK(v8_isolate);
     544             :   {
     545             :     v8::Isolate::Scope isolate_scope(v8_isolate);
     546             : 
     547             :     Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
     548             :     HandleScope handle_scope(isolate);
     549             :     Handle<Object> root;
     550             :     Handle<JSGlobalProxy> global_proxy =
     551             :         isolate->factory()->NewUninitializedJSGlobalProxy(
     552           5 :             JSGlobalProxy::SizeWithEmbedderFields(0));
     553             :     {
     554             :       SnapshotData snapshot_data(partial_blob);
     555             :       root = PartialDeserializer::DeserializeContext(
     556             :                  isolate, &snapshot_data, false, global_proxy,
     557           5 :                  v8::DeserializeInternalFieldsCallback())
     558          10 :                  .ToHandleChecked();
     559          10 :       CHECK(root->IsContext());
     560          15 :       CHECK(Handle<Context>::cast(root)->global_proxy() == *global_proxy);
     561             :     }
     562             : 
     563             :     Handle<Object> root2;
     564             :     {
     565             :       SnapshotData snapshot_data(partial_blob);
     566             :       root2 = PartialDeserializer::DeserializeContext(
     567             :                   isolate, &snapshot_data, false, global_proxy,
     568           5 :                   v8::DeserializeInternalFieldsCallback())
     569          10 :                   .ToHandleChecked();
     570          10 :       CHECK(root2->IsContext());
     571           5 :       CHECK(!root.is_identical_to(root2));
     572             :     }
     573             :     partial_blob.Dispose();
     574             :   }
     575           5 :   v8_isolate->Dispose();
     576           5 :   blobs.Dispose();
     577           5 :   FreeCurrentEmbeddedBlob();
     578           5 : }
     579             : 
     580           5 : static void PartiallySerializeCustomContext(
     581             :     Vector<const byte>* startup_blob_out,
     582             :     Vector<const byte>* read_only_blob_out,
     583             :     Vector<const byte>* partial_blob_out) {
     584           5 :   v8::Isolate* v8_isolate = TestSerializer::NewIsolateInitialized();
     585             :   Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
     586             :   {
     587             :     v8::Isolate::Scope isolate_scope(v8_isolate);
     588             : 
     589             :     v8::Persistent<v8::Context> env;
     590             :     {
     591             :       HandleScope scope(isolate);
     592          10 :       env.Reset(v8_isolate, v8::Context::New(v8_isolate));
     593             :     }
     594           5 :     CHECK(!env.IsEmpty());
     595             :     {
     596           5 :       v8::HandleScope handle_scope(v8_isolate);
     597           5 :       v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
     598             :       // After execution, e's function context refers to the global object.
     599             :       CompileRun(
     600             :           "var e;"
     601             :           "(function() {"
     602             :           "  e = function(s) { return eval (s); }"
     603             :           "})();"
     604             :           "var o = this;"
     605             :           "var r = Math.random();"
     606             :           "var c = Math.sin(0) + Math.cos(0);"
     607             :           "var f = (function(a, b) { return a + b; }).bind(1, 2, 3);"
     608             :           "var s = parseInt('12345');"
     609             :           "var p = 0;"
     610             :           "(async ()=>{ p = await 42; })();");
     611             : 
     612             :       Vector<const uint8_t> source = ConstructSource(
     613             :           StaticCharVector("function g() { return [,"), StaticCharVector("1,"),
     614           5 :           StaticCharVector("];} a = g(); b = g(); b.push(1);"), 100000);
     615             :       v8::MaybeLocal<v8::String> source_str = v8::String::NewFromOneByte(
     616             :           v8_isolate, source.start(), v8::NewStringType::kNormal,
     617           5 :           source.length());
     618           5 :       CompileRun(source_str.ToLocalChecked());
     619           5 :       source.Dispose();
     620             :     }
     621             :     // If we don't do this then we end up with a stray root pointing at the
     622             :     // context even after we have disposed of env.
     623             :     isolate->heap()->CollectAllAvailableGarbage(
     624           5 :         i::GarbageCollectionReason::kTesting);
     625             : 
     626             :     {
     627           5 :       v8::HandleScope handle_scope(v8_isolate);
     628           5 :       v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
     629             :     }
     630             : 
     631           5 :     i::Context raw_context = i::Context::cast(*v8::Utils::OpenPersistent(env));
     632             : 
     633             :     env.Reset();
     634             : 
     635             :     SnapshotByteSink read_only_sink;
     636          10 :     ReadOnlySerializer read_only_serializer(isolate);
     637           5 :     read_only_serializer.SerializeReadOnlyRoots();
     638             : 
     639             :     SnapshotByteSink startup_sink;
     640          10 :     StartupSerializer startup_serializer(isolate, &read_only_serializer);
     641           5 :     startup_serializer.SerializeStrongReferences();
     642             : 
     643             :     SnapshotByteSink partial_sink;
     644             :     PartialSerializer partial_serializer(isolate, &startup_serializer,
     645          10 :                                          v8::SerializeInternalFieldsCallback());
     646           5 :     partial_serializer.Serialize(&raw_context, false);
     647             : 
     648           5 :     startup_serializer.SerializeWeakReferencesAndDeferred();
     649             : 
     650           5 :     read_only_serializer.FinalizeSerialization();
     651             : 
     652           5 :     SnapshotData read_only_snapshot(&read_only_serializer);
     653           5 :     SnapshotData startup_snapshot(&startup_serializer);
     654           5 :     SnapshotData partial_snapshot(&partial_serializer);
     655             : 
     656          10 :     *partial_blob_out = WritePayload(partial_snapshot.RawData());
     657          10 :     *startup_blob_out = WritePayload(startup_snapshot.RawData());
     658          10 :     *read_only_blob_out = WritePayload(read_only_snapshot.RawData());
     659             :   }
     660           5 :   v8_isolate->Dispose();
     661           5 : }
     662             : 
     663       28342 : UNINITIALIZED_TEST(PartialSerializerCustomContext) {
     664             :   DisableAlwaysOpt();
     665           5 :   Vector<const byte> startup_blob;
     666           5 :   Vector<const byte> read_only_blob;
     667           5 :   Vector<const byte> partial_blob;
     668             :   PartiallySerializeCustomContext(&startup_blob, &read_only_blob,
     669           5 :                                   &partial_blob);
     670             : 
     671           5 :   StartupBlobs blobs = {startup_blob, read_only_blob};
     672           5 :   v8::Isolate* v8_isolate = TestSerializer::NewIsolateFromBlob(blobs);
     673           5 :   CHECK(v8_isolate);
     674             :   {
     675             :     v8::Isolate::Scope isolate_scope(v8_isolate);
     676             : 
     677             :     Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
     678             :     HandleScope handle_scope(isolate);
     679             :     Handle<Object> root;
     680             :     Handle<JSGlobalProxy> global_proxy =
     681             :         isolate->factory()->NewUninitializedJSGlobalProxy(
     682           5 :             JSGlobalProxy::SizeWithEmbedderFields(0));
     683             :     {
     684             :       SnapshotData snapshot_data(partial_blob);
     685             :       root = PartialDeserializer::DeserializeContext(
     686             :                  isolate, &snapshot_data, false, global_proxy,
     687           5 :                  v8::DeserializeInternalFieldsCallback())
     688          10 :                  .ToHandleChecked();
     689          10 :       CHECK(root->IsContext());
     690           5 :       Handle<Context> context = Handle<Context>::cast(root);
     691             : 
     692             :       // Add context to the weak native context list
     693             :       context->set(Context::NEXT_CONTEXT_LINK,
     694             :                    isolate->heap()->native_contexts_list(),
     695          10 :                    UPDATE_WEAK_WRITE_BARRIER);
     696             :       isolate->heap()->set_native_contexts_list(*context);
     697             : 
     698          10 :       CHECK(context->global_proxy() == *global_proxy);
     699           5 :       Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o");
     700          10 :       Handle<JSObject> global_object(context->global_object(), isolate);
     701           5 :       Handle<Object> property = JSReceiver::GetDataProperty(global_object, o);
     702           5 :       CHECK(property.is_identical_to(global_proxy));
     703             : 
     704             :       v8::Local<v8::Context> v8_context = v8::Utils::ToLocal(context);
     705             :       v8::Context::Scope context_scope(v8_context);
     706             :       double r = CompileRun("r")
     707           5 :                      ->ToNumber(v8_isolate->GetCurrentContext())
     708           5 :                      .ToLocalChecked()
     709           5 :                      ->Value();
     710           5 :       CHECK(0.0 <= r && r < 1.0);
     711             :       // Math.random still works.
     712             :       double random = CompileRun("Math.random()")
     713           5 :                           ->ToNumber(v8_isolate->GetCurrentContext())
     714           5 :                           .ToLocalChecked()
     715           5 :                           ->Value();
     716           5 :       CHECK(0.0 <= random && random < 1.0);
     717             :       double c = CompileRun("c")
     718           5 :                      ->ToNumber(v8_isolate->GetCurrentContext())
     719           5 :                      .ToLocalChecked()
     720           5 :                      ->Value();
     721           5 :       CHECK_EQ(1, c);
     722             :       int f = CompileRun("f()")
     723           5 :                   ->ToNumber(v8_isolate->GetCurrentContext())
     724           5 :                   .ToLocalChecked()
     725           5 :                   ->Int32Value(v8_isolate->GetCurrentContext())
     726          10 :                   .FromJust();
     727           5 :       CHECK_EQ(5, f);
     728             :       f = CompileRun("e('f()')")
     729           5 :               ->ToNumber(v8_isolate->GetCurrentContext())
     730           5 :               .ToLocalChecked()
     731           5 :               ->Int32Value(v8_isolate->GetCurrentContext())
     732          10 :               .FromJust();
     733           5 :       CHECK_EQ(5, f);
     734             :       v8::Local<v8::String> s = CompileRun("s")
     735           5 :                                     ->ToString(v8_isolate->GetCurrentContext())
     736           5 :                                     .ToLocalChecked();
     737          15 :       CHECK(s->Equals(v8_isolate->GetCurrentContext(), v8_str("12345"))
     738             :                 .FromJust());
     739             :       v8::Local<v8::String> p = CompileRun("p")
     740           5 :                                     ->ToString(v8_isolate->GetCurrentContext())
     741           5 :                                     .ToLocalChecked();
     742          15 :       CHECK(
     743             :           p->Equals(v8_isolate->GetCurrentContext(), v8_str("42")).FromJust());
     744             :       int a = CompileRun("a.length")
     745           5 :                   ->ToNumber(v8_isolate->GetCurrentContext())
     746           5 :                   .ToLocalChecked()
     747           5 :                   ->Int32Value(v8_isolate->GetCurrentContext())
     748          10 :                   .FromJust();
     749           5 :       CHECK_EQ(100001, a);
     750             :       int b = CompileRun("b.length")
     751           5 :                   ->ToNumber(v8_isolate->GetCurrentContext())
     752           5 :                   .ToLocalChecked()
     753           5 :                   ->Int32Value(v8_isolate->GetCurrentContext())
     754          10 :                   .FromJust();
     755           5 :       CHECK_EQ(100002, b);
     756             :     }
     757             :     partial_blob.Dispose();
     758             :   }
     759           5 :   v8_isolate->Dispose();
     760           5 :   blobs.Dispose();
     761           5 :   FreeCurrentEmbeddedBlob();
     762           5 : }
     763             : 
     764       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlob1) {
     765             :   DisableAlwaysOpt();
     766             :   const char* source1 = "function f() { return 42; }";
     767             : 
     768           5 :   v8::StartupData data1 = CreateSnapshotDataBlob(source1);
     769             : 
     770             :   v8::Isolate::CreateParams params1;
     771           5 :   params1.snapshot_blob = &data1;
     772           5 :   params1.array_buffer_allocator = CcTest::array_buffer_allocator();
     773             : 
     774             :   // Test-appropriate equivalent of v8::Isolate::New.
     775           5 :   v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
     776             :   {
     777             :     v8::Isolate::Scope i_scope(isolate1);
     778          10 :     v8::HandleScope h_scope(isolate1);
     779           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate1);
     780             :     v8::Context::Scope c_scope(context);
     781             :     v8::Maybe<int32_t> result =
     782          10 :         CompileRun("f()")->Int32Value(isolate1->GetCurrentContext());
     783           5 :     CHECK_EQ(42, result.FromJust());
     784           5 :     CHECK(CompileRun("this.g")->IsUndefined());
     785             :   }
     786           5 :   isolate1->Dispose();
     787           5 :   delete[] data1.data;  // We can dispose of the snapshot blob now.
     788           5 :   FreeCurrentEmbeddedBlob();
     789           5 : }
     790             : 
     791           0 : static void UnreachableCallback(const FunctionCallbackInfo<Value>& args) {
     792           0 :   UNREACHABLE();
     793             : }
     794             : 
     795       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobOverwriteGlobal) {
     796             :   DisableAlwaysOpt();
     797             :   const char* source1 = "function f() { return 42; }";
     798             : 
     799           5 :   v8::StartupData data1 = CreateSnapshotDataBlob(source1);
     800             : 
     801             :   v8::Isolate::CreateParams params1;
     802           5 :   params1.snapshot_blob = &data1;
     803           5 :   params1.array_buffer_allocator = CcTest::array_buffer_allocator();
     804             : 
     805             :   // Test that the snapshot overwrites the object template when there are
     806             :   // duplicate global properties.
     807           5 :   v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
     808             :   {
     809             :     v8::Isolate::Scope i_scope(isolate1);
     810          10 :     v8::HandleScope h_scope(isolate1);
     811             :     v8::Local<v8::ObjectTemplate> global_template =
     812           5 :         v8::ObjectTemplate::New(isolate1);
     813             :     global_template->Set(
     814          15 :         v8_str("f"), v8::FunctionTemplate::New(isolate1, UnreachableCallback));
     815             :     v8::Local<v8::Context> context =
     816           5 :         v8::Context::New(isolate1, nullptr, global_template);
     817             :     v8::Context::Scope c_scope(context);
     818             :     v8::Maybe<int32_t> result =
     819          10 :         CompileRun("f()")->Int32Value(isolate1->GetCurrentContext());
     820           5 :     CHECK_EQ(42, result.FromJust());
     821             :   }
     822           5 :   isolate1->Dispose();
     823           5 :   delete[] data1.data;  // We can dispose of the snapshot blob now.
     824           5 :   FreeCurrentEmbeddedBlob();
     825           5 : }
     826             : 
     827       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobStringNotInternalized) {
     828             :   DisableAlwaysOpt();
     829             :   const char* source1 =
     830             :       R"javascript(
     831             :       // String would be internalized if it came from a literal so create "A"
     832             :       // via a function call.
     833             :       var global = String.fromCharCode(65);
     834             :       function f() { return global; }
     835             :       )javascript";
     836             : 
     837           5 :   v8::StartupData data1 = CreateSnapshotDataBlob(source1);
     838             : 
     839             :   v8::Isolate::CreateParams params1;
     840           5 :   params1.snapshot_blob = &data1;
     841           5 :   params1.array_buffer_allocator = CcTest::array_buffer_allocator();
     842             : 
     843             :   // Test-appropriate equivalent of v8::Isolate::New.
     844           5 :   v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
     845             :   {
     846             :     v8::Isolate::Scope i_scope(isolate1);
     847          10 :     v8::HandleScope h_scope(isolate1);
     848           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate1);
     849             :     v8::Context::Scope c_scope(context);
     850             :     v8::Local<v8::Value> result = CompileRun("f()").As<v8::Value>();
     851           5 :     CHECK(result->IsString());
     852           5 :     i::String str = *v8::Utils::OpenHandle(*result.As<v8::String>());
     853          20 :     CHECK_EQ(std::string(str->ToCString().get()), "A");
     854           5 :     CHECK(!str.IsInternalizedString());
     855          10 :     CHECK(
     856             :         !reinterpret_cast<i::Isolate*>(isolate1)->heap()->InReadOnlySpace(str));
     857             :   }
     858           5 :   isolate1->Dispose();
     859           5 :   delete[] data1.data;  // We can dispose of the snapshot blob now.
     860           5 :   FreeCurrentEmbeddedBlob();
     861           5 : }
     862             : 
     863             : #ifndef V8_INTERPRETED_REGEXP
     864             : namespace {
     865             : 
     866          10 : void TestCustomSnapshotDataBlobWithIrregexpCode(
     867             :     v8::SnapshotCreator::FunctionCodeHandling function_code_handling) {
     868             :   DisableAlwaysOpt();
     869             :   const char* source =
     870             :       "var re1 = /\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\//;\n"
     871             :       "function f() { return '/* a comment */'.search(re1); }\n"
     872             :       "function g() { return 'not a comment'.search(re1); }\n"
     873             :       "function h() { return '// this is a comment'.search(re1); }\n"
     874             :       "var re2 = /a/;\n"
     875             :       "function i() { return '/* a comment */'.search(re2); }\n"
     876             :       "f(); f(); g(); g(); h(); h(); i(); i();\n";
     877             : 
     878             :   v8::StartupData data1 =
     879          10 :       CreateSnapshotDataBlob(function_code_handling, source);
     880             : 
     881             :   v8::Isolate::CreateParams params1;
     882          10 :   params1.snapshot_blob = &data1;
     883          10 :   params1.array_buffer_allocator = CcTest::array_buffer_allocator();
     884             : 
     885             :   // Test-appropriate equivalent of v8::Isolate::New.
     886          10 :   v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
     887             :   {
     888             :     v8::Isolate::Scope i_scope(isolate1);
     889          20 :     v8::HandleScope h_scope(isolate1);
     890          10 :     v8::Local<v8::Context> context = v8::Context::New(isolate1);
     891             :     v8::Context::Scope c_scope(context);
     892             :     {
     893             :       // Check that compiled irregexp code has not been flushed prior to
     894             :       // serialization.
     895             :       i::Handle<i::JSRegExp> re =
     896             :           Utils::OpenHandle(*CompileRun("re1").As<v8::RegExp>());
     897          20 :       CHECK_EQ(re->HasCompiledCode(),
     898             :                function_code_handling ==
     899             :                    v8::SnapshotCreator::FunctionCodeHandling::kKeep);
     900             :     }
     901             :     {
     902             :       v8::Maybe<int32_t> result =
     903          20 :           CompileRun("f()")->Int32Value(isolate1->GetCurrentContext());
     904          10 :       CHECK_EQ(0, result.FromJust());
     905             :     }
     906             :     {
     907             :       v8::Maybe<int32_t> result =
     908          20 :           CompileRun("g()")->Int32Value(isolate1->GetCurrentContext());
     909          10 :       CHECK_EQ(-1, result.FromJust());
     910             :     }
     911             :     {
     912             :       v8::Maybe<int32_t> result =
     913          20 :           CompileRun("h()")->Int32Value(isolate1->GetCurrentContext());
     914          10 :       CHECK_EQ(-1, result.FromJust());
     915             :     }
     916             :     {
     917             :       // Check that ATOM regexp remains valid.
     918             :       i::Handle<i::JSRegExp> re =
     919             :           Utils::OpenHandle(*CompileRun("re2").As<v8::RegExp>());
     920          10 :       CHECK_EQ(re->TypeTag(), JSRegExp::ATOM);
     921          10 :       CHECK(!re->HasCompiledCode());
     922             :     }
     923             :   }
     924          10 :   isolate1->Dispose();
     925          10 :   delete[] data1.data;  // We can dispose of the snapshot blob now.
     926          10 :   FreeCurrentEmbeddedBlob();
     927          10 : }
     928             : 
     929             : }  // namespace
     930             : 
     931       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCodeKeepCode) {
     932             :   TestCustomSnapshotDataBlobWithIrregexpCode(
     933           5 :       v8::SnapshotCreator::FunctionCodeHandling::kKeep);
     934           5 : }
     935             : 
     936       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCodeClearCode) {
     937             :   TestCustomSnapshotDataBlobWithIrregexpCode(
     938           5 :       v8::SnapshotCreator::FunctionCodeHandling::kClear);
     939           5 : }
     940             : #endif  // V8_INTERPRETED_REGEXP
     941             : 
     942       28342 : UNINITIALIZED_TEST(SnapshotChecksum) {
     943             :   DisableAlwaysOpt();
     944             :   const char* source1 = "function f() { return 42; }";
     945             : 
     946           5 :   v8::StartupData data1 = CreateSnapshotDataBlob(source1);
     947           5 :   CHECK(i::Snapshot::VerifyChecksum(&data1));
     948           5 :   const_cast<char*>(data1.data)[142] = data1.data[142] ^ 4;  // Flip a bit.
     949           5 :   CHECK(!i::Snapshot::VerifyChecksum(&data1));
     950           5 :   delete[] data1.data;  // We can dispose of the snapshot blob now.
     951           5 :   FreeCurrentEmbeddedBlob();
     952           5 : }
     953             : 
     954             : struct InternalFieldData {
     955             :   uint32_t data;
     956             : };
     957             : 
     958         250 : v8::StartupData SerializeInternalFields(v8::Local<v8::Object> holder, int index,
     959             :                                         void* data) {
     960         250 :   if (data == reinterpret_cast<void*>(2000)) {
     961             :     // Used for SnapshotCreatorTemplates test. We check that none of the fields
     962             :     // have been cleared yet.
     963          20 :     CHECK_NOT_NULL(holder->GetAlignedPointerFromInternalField(1));
     964             :   } else {
     965         230 :     CHECK_EQ(reinterpret_cast<void*>(2016), data);
     966             :   }
     967         250 :   if (index != 1) return {nullptr, 0};
     968             :   InternalFieldData* embedder_field = static_cast<InternalFieldData*>(
     969             :       holder->GetAlignedPointerFromInternalField(index));
     970         130 :   if (embedder_field == nullptr) return {nullptr, 0};
     971             :   int size = sizeof(*embedder_field);
     972          15 :   char* payload = new char[size];
     973             :   // We simply use memcpy to serialize the content.
     974             :   memcpy(payload, embedder_field, size);
     975          15 :   return {payload, size};
     976             : }
     977             : 
     978       28337 : std::vector<InternalFieldData*> deserialized_data;
     979             : 
     980          15 : void DeserializeInternalFields(v8::Local<v8::Object> holder, int index,
     981             :                                v8::StartupData payload, void* data) {
     982          15 :   if (payload.raw_size == 0) {
     983           0 :     holder->SetAlignedPointerInInternalField(index, nullptr);
     984          15 :     return;
     985             :   }
     986          15 :   CHECK_EQ(reinterpret_cast<void*>(2017), data);
     987          15 :   InternalFieldData* embedder_field = new InternalFieldData{0};
     988          15 :   memcpy(embedder_field, payload.data, payload.raw_size);
     989          15 :   holder->SetAlignedPointerInInternalField(index, embedder_field);
     990          15 :   deserialized_data.push_back(embedder_field);
     991             : }
     992             : 
     993             : typedef std::vector<std::tuple<const char*, int32_t>> Int32Expectations;
     994             : 
     995          80 : void TestInt32Expectations(const Int32Expectations& expectations) {
     996         410 :   for (const auto& e : expectations) {
     997         250 :     ExpectInt32(std::get<0>(e), std::get<1>(e));
     998             :   }
     999          80 : }
    1000             : 
    1001          20 : void TypedArrayTestHelper(
    1002             :     const char* code, const Int32Expectations& expectations,
    1003             :     const char* code_to_run_after_restore = nullptr,
    1004             :     const Int32Expectations& after_restore_expectations = Int32Expectations()) {
    1005             :   DisableAlwaysOpt();
    1006          20 :   i::FLAG_allow_natives_syntax = true;
    1007          20 :   DisableEmbeddedBlobRefcounting();
    1008             :   v8::StartupData blob;
    1009             :   {
    1010          20 :     v8::SnapshotCreator creator;
    1011          20 :     v8::Isolate* isolate = creator.GetIsolate();
    1012             :     {
    1013          20 :       v8::HandleScope handle_scope(isolate);
    1014          20 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    1015             :       v8::Context::Scope context_scope(context);
    1016             : 
    1017             :       CompileRun(code);
    1018          20 :       TestInt32Expectations(expectations);
    1019             :       creator.SetDefaultContext(
    1020             :           context, v8::SerializeInternalFieldsCallback(
    1021          40 :                        SerializeInternalFields, reinterpret_cast<void*>(2016)));
    1022             :     }
    1023             :     blob =
    1024          20 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    1025             :   }
    1026             : 
    1027             :   v8::Isolate::CreateParams create_params;
    1028          20 :   create_params.snapshot_blob = &blob;
    1029          20 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    1030          20 :   v8::Isolate* isolate = TestSerializer::NewIsolate(create_params);
    1031             :   {
    1032             :     v8::Isolate::Scope i_scope(isolate);
    1033          40 :     v8::HandleScope h_scope(isolate);
    1034             :     v8::Local<v8::Context> context = v8::Context::New(
    1035             :         isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
    1036             :         v8::MaybeLocal<v8::Value>(),
    1037             :         v8::DeserializeInternalFieldsCallback(DeserializeInternalFields,
    1038          20 :                                               reinterpret_cast<void*>(2017)));
    1039          20 :     CHECK(deserialized_data.empty());  // We do not expect any embedder data.
    1040             :     v8::Context::Scope c_scope(context);
    1041          20 :     TestInt32Expectations(expectations);
    1042          20 :     if (code_to_run_after_restore) {
    1043             :       CompileRun(code_to_run_after_restore);
    1044             :     }
    1045          20 :     TestInt32Expectations(after_restore_expectations);
    1046             :   }
    1047          20 :   isolate->Dispose();
    1048          20 :   delete[] blob.data;  // We can dispose of the snapshot blob now.
    1049          20 :   FreeCurrentEmbeddedBlob();
    1050          20 : }
    1051             : 
    1052       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobWithOffHeapTypedArray) {
    1053             :   const char* code =
    1054             :       "var x = new Uint8Array(128);"
    1055             :       "x[0] = 12;"
    1056             :       "var arr = new Array(17);"
    1057             :       "arr[1] = 24;"
    1058             :       "var y = new Uint32Array(arr);"
    1059             :       "var buffer = new ArrayBuffer(128);"
    1060             :       "var z = new Int16Array(buffer);"
    1061             :       "z[0] = 48;";
    1062             :   Int32Expectations expectations = {std::make_tuple("x[0]", 12),
    1063             :                                     std::make_tuple("y[1]", 24),
    1064           5 :                                     std::make_tuple("z[0]", 48)};
    1065             : 
    1066          10 :   TypedArrayTestHelper(code, expectations);
    1067           5 : }
    1068             : 
    1069       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobSharedArrayBuffer) {
    1070             :   const char* code =
    1071             :       "var x = new Int32Array([12, 24, 48, 96]);"
    1072             :       "var y = new Uint8Array(x.buffer)";
    1073             :   Int32Expectations expectations = {
    1074             :     std::make_tuple("x[0]", 12),
    1075             :     std::make_tuple("x[1]", 24),
    1076             : #if !V8_TARGET_BIG_ENDIAN
    1077             :     std::make_tuple("y[0]", 12),
    1078             :     std::make_tuple("y[1]", 0),
    1079             :     std::make_tuple("y[2]", 0),
    1080             :     std::make_tuple("y[3]", 0),
    1081             :     std::make_tuple("y[4]", 24)
    1082             : #else
    1083             :     std::make_tuple("y[3]", 12),
    1084             :     std::make_tuple("y[2]", 0),
    1085             :     std::make_tuple("y[1]", 0),
    1086             :     std::make_tuple("y[0]", 0),
    1087             :     std::make_tuple("y[7]", 24)
    1088             : #endif
    1089           5 :   };
    1090             : 
    1091          10 :   TypedArrayTestHelper(code, expectations);
    1092           5 : }
    1093             : 
    1094       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobArrayBufferWithOffset) {
    1095             :   const char* code =
    1096             :       "var x = new Int32Array([12, 24, 48, 96]);"
    1097             :       "var y = new Int32Array(x.buffer, 4, 2)";
    1098             :   Int32Expectations expectations = {
    1099             :       std::make_tuple("x[1]", 24), std::make_tuple("x[2]", 48),
    1100             :       std::make_tuple("y[0]", 24), std::make_tuple("y[1]", 48),
    1101           5 :   };
    1102             : 
    1103             :   // Verify that the typed arrays use the same buffer (not independent copies).
    1104             :   const char* code_to_run_after_restore = "x[2] = 57; y[0] = 42;";
    1105             :   Int32Expectations after_restore_expectations = {
    1106             :       std::make_tuple("x[1]", 42), std::make_tuple("y[1]", 57),
    1107           5 :   };
    1108             : 
    1109             :   TypedArrayTestHelper(code, expectations, code_to_run_after_restore,
    1110           5 :                        after_restore_expectations);
    1111           5 : }
    1112             : 
    1113       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobDataView) {
    1114             :   const char* code =
    1115             :       "var x = new Int8Array([1, 2, 3, 4]);"
    1116             :       "var v = new DataView(x.buffer)";
    1117             :   Int32Expectations expectations = {std::make_tuple("v.getInt8(0)", 1),
    1118             :                                     std::make_tuple("v.getInt8(1)", 2),
    1119             :                                     std::make_tuple("v.getInt16(0)", 258),
    1120           5 :                                     std::make_tuple("v.getInt16(1)", 515)};
    1121             : 
    1122          10 :   TypedArrayTestHelper(code, expectations);
    1123           5 : }
    1124             : 
    1125       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobDetachedArrayBuffer) {
    1126             :   const char* code =
    1127             :       "var x = new Int16Array([12, 24, 48]);"
    1128             :       "%ArrayBufferDetach(x.buffer);";
    1129             :   Int32Expectations expectations = {std::make_tuple("x.buffer.byteLength", 0),
    1130           5 :                                     std::make_tuple("x.length", 0)};
    1131             : 
    1132             :   DisableAlwaysOpt();
    1133           5 :   i::FLAG_allow_natives_syntax = true;
    1134           5 :   DisableEmbeddedBlobRefcounting();
    1135             :   v8::StartupData blob;
    1136             :   {
    1137           5 :     v8::SnapshotCreator creator;
    1138           5 :     v8::Isolate* isolate = creator.GetIsolate();
    1139             :     {
    1140           5 :       v8::HandleScope handle_scope(isolate);
    1141           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    1142             :       v8::Context::Scope context_scope(context);
    1143             : 
    1144             :       CompileRun(code);
    1145           5 :       TestInt32Expectations(expectations);
    1146             :       creator.SetDefaultContext(
    1147             :           context, v8::SerializeInternalFieldsCallback(
    1148          10 :                        SerializeInternalFields, reinterpret_cast<void*>(2016)));
    1149             :     }
    1150             :     blob =
    1151           5 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    1152             :   }
    1153             : 
    1154             :   v8::Isolate::CreateParams create_params;
    1155           5 :   create_params.snapshot_blob = &blob;
    1156           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    1157           5 :   v8::Isolate* isolate = TestSerializer::NewIsolate(create_params);
    1158             :   {
    1159             :     v8::Isolate::Scope i_scope(isolate);
    1160          10 :     v8::HandleScope h_scope(isolate);
    1161             :     v8::Local<v8::Context> context = v8::Context::New(
    1162             :         isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
    1163             :         v8::MaybeLocal<v8::Value>(),
    1164             :         v8::DeserializeInternalFieldsCallback(DeserializeInternalFields,
    1165           5 :                                               reinterpret_cast<void*>(2017)));
    1166             :     v8::Context::Scope c_scope(context);
    1167           5 :     TestInt32Expectations(expectations);
    1168             : 
    1169             :     v8::Local<v8::Value> x = CompileRun("x");
    1170           5 :     CHECK(x->IsTypedArray());
    1171             :     i::Handle<i::JSTypedArray> array =
    1172           5 :         i::Handle<i::JSTypedArray>::cast(v8::Utils::OpenHandle(*x));
    1173           5 :     CHECK(array->WasDetached());
    1174          10 :     CHECK_NULL(
    1175             :         FixedTypedArrayBase::cast(array->elements())->external_pointer());
    1176             :   }
    1177           5 :   isolate->Dispose();
    1178           5 :   delete[] blob.data;  // We can dispose of the snapshot blob now.
    1179           5 :   FreeCurrentEmbeddedBlob();
    1180           5 : }
    1181             : 
    1182          15 : i::Handle<i::JSArrayBuffer> GetBufferFromTypedArray(
    1183             :     v8::Local<v8::Value> typed_array) {
    1184          15 :   CHECK(typed_array->IsTypedArray());
    1185             : 
    1186             :   i::Handle<i::JSArrayBufferView> view = i::Handle<i::JSArrayBufferView>::cast(
    1187          15 :       v8::Utils::OpenHandle(*typed_array));
    1188             : 
    1189          30 :   return i::handle(i::JSArrayBuffer::cast(view->buffer()), view->GetIsolate());
    1190             : }
    1191             : 
    1192       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobOnOrOffHeapTypedArray) {
    1193             :   const char* code =
    1194             :       "var x = new Uint8Array(8);"
    1195             :       "x[0] = 12;"
    1196             :       "x[7] = 24;"
    1197             :       "var y = new Int16Array([12, 24, 48]);"
    1198             :       "var z = new Int32Array(64);"
    1199             :       "z[0] = 96;";
    1200             :   Int32Expectations expectations = {
    1201             :       std::make_tuple("x[0]", 12), std::make_tuple("x[7]", 24),
    1202           5 :       std::make_tuple("y[2]", 48), std::make_tuple("z[0]", 96)};
    1203             : 
    1204             :   DisableAlwaysOpt();
    1205           5 :   i::FLAG_allow_natives_syntax = true;
    1206           5 :   DisableEmbeddedBlobRefcounting();
    1207             :   v8::StartupData blob;
    1208             :   {
    1209           5 :     v8::SnapshotCreator creator;
    1210           5 :     v8::Isolate* isolate = creator.GetIsolate();
    1211             :     {
    1212           5 :       v8::HandleScope handle_scope(isolate);
    1213           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    1214             :       v8::Context::Scope context_scope(context);
    1215             : 
    1216             :       CompileRun(code);
    1217           5 :       TestInt32Expectations(expectations);
    1218             :       creator.SetDefaultContext(
    1219             :           context, v8::SerializeInternalFieldsCallback(
    1220          10 :                        SerializeInternalFields, reinterpret_cast<void*>(2016)));
    1221             :     }
    1222             :     blob =
    1223           5 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    1224             :   }
    1225             : 
    1226             :   v8::Isolate::CreateParams create_params;
    1227           5 :   create_params.snapshot_blob = &blob;
    1228           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    1229           5 :   v8::Isolate* isolate = TestSerializer::NewIsolate(create_params);
    1230             :   {
    1231             :     v8::Isolate::Scope i_scope(isolate);
    1232          10 :     v8::HandleScope h_scope(isolate);
    1233             :     v8::Local<v8::Context> context = v8::Context::New(
    1234             :         isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
    1235             :         v8::MaybeLocal<v8::Value>(),
    1236             :         v8::DeserializeInternalFieldsCallback(DeserializeInternalFields,
    1237           5 :                                               reinterpret_cast<void*>(2017)));
    1238             :     v8::Context::Scope c_scope(context);
    1239           5 :     TestInt32Expectations(expectations);
    1240             : 
    1241             :     i::Handle<i::JSArrayBuffer> buffer =
    1242           5 :         GetBufferFromTypedArray(CompileRun("x"));
    1243             :     // The resulting buffer should be on-heap.
    1244           5 :     CHECK_NULL(buffer->backing_store());
    1245             : 
    1246           5 :     buffer = GetBufferFromTypedArray(CompileRun("y"));
    1247           5 :     CHECK_NULL(buffer->backing_store());
    1248             : 
    1249           5 :     buffer = GetBufferFromTypedArray(CompileRun("z"));
    1250             :     // The resulting buffer should be off-heap.
    1251           5 :     CHECK_NOT_NULL(buffer->backing_store());
    1252             :   }
    1253           5 :   isolate->Dispose();
    1254           5 :   delete[] blob.data;  // We can dispose of the snapshot blob now.
    1255           5 :   FreeCurrentEmbeddedBlob();
    1256           5 : }
    1257             : 
    1258       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlob2) {
    1259             :   DisableAlwaysOpt();
    1260             :   const char* source2 =
    1261             :       "function f() { return g() * 2; }"
    1262             :       "function g() { return 43; }"
    1263             :       "/./.test('a')";
    1264             : 
    1265           5 :   v8::StartupData data2 = CreateSnapshotDataBlob(source2);
    1266             : 
    1267             :   v8::Isolate::CreateParams params2;
    1268           5 :   params2.snapshot_blob = &data2;
    1269           5 :   params2.array_buffer_allocator = CcTest::array_buffer_allocator();
    1270             :   // Test-appropriate equivalent of v8::Isolate::New.
    1271           5 :   v8::Isolate* isolate2 = TestSerializer::NewIsolate(params2);
    1272             :   {
    1273             :     v8::Isolate::Scope i_scope(isolate2);
    1274          10 :     v8::HandleScope h_scope(isolate2);
    1275           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate2);
    1276             :     v8::Context::Scope c_scope(context);
    1277             :     v8::Maybe<int32_t> result =
    1278          10 :         CompileRun("f()")->Int32Value(isolate2->GetCurrentContext());
    1279           5 :     CHECK_EQ(86, result.FromJust());
    1280          10 :     result = CompileRun("g()")->Int32Value(isolate2->GetCurrentContext());
    1281           5 :     CHECK_EQ(43, result.FromJust());
    1282             :   }
    1283           5 :   isolate2->Dispose();
    1284           5 :   delete[] data2.data;  // We can dispose of the snapshot blob now.
    1285           5 :   FreeCurrentEmbeddedBlob();
    1286           5 : }
    1287             : 
    1288           5 : static void SerializationFunctionTemplate(
    1289           5 :     const v8::FunctionCallbackInfo<v8::Value>& args) {
    1290             :   args.GetReturnValue().Set(args[0]);
    1291           5 : }
    1292             : 
    1293       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobOutdatedContextWithOverflow) {
    1294             :   DisableAlwaysOpt();
    1295             :   const char* source1 =
    1296             :       "var o = {};"
    1297             :       "(function() {"
    1298             :       "  function f1(x) { return f2(x) instanceof Array; }"
    1299             :       "  function f2(x) { return foo.bar(x); }"
    1300             :       "  o.a = f2.bind(null);"
    1301             :       "  o.b = 1;"
    1302             :       "  o.c = 2;"
    1303             :       "  o.d = 3;"
    1304             :       "  o.e = 4;"
    1305             :       "})();\n";
    1306             : 
    1307             :   const char* source2 = "o.a(42)";
    1308             : 
    1309           5 :   v8::StartupData data = CreateSnapshotDataBlob(source1);
    1310             : 
    1311             :   v8::Isolate::CreateParams params;
    1312           5 :   params.snapshot_blob = &data;
    1313           5 :   params.array_buffer_allocator = CcTest::array_buffer_allocator();
    1314             : 
    1315             :   // Test-appropriate equivalent of v8::Isolate::New.
    1316           5 :   v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    1317             :   {
    1318             :     v8::Isolate::Scope i_scope(isolate);
    1319          10 :     v8::HandleScope h_scope(isolate);
    1320             : 
    1321           5 :     v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
    1322           5 :     v8::Local<v8::ObjectTemplate> property = v8::ObjectTemplate::New(isolate);
    1323             :     v8::Local<v8::FunctionTemplate> function =
    1324           5 :         v8::FunctionTemplate::New(isolate, SerializationFunctionTemplate);
    1325             :     property->Set(isolate, "bar", function);
    1326             :     global->Set(isolate, "foo", property);
    1327             : 
    1328           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);
    1329             :     v8::Context::Scope c_scope(context);
    1330           5 :     v8::Local<v8::Value> result = CompileRun(source2);
    1331          10 :     v8::Maybe<bool> compare = v8_str("42")->Equals(
    1332          10 :         v8::Isolate::GetCurrent()->GetCurrentContext(), result);
    1333           5 :     CHECK(compare.FromJust());
    1334             :   }
    1335           5 :   isolate->Dispose();
    1336           5 :   delete[] data.data;  // We can dispose of the snapshot blob now.
    1337           5 :   FreeCurrentEmbeddedBlob();
    1338           5 : }
    1339             : 
    1340       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobWithLocker) {
    1341             :   DisableAlwaysOpt();
    1342             :   v8::Isolate::CreateParams create_params;
    1343           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    1344           5 :   DisableEmbeddedBlobRefcounting();
    1345           5 :   v8::Isolate* isolate0 = v8::Isolate::New(create_params);
    1346             :   {
    1347             :     v8::Locker locker(isolate0);
    1348             :     v8::Isolate::Scope i_scope(isolate0);
    1349          10 :     v8::HandleScope h_scope(isolate0);
    1350           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate0);
    1351             :     v8::Context::Scope c_scope(context);
    1352             :     v8::Maybe<int32_t> result =
    1353          10 :         CompileRun("Math.cos(0)")->Int32Value(isolate0->GetCurrentContext());
    1354          10 :     CHECK_EQ(1, result.FromJust());
    1355             :   }
    1356           5 :   isolate0->Dispose();
    1357             : 
    1358             :   const char* source1 = "function f() { return 42; }";
    1359             : 
    1360           5 :   v8::StartupData data1 = CreateSnapshotDataBlob(source1);
    1361             : 
    1362             :   v8::Isolate::CreateParams params1;
    1363           5 :   params1.snapshot_blob = &data1;
    1364           5 :   params1.array_buffer_allocator = CcTest::array_buffer_allocator();
    1365             :   // Test-appropriate equivalent of v8::Isolate::New.
    1366           5 :   v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
    1367             :   {
    1368             :     v8::Locker locker(isolate1);
    1369             :     v8::Isolate::Scope i_scope(isolate1);
    1370          10 :     v8::HandleScope h_scope(isolate1);
    1371           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate1);
    1372             :     v8::Context::Scope c_scope(context);
    1373           5 :     v8::Maybe<int32_t> result = CompileRun("f()")->Int32Value(context);
    1374          10 :     CHECK_EQ(42, result.FromJust());
    1375             :   }
    1376           5 :   isolate1->Dispose();
    1377           5 :   delete[] data1.data;  // We can dispose of the snapshot blob now.
    1378           5 :   FreeCurrentEmbeddedBlob();
    1379           5 : }
    1380             : 
    1381       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobStackOverflow) {
    1382             :   DisableAlwaysOpt();
    1383             :   const char* source =
    1384             :       "var a = [0];"
    1385             :       "var b = a;"
    1386             :       "for (var i = 0; i < 10000; i++) {"
    1387             :       "  var c = [i];"
    1388             :       "  b.push(c);"
    1389             :       "  b.push(c);"
    1390             :       "  b = c;"
    1391             :       "}";
    1392             : 
    1393           5 :   v8::StartupData data = CreateSnapshotDataBlob(source);
    1394             : 
    1395             :   v8::Isolate::CreateParams params;
    1396           5 :   params.snapshot_blob = &data;
    1397           5 :   params.array_buffer_allocator = CcTest::array_buffer_allocator();
    1398             : 
    1399             :   // Test-appropriate equivalent of v8::Isolate::New.
    1400           5 :   v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    1401             :   {
    1402             :     v8::Isolate::Scope i_scope(isolate);
    1403          10 :     v8::HandleScope h_scope(isolate);
    1404           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
    1405             :     v8::Context::Scope c_scope(context);
    1406             :     const char* test =
    1407             :         "var sum = 0;"
    1408             :         "while (a) {"
    1409             :         "  sum += a[0];"
    1410             :         "  a = a[1];"
    1411             :         "}"
    1412             :         "sum";
    1413             :     v8::Maybe<int32_t> result =
    1414          10 :         CompileRun(test)->Int32Value(isolate->GetCurrentContext());
    1415           5 :     CHECK_EQ(9999 * 5000, result.FromJust());
    1416             :   }
    1417           5 :   isolate->Dispose();
    1418           5 :   delete[] data.data;  // We can dispose of the snapshot blob now.
    1419           5 :   FreeCurrentEmbeddedBlob();
    1420           5 : }
    1421             : 
    1422          35 : bool IsCompiled(const char* name) {
    1423             :   return i::Handle<i::JSFunction>::cast(
    1424             :              v8::Utils::OpenHandle(*CompileRun(name)))
    1425         105 :       ->shared()
    1426          70 :       ->is_compiled();
    1427             : }
    1428             : 
    1429       28342 : UNINITIALIZED_TEST(SnapshotDataBlobWithWarmup) {
    1430             :   DisableAlwaysOpt();
    1431             :   const char* warmup = "Math.abs(1); Math.random = 1;";
    1432             : 
    1433           5 :   v8::StartupData cold = CreateSnapshotDataBlob();
    1434           5 :   v8::StartupData warm = WarmUpSnapshotDataBlob(cold, warmup);
    1435           5 :   delete[] cold.data;
    1436             : 
    1437             :   v8::Isolate::CreateParams params;
    1438           5 :   params.snapshot_blob = &warm;
    1439           5 :   params.array_buffer_allocator = CcTest::array_buffer_allocator();
    1440             : 
    1441             :   // Test-appropriate equivalent of v8::Isolate::New.
    1442           5 :   v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    1443             :   {
    1444             :     v8::Isolate::Scope i_scope(isolate);
    1445          10 :     v8::HandleScope h_scope(isolate);
    1446           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
    1447             :     v8::Context::Scope c_scope(context);
    1448             :     // Running the warmup script has effect on whether functions are
    1449             :     // pre-compiled, but does not pollute the context.
    1450           5 :     CHECK(IsCompiled("Math.abs"));
    1451           5 :     CHECK(IsCompiled("String.raw"));
    1452           5 :     CHECK(CompileRun("Math.random")->IsFunction());
    1453             :   }
    1454           5 :   isolate->Dispose();
    1455           5 :   delete[] warm.data;
    1456           5 :   FreeCurrentEmbeddedBlob();
    1457           5 : }
    1458             : 
    1459       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobWithWarmup) {
    1460             :   DisableAlwaysOpt();
    1461             :   const char* source =
    1462             :       "function f() { return Math.abs(1); }\n"
    1463             :       "function g() { return String.raw(1); }\n"
    1464             :       "Object.valueOf(1);"
    1465             :       "var a = 5";
    1466             :   const char* warmup = "a = f()";
    1467             : 
    1468           5 :   v8::StartupData cold = CreateSnapshotDataBlob(source);
    1469           5 :   v8::StartupData warm = WarmUpSnapshotDataBlob(cold, warmup);
    1470           5 :   delete[] cold.data;
    1471             : 
    1472             :   v8::Isolate::CreateParams params;
    1473           5 :   params.snapshot_blob = &warm;
    1474           5 :   params.array_buffer_allocator = CcTest::array_buffer_allocator();
    1475             : 
    1476             :   // Test-appropriate equivalent of v8::Isolate::New.
    1477           5 :   v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    1478             :   {
    1479             :     v8::Isolate::Scope i_scope(isolate);
    1480          10 :     v8::HandleScope h_scope(isolate);
    1481           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
    1482             :     v8::Context::Scope c_scope(context);
    1483             :     // Running the warmup script has effect on whether functions are
    1484             :     // pre-compiled, but does not pollute the context.
    1485           5 :     CHECK(IsCompiled("f"));
    1486           5 :     CHECK(IsCompiled("Math.abs"));
    1487           5 :     CHECK(!IsCompiled("g"));
    1488           5 :     CHECK(IsCompiled("String.raw"));
    1489           5 :     CHECK(IsCompiled("Array.prototype.lastIndexOf"));
    1490          10 :     CHECK_EQ(5, CompileRun("a")->Int32Value(context).FromJust());
    1491             :   }
    1492           5 :   isolate->Dispose();
    1493           5 :   delete[] warm.data;
    1494           5 :   FreeCurrentEmbeddedBlob();
    1495           5 : }
    1496             : 
    1497       28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobImmortalImmovableRoots) {
    1498             :   DisableAlwaysOpt();
    1499             :   // Flood the startup snapshot with shared function infos. If they are
    1500             :   // serialized before the immortal immovable root, the root will no longer end
    1501             :   // up on the first page.
    1502             :   Vector<const uint8_t> source =
    1503             :       ConstructSource(StaticCharVector("var a = [];"),
    1504             :                       StaticCharVector("a.push(function() {return 7});"),
    1505           5 :                       StaticCharVector("\0"), 10000);
    1506             : 
    1507             :   v8::StartupData data =
    1508           5 :       CreateSnapshotDataBlob(reinterpret_cast<const char*>(source.start()));
    1509             : 
    1510             :   v8::Isolate::CreateParams params;
    1511           5 :   params.snapshot_blob = &data;
    1512           5 :   params.array_buffer_allocator = CcTest::array_buffer_allocator();
    1513             : 
    1514             :   // Test-appropriate equivalent of v8::Isolate::New.
    1515           5 :   v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    1516             :   {
    1517             :     v8::Isolate::Scope i_scope(isolate);
    1518          10 :     v8::HandleScope h_scope(isolate);
    1519           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
    1520             :     v8::Context::Scope c_scope(context);
    1521          10 :     CHECK_EQ(7, CompileRun("a[0]()")->Int32Value(context).FromJust());
    1522             :   }
    1523           5 :   isolate->Dispose();
    1524             :   source.Dispose();
    1525           5 :   delete[] data.data;  // We can dispose of the snapshot blob now.
    1526           5 :   FreeCurrentEmbeddedBlob();
    1527           5 : }
    1528             : 
    1529       28342 : TEST(TestThatAlwaysSucceeds) {
    1530           5 : }
    1531             : 
    1532             : 
    1533       28337 : TEST(TestThatAlwaysFails) {
    1534             :   bool ArtificialFailure = false;
    1535           0 :   CHECK(ArtificialFailure);
    1536             : }
    1537             : 
    1538             : 
    1539          60 : int CountBuiltins() {
    1540             :   // Check that we have not deserialized any additional builtin.
    1541          60 :   HeapIterator iterator(CcTest::heap());
    1542             :   DisallowHeapAllocation no_allocation;
    1543             :   int counter = 0;
    1544      832238 :   for (HeapObject obj = iterator.next(); !obj.is_null();
    1545             :        obj = iterator.next()) {
    1546      506748 :     if (obj->IsCode() && Code::cast(obj)->kind() == Code::BUILTIN) counter++;
    1547             :   }
    1548          60 :   return counter;
    1549             : }
    1550             : 
    1551          75 : static Handle<SharedFunctionInfo> CompileScript(
    1552             :     Isolate* isolate, Handle<String> source, Handle<String> name,
    1553             :     ScriptData* cached_data, v8::ScriptCompiler::CompileOptions options) {
    1554             :   return Compiler::GetSharedFunctionInfoForScript(
    1555             :              isolate, source, Compiler::ScriptDetails(name),
    1556             :              v8::ScriptOriginOptions(), nullptr, cached_data, options,
    1557          75 :              ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE)
    1558         225 :       .ToHandleChecked();
    1559             : }
    1560             : 
    1561          80 : static Handle<SharedFunctionInfo> CompileScriptAndProduceCache(
    1562             :     Isolate* isolate, Handle<String> source, Handle<String> name,
    1563             :     ScriptData** script_data, v8::ScriptCompiler::CompileOptions options) {
    1564             :   Handle<SharedFunctionInfo> sfi =
    1565             :       Compiler::GetSharedFunctionInfoForScript(
    1566             :           isolate, source, Compiler::ScriptDetails(name),
    1567             :           v8::ScriptOriginOptions(), nullptr, nullptr, options,
    1568          80 :           ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE)
    1569         160 :           .ToHandleChecked();
    1570             :   std::unique_ptr<ScriptCompiler::CachedData> cached_data(
    1571          80 :       ScriptCompiler::CreateCodeCache(ToApiHandle<UnboundScript>(sfi)));
    1572          80 :   uint8_t* buffer = NewArray<uint8_t>(cached_data->length);
    1573          80 :   MemCopy(buffer, cached_data->data, cached_data->length);
    1574          80 :   *script_data = new i::ScriptData(buffer, cached_data->length);
    1575             :   (*script_data)->AcquireDataOwnership();
    1576         160 :   return sfi;
    1577             : }
    1578             : 
    1579          25 : void TestCodeSerializerOnePlusOneImpl() {
    1580          25 :   LocalContext context;
    1581          25 :   Isolate* isolate = CcTest::i_isolate();
    1582          25 :   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
    1583             : 
    1584          50 :   v8::HandleScope scope(CcTest::isolate());
    1585             : 
    1586             :   const char* source = "1 + 1";
    1587             : 
    1588             :   Handle<String> orig_source = isolate->factory()
    1589             :                                    ->NewStringFromUtf8(CStrVector(source))
    1590          50 :                                    .ToHandleChecked();
    1591             :   Handle<String> copy_source = isolate->factory()
    1592             :                                    ->NewStringFromUtf8(CStrVector(source))
    1593          50 :                                    .ToHandleChecked();
    1594          25 :   CHECK(!orig_source.is_identical_to(copy_source));
    1595          25 :   CHECK(orig_source->Equals(*copy_source));
    1596             : 
    1597          25 :   ScriptData* cache = nullptr;
    1598             : 
    1599             :   Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
    1600             :       isolate, orig_source, Handle<String>(), &cache,
    1601          25 :       v8::ScriptCompiler::kNoCompileOptions);
    1602             : 
    1603          25 :   int builtins_count = CountBuiltins();
    1604             : 
    1605             :   Handle<SharedFunctionInfo> copy;
    1606             :   {
    1607             :     DisallowCompilation no_compile_expected(isolate);
    1608             :     copy = CompileScript(isolate, copy_source, Handle<String>(), cache,
    1609          50 :                          v8::ScriptCompiler::kConsumeCodeCache);
    1610             :   }
    1611             : 
    1612          75 :   CHECK_NE(*orig, *copy);
    1613          75 :   CHECK(Script::cast(copy->script())->source() == *copy_source);
    1614             : 
    1615             :   Handle<JSFunction> copy_fun =
    1616             :       isolate->factory()->NewFunctionFromSharedFunctionInfo(
    1617          50 :           copy, isolate->native_context());
    1618          50 :   Handle<JSObject> global(isolate->context()->global_object(), isolate);
    1619             :   Handle<Object> copy_result =
    1620          50 :       Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
    1621          50 :   CHECK_EQ(2, Handle<Smi>::cast(copy_result)->value());
    1622             : 
    1623          25 :   CHECK_EQ(builtins_count, CountBuiltins());
    1624             : 
    1625          75 :   delete cache;
    1626          25 : }
    1627             : 
    1628       28342 : TEST(CodeSerializerOnePlusOne) { TestCodeSerializerOnePlusOneImpl(); }
    1629             : 
    1630       28342 : TEST(CodeSerializerOnePlusOneWithDebugger) {
    1631           5 :   v8::HandleScope scope(CcTest::isolate());
    1632           5 :   static v8::debug::DebugDelegate dummy_delegate;
    1633           5 :   v8::debug::SetDebugDelegate(CcTest::isolate(), &dummy_delegate);
    1634           5 :   TestCodeSerializerOnePlusOneImpl();
    1635           5 : }
    1636             : 
    1637       28342 : TEST(CodeSerializerOnePlusOne1) {
    1638           5 :   FLAG_serialization_chunk_size = 1;
    1639           5 :   TestCodeSerializerOnePlusOneImpl();
    1640           5 : }
    1641             : 
    1642       28342 : TEST(CodeSerializerOnePlusOne32) {
    1643           5 :   FLAG_serialization_chunk_size = 32;
    1644           5 :   TestCodeSerializerOnePlusOneImpl();
    1645           5 : }
    1646             : 
    1647       28342 : TEST(CodeSerializerOnePlusOne4K) {
    1648           5 :   FLAG_serialization_chunk_size = 4 * KB;
    1649           5 :   TestCodeSerializerOnePlusOneImpl();
    1650           5 : }
    1651             : 
    1652       28342 : TEST(CodeSerializerPromotedToCompilationCache) {
    1653           5 :   LocalContext context;
    1654           5 :   Isolate* isolate = CcTest::i_isolate();
    1655             : 
    1656          10 :   v8::HandleScope scope(CcTest::isolate());
    1657             : 
    1658             :   const char* source = "1 + 1";
    1659             : 
    1660             :   Handle<String> src = isolate->factory()
    1661             :                            ->NewStringFromUtf8(CStrVector(source))
    1662          10 :                            .ToHandleChecked();
    1663           5 :   ScriptData* cache = nullptr;
    1664             : 
    1665             :   CompileScriptAndProduceCache(isolate, src, src, &cache,
    1666           5 :                                v8::ScriptCompiler::kNoCompileOptions);
    1667             : 
    1668             :   DisallowCompilation no_compile_expected(isolate);
    1669             :   Handle<SharedFunctionInfo> copy = CompileScript(
    1670           5 :       isolate, src, src, cache, v8::ScriptCompiler::kConsumeCodeCache);
    1671             : 
    1672             :   MaybeHandle<SharedFunctionInfo> shared =
    1673             :       isolate->compilation_cache()->LookupScript(
    1674             :           src, src, 0, 0, v8::ScriptOriginOptions(), isolate->native_context(),
    1675          10 :           LanguageMode::kSloppy);
    1676             : 
    1677           5 :   CHECK(*shared.ToHandleChecked() == *copy);
    1678             : 
    1679          15 :   delete cache;
    1680           5 : }
    1681             : 
    1682       28342 : TEST(CodeSerializerInternalizedString) {
    1683           5 :   LocalContext context;
    1684           5 :   Isolate* isolate = CcTest::i_isolate();
    1685           5 :   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
    1686             : 
    1687          10 :   v8::HandleScope scope(CcTest::isolate());
    1688             : 
    1689             :   const char* source = "'string1'";
    1690             : 
    1691             :   Handle<String> orig_source = isolate->factory()
    1692             :                                    ->NewStringFromUtf8(CStrVector(source))
    1693          10 :                                    .ToHandleChecked();
    1694             :   Handle<String> copy_source = isolate->factory()
    1695             :                                    ->NewStringFromUtf8(CStrVector(source))
    1696          10 :                                    .ToHandleChecked();
    1697           5 :   CHECK(!orig_source.is_identical_to(copy_source));
    1698           5 :   CHECK(orig_source->Equals(*copy_source));
    1699             : 
    1700          10 :   Handle<JSObject> global(isolate->context()->global_object(), isolate);
    1701             : 
    1702           5 :   i::ScriptData* script_data = nullptr;
    1703             :   Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
    1704             :       isolate, orig_source, Handle<String>(), &script_data,
    1705           5 :       v8::ScriptCompiler::kNoCompileOptions);
    1706             :   Handle<JSFunction> orig_fun =
    1707             :       isolate->factory()->NewFunctionFromSharedFunctionInfo(
    1708          10 :           orig, isolate->native_context());
    1709             :   Handle<Object> orig_result =
    1710          10 :       Execution::Call(isolate, orig_fun, global, 0, nullptr).ToHandleChecked();
    1711          10 :   CHECK(orig_result->IsInternalizedString());
    1712             : 
    1713           5 :   int builtins_count = CountBuiltins();
    1714             : 
    1715             :   Handle<SharedFunctionInfo> copy;
    1716             :   {
    1717             :     DisallowCompilation no_compile_expected(isolate);
    1718             :     copy = CompileScript(isolate, copy_source, Handle<String>(), script_data,
    1719          10 :                          v8::ScriptCompiler::kConsumeCodeCache);
    1720             :   }
    1721          15 :   CHECK_NE(*orig, *copy);
    1722          15 :   CHECK(Script::cast(copy->script())->source() == *copy_source);
    1723             : 
    1724             :   Handle<JSFunction> copy_fun =
    1725             :       isolate->factory()->NewFunctionFromSharedFunctionInfo(
    1726          10 :           copy, isolate->native_context());
    1727          15 :   CHECK_NE(*orig_fun, *copy_fun);
    1728             :   Handle<Object> copy_result =
    1729          10 :       Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
    1730           5 :   CHECK(orig_result.is_identical_to(copy_result));
    1731             :   Handle<String> expected =
    1732           5 :       isolate->factory()->NewStringFromAsciiChecked("string1");
    1733             : 
    1734          10 :   CHECK(Handle<String>::cast(copy_result)->Equals(*expected));
    1735           5 :   CHECK_EQ(builtins_count, CountBuiltins());
    1736             : 
    1737          15 :   delete script_data;
    1738           5 : }
    1739             : 
    1740       28342 : TEST(CodeSerializerLargeCodeObject) {
    1741           5 :   LocalContext context;
    1742           5 :   Isolate* isolate = CcTest::i_isolate();
    1743           5 :   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
    1744             : 
    1745          10 :   v8::HandleScope scope(CcTest::isolate());
    1746             : 
    1747             :   // The serializer only tests the shared code, which is always the unoptimized
    1748             :   // code. Don't even bother generating optimized code to avoid timeouts.
    1749           5 :   FLAG_always_opt = false;
    1750             : 
    1751             :   Vector<const uint8_t> source = ConstructSource(
    1752             :       StaticCharVector("var j=1; if (j == 0) {"),
    1753             :       StaticCharVector(
    1754             :           "for (let i of Object.prototype) for (let k = 0; k < 0; ++k);"),
    1755           5 :       StaticCharVector("} j=7; j"), 2000);
    1756             :   Handle<String> source_str =
    1757          10 :       isolate->factory()->NewStringFromOneByte(source).ToHandleChecked();
    1758             : 
    1759          10 :   Handle<JSObject> global(isolate->context()->global_object(), isolate);
    1760           5 :   ScriptData* cache = nullptr;
    1761             : 
    1762             :   Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
    1763             :       isolate, source_str, Handle<String>(), &cache,
    1764           5 :       v8::ScriptCompiler::kNoCompileOptions);
    1765             : 
    1766           5 :   CHECK(isolate->heap()->InSpace(orig->abstract_code(), LO_SPACE));
    1767             : 
    1768             :   Handle<SharedFunctionInfo> copy;
    1769             :   {
    1770             :     DisallowCompilation no_compile_expected(isolate);
    1771             :     copy = CompileScript(isolate, source_str, Handle<String>(), cache,
    1772          10 :                          v8::ScriptCompiler::kConsumeCodeCache);
    1773             :   }
    1774          15 :   CHECK_NE(*orig, *copy);
    1775             : 
    1776             :   Handle<JSFunction> copy_fun =
    1777             :       isolate->factory()->NewFunctionFromSharedFunctionInfo(
    1778          10 :           copy, isolate->native_context());
    1779             : 
    1780             :   Handle<Object> copy_result =
    1781          10 :       Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
    1782             : 
    1783             :   int result_int;
    1784           5 :   CHECK(copy_result->ToInt32(&result_int));
    1785           5 :   CHECK_EQ(7, result_int);
    1786             : 
    1787          10 :   delete cache;
    1788           5 :   source.Dispose();
    1789           5 : }
    1790             : 
    1791       28342 : TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) {
    1792           5 :   if (FLAG_never_compact) return;
    1793             :   ManualGCScope manual_gc_scope;
    1794           5 :   FLAG_always_opt = false;
    1795             :   const char* filter_flag = "--turbo-filter=NOTHING";
    1796           5 :   FlagList::SetFlagsFromString(filter_flag, StrLength(filter_flag));
    1797           5 :   FLAG_black_allocation = true;
    1798           5 :   FLAG_manual_evacuation_candidates_selection = true;
    1799             : 
    1800          10 :   LocalContext context;
    1801           5 :   Isolate* isolate = CcTest::i_isolate();
    1802          15 :   Heap* heap = isolate->heap();
    1803           5 :   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
    1804             : 
    1805          10 :   v8::HandleScope scope(CcTest::isolate());
    1806             : 
    1807             :   Vector<const uint8_t> source = ConstructSource(
    1808             :       StaticCharVector("var j=1; if (j == 0) {"),
    1809             :       StaticCharVector("for (var i = 0; i < Object.prototype; i++);"),
    1810           5 :       StaticCharVector("} j=7; var s = 'happy_hippo'; j"), 20000);
    1811             :   Handle<String> source_str =
    1812          10 :       isolate->factory()->NewStringFromOneByte(source).ToHandleChecked();
    1813             : 
    1814             :   // Create a string on an evacuation candidate in old space.
    1815             :   Handle<String> moving_object;
    1816             :   Page* ec_page;
    1817             :   {
    1818             :     AlwaysAllocateScope always_allocate(isolate);
    1819           5 :     heap::SimulateFullSpace(heap->old_space());
    1820             :     moving_object = isolate->factory()->InternalizeString(
    1821           5 :         isolate->factory()->NewStringFromAsciiChecked("happy_hippo"));
    1822             :     ec_page = Page::FromHeapObject(*moving_object);
    1823             :   }
    1824             : 
    1825          10 :   Handle<JSObject> global(isolate->context()->global_object(), isolate);
    1826           5 :   ScriptData* cache = nullptr;
    1827             : 
    1828             :   Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
    1829             :       isolate, source_str, Handle<String>(), &cache,
    1830           5 :       v8::ScriptCompiler::kNoCompileOptions);
    1831             : 
    1832           5 :   CHECK(heap->InSpace(orig->abstract_code(), LO_SPACE));
    1833             : 
    1834             :   // Pretend that incremental marking is on when deserialization begins.
    1835           5 :   heap::ForceEvacuationCandidate(ec_page);
    1836           5 :   heap::SimulateIncrementalMarking(heap, false);
    1837             :   IncrementalMarking* marking = heap->incremental_marking();
    1838             :   marking->StartBlackAllocationForTesting();
    1839           5 :   CHECK(marking->IsCompacting());
    1840           5 :   CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*moving_object));
    1841             : 
    1842             :   Handle<SharedFunctionInfo> copy;
    1843             :   {
    1844             :     DisallowCompilation no_compile_expected(isolate);
    1845             :     copy = CompileScript(isolate, source_str, Handle<String>(), cache,
    1846          10 :                          v8::ScriptCompiler::kConsumeCodeCache);
    1847             :   }
    1848          15 :   CHECK_NE(*orig, *copy);
    1849             : 
    1850             :   // We should have missed a write barrier. Complete incremental marking
    1851             :   // to flush out the bug.
    1852           5 :   heap::SimulateIncrementalMarking(heap, true);
    1853           5 :   CcTest::CollectAllGarbage();
    1854             : 
    1855             :   Handle<JSFunction> copy_fun =
    1856             :       isolate->factory()->NewFunctionFromSharedFunctionInfo(
    1857          10 :           copy, isolate->native_context());
    1858             : 
    1859             :   Handle<Object> copy_result =
    1860          10 :       Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
    1861             : 
    1862             :   int result_int;
    1863           5 :   CHECK(copy_result->ToInt32(&result_int));
    1864           5 :   CHECK_EQ(7, result_int);
    1865             : 
    1866          10 :   delete cache;
    1867             :   source.Dispose();
    1868             : }
    1869       28342 : TEST(CodeSerializerLargeStrings) {
    1870           5 :   LocalContext context;
    1871           5 :   Isolate* isolate = CcTest::i_isolate();
    1872             :   Factory* f = isolate->factory();
    1873           5 :   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
    1874             : 
    1875          10 :   v8::HandleScope scope(CcTest::isolate());
    1876             : 
    1877             :   Vector<const uint8_t> source_s = ConstructSource(
    1878             :       StaticCharVector("var s = \""), StaticCharVector("abcdef"),
    1879           5 :       StaticCharVector("\";"), 1000000);
    1880             :   Vector<const uint8_t> source_t = ConstructSource(
    1881             :       StaticCharVector("var t = \""), StaticCharVector("uvwxyz"),
    1882           5 :       StaticCharVector("\"; s + t"), 999999);
    1883             :   Handle<String> source_str =
    1884             :       f->NewConsString(f->NewStringFromOneByte(source_s).ToHandleChecked(),
    1885          15 :                        f->NewStringFromOneByte(source_t).ToHandleChecked())
    1886          10 :           .ToHandleChecked();
    1887             : 
    1888          10 :   Handle<JSObject> global(isolate->context()->global_object(), isolate);
    1889           5 :   ScriptData* cache = nullptr;
    1890             : 
    1891             :   Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
    1892             :       isolate, source_str, Handle<String>(), &cache,
    1893           5 :       v8::ScriptCompiler::kNoCompileOptions);
    1894             : 
    1895             :   Handle<SharedFunctionInfo> copy;
    1896             :   {
    1897             :     DisallowCompilation no_compile_expected(isolate);
    1898             :     copy = CompileScript(isolate, source_str, Handle<String>(), cache,
    1899          15 :                          v8::ScriptCompiler::kConsumeCodeCache);
    1900             :   }
    1901          15 :   CHECK_NE(*orig, *copy);
    1902             : 
    1903             :   Handle<JSFunction> copy_fun =
    1904             :       isolate->factory()->NewFunctionFromSharedFunctionInfo(
    1905          10 :           copy, isolate->native_context());
    1906             : 
    1907             :   Handle<Object> copy_result =
    1908          10 :       Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
    1909             : 
    1910          10 :   CHECK_EQ(6 * 1999999, Handle<String>::cast(copy_result)->length());
    1911             :   Handle<Object> property = JSReceiver::GetDataProperty(
    1912          15 :       isolate->global_object(), f->NewStringFromAsciiChecked("s"));
    1913           5 :   CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
    1914             :   property = JSReceiver::GetDataProperty(isolate->global_object(),
    1915          15 :                                          f->NewStringFromAsciiChecked("t"));
    1916           5 :   CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
    1917             :   // Make sure we do not serialize too much, e.g. include the source string.
    1918          10 :   CHECK_LT(cache->length(), 13000000);
    1919             : 
    1920          10 :   delete cache;
    1921             :   source_s.Dispose();
    1922           5 :   source_t.Dispose();
    1923           5 : }
    1924             : 
    1925       28342 : TEST(CodeSerializerThreeBigStrings) {
    1926           5 :   LocalContext context;
    1927           5 :   Isolate* isolate = CcTest::i_isolate();
    1928             :   Factory* f = isolate->factory();
    1929           5 :   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
    1930             : 
    1931          10 :   v8::HandleScope scope(CcTest::isolate());
    1932             : 
    1933             :   Vector<const uint8_t> source_a =
    1934             :       ConstructSource(StaticCharVector("var a = \""), StaticCharVector("a"),
    1935           5 :                       StaticCharVector("\";"), 700000);
    1936             :   Handle<String> source_a_str =
    1937          10 :       f->NewStringFromOneByte(source_a).ToHandleChecked();
    1938             : 
    1939             :   Vector<const uint8_t> source_b =
    1940             :       ConstructSource(StaticCharVector("var b = \""), StaticCharVector("b"),
    1941           5 :                       StaticCharVector("\";"), 400000);
    1942             :   Handle<String> source_b_str =
    1943          10 :       f->NewStringFromOneByte(source_b).ToHandleChecked();
    1944             : 
    1945             :   Vector<const uint8_t> source_c =
    1946             :       ConstructSource(StaticCharVector("var c = \""), StaticCharVector("c"),
    1947           5 :                       StaticCharVector("\";"), 400000);
    1948             :   Handle<String> source_c_str =
    1949          10 :       f->NewStringFromOneByte(source_c).ToHandleChecked();
    1950             : 
    1951             :   Handle<String> source_str =
    1952             :       f->NewConsString(
    1953             :              f->NewConsString(source_a_str, source_b_str).ToHandleChecked(),
    1954          15 :              source_c_str).ToHandleChecked();
    1955             : 
    1956          10 :   Handle<JSObject> global(isolate->context()->global_object(), isolate);
    1957           5 :   ScriptData* cache = nullptr;
    1958             : 
    1959             :   Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
    1960             :       isolate, source_str, Handle<String>(), &cache,
    1961           5 :       v8::ScriptCompiler::kNoCompileOptions);
    1962             : 
    1963             :   Handle<SharedFunctionInfo> copy;
    1964             :   {
    1965             :     DisallowCompilation no_compile_expected(isolate);
    1966             :     copy = CompileScript(isolate, source_str, Handle<String>(), cache,
    1967          10 :                          v8::ScriptCompiler::kConsumeCodeCache);
    1968             :   }
    1969          15 :   CHECK_NE(*orig, *copy);
    1970             : 
    1971             :   Handle<JSFunction> copy_fun =
    1972             :       isolate->factory()->NewFunctionFromSharedFunctionInfo(
    1973          10 :           copy, isolate->native_context());
    1974             : 
    1975           5 :   USE(Execution::Call(isolate, copy_fun, global, 0, nullptr));
    1976             : 
    1977             :   v8::Maybe<int32_t> result =
    1978             :       CompileRun("(a + b).length")
    1979          10 :           ->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext());
    1980           5 :   CHECK_EQ(400000 + 700000, result.FromJust());
    1981             :   result = CompileRun("(b + c).length")
    1982          10 :                ->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext());
    1983           5 :   CHECK_EQ(400000 + 400000, result.FromJust());
    1984           5 :   Heap* heap = isolate->heap();
    1985             :   v8::Local<v8::String> result_str =
    1986             :       CompileRun("a")
    1987           5 :           ->ToString(CcTest::isolate()->GetCurrentContext())
    1988           5 :           .ToLocalChecked();
    1989           5 :   CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), LO_SPACE));
    1990             :   result_str = CompileRun("b")
    1991           5 :                    ->ToString(CcTest::isolate()->GetCurrentContext())
    1992           5 :                    .ToLocalChecked();
    1993             : #if V8_HOST_ARCH_PPC
    1994             :   CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), LO_SPACE));
    1995             : #else
    1996           5 :   CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), OLD_SPACE));
    1997             : #endif
    1998             : 
    1999             :   result_str = CompileRun("c")
    2000           5 :                    ->ToString(CcTest::isolate()->GetCurrentContext())
    2001           5 :                    .ToLocalChecked();
    2002             : #if V8_HOST_ARCH_PPC
    2003             :   CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), LO_SPACE));
    2004             : #else
    2005           5 :   CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), OLD_SPACE));
    2006             : #endif
    2007             : 
    2008          10 :   delete cache;
    2009             :   source_a.Dispose();
    2010             :   source_b.Dispose();
    2011           5 :   source_c.Dispose();
    2012           5 : }
    2013             : 
    2014             : 
    2015       56689 : class SerializerOneByteResource
    2016             :     : public v8::String::ExternalOneByteStringResource {
    2017             :  public:
    2018             :   SerializerOneByteResource(const char* data, size_t length)
    2019       28352 :       : data_(data), length_(length), dispose_count_(0) {}
    2020         112 :   const char* data() const override { return data_; }
    2021          40 :   size_t length() const override { return length_; }
    2022          15 :   void Dispose() override { dispose_count_++; }
    2023             :   int dispose_count() { return dispose_count_; }
    2024             : 
    2025             :  private:
    2026             :   const char* data_;
    2027             :   size_t length_;
    2028             :   int dispose_count_;
    2029             : };
    2030             : 
    2031             : 
    2032             : class SerializerTwoByteResource : public v8::String::ExternalStringResource {
    2033             :  public:
    2034             :   SerializerTwoByteResource(const char* data, size_t length)
    2035       28342 :       : data_(AsciiToTwoByteString(data)), length_(length), dispose_count_(0) {}
    2036       56679 :   ~SerializerTwoByteResource() override { DeleteArray<const uint16_t>(data_); }
    2037             : 
    2038          72 :   const uint16_t* data() const override { return data_; }
    2039          25 :   size_t length() const override { return length_; }
    2040          15 :   void Dispose() override { dispose_count_++; }
    2041             :   int dispose_count() { return dispose_count_; }
    2042             : 
    2043             :  private:
    2044             :   const uint16_t* data_;
    2045             :   size_t length_;
    2046             :   int dispose_count_;
    2047             : };
    2048             : 
    2049       28342 : TEST(CodeSerializerExternalString) {
    2050           5 :   LocalContext context;
    2051           5 :   Isolate* isolate = CcTest::i_isolate();
    2052           5 :   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
    2053             : 
    2054          10 :   v8::HandleScope scope(CcTest::isolate());
    2055             : 
    2056             :   // Obtain external internalized one-byte string.
    2057             :   SerializerOneByteResource one_byte_resource("one_byte", 8);
    2058             :   Handle<String> one_byte_string =
    2059           5 :       isolate->factory()->NewStringFromAsciiChecked("one_byte");
    2060           5 :   one_byte_string = isolate->factory()->InternalizeString(one_byte_string);
    2061           5 :   one_byte_string->MakeExternal(&one_byte_resource);
    2062          10 :   CHECK(one_byte_string->IsExternalOneByteString());
    2063          10 :   CHECK(one_byte_string->IsInternalizedString());
    2064             : 
    2065             :   // Obtain external internalized two-byte string.
    2066             :   SerializerTwoByteResource two_byte_resource("two_byte", 8);
    2067             :   Handle<String> two_byte_string =
    2068           5 :       isolate->factory()->NewStringFromAsciiChecked("two_byte");
    2069           5 :   two_byte_string = isolate->factory()->InternalizeString(two_byte_string);
    2070           5 :   two_byte_string->MakeExternal(&two_byte_resource);
    2071          10 :   CHECK(two_byte_string->IsExternalTwoByteString());
    2072          10 :   CHECK(two_byte_string->IsInternalizedString());
    2073             : 
    2074             :   const char* source =
    2075             :       "var o = {}               \n"
    2076             :       "o.one_byte = 7;          \n"
    2077             :       "o.two_byte = 8;          \n"
    2078             :       "o.one_byte + o.two_byte; \n";
    2079             :   Handle<String> source_string = isolate->factory()
    2080             :                                      ->NewStringFromUtf8(CStrVector(source))
    2081          10 :                                      .ToHandleChecked();
    2082             : 
    2083          10 :   Handle<JSObject> global(isolate->context()->global_object(), isolate);
    2084           5 :   ScriptData* cache = nullptr;
    2085             : 
    2086             :   Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
    2087             :       isolate, source_string, Handle<String>(), &cache,
    2088           5 :       v8::ScriptCompiler::kNoCompileOptions);
    2089             : 
    2090             :   Handle<SharedFunctionInfo> copy;
    2091             :   {
    2092             :     DisallowCompilation no_compile_expected(isolate);
    2093             :     copy = CompileScript(isolate, source_string, Handle<String>(), cache,
    2094          10 :                          v8::ScriptCompiler::kConsumeCodeCache);
    2095             :   }
    2096          15 :   CHECK_NE(*orig, *copy);
    2097             : 
    2098             :   Handle<JSFunction> copy_fun =
    2099             :       isolate->factory()->NewFunctionFromSharedFunctionInfo(
    2100          10 :           copy, isolate->native_context());
    2101             : 
    2102             :   Handle<Object> copy_result =
    2103          10 :       Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
    2104             : 
    2105           5 :   CHECK_EQ(15.0, copy_result->Number());
    2106             : 
    2107             :   // This avoids the GC from trying to free stack allocated resources.
    2108             :   i::Handle<i::ExternalOneByteString>::cast(one_byte_string)
    2109          10 :       ->SetResource(isolate, nullptr);
    2110             :   i::Handle<i::ExternalTwoByteString>::cast(two_byte_string)
    2111          10 :       ->SetResource(isolate, nullptr);
    2112          15 :   delete cache;
    2113           5 : }
    2114             : 
    2115       28342 : TEST(CodeSerializerLargeExternalString) {
    2116           5 :   LocalContext context;
    2117           5 :   Isolate* isolate = CcTest::i_isolate();
    2118           5 :   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
    2119             : 
    2120             :   Factory* f = isolate->factory();
    2121             : 
    2122          10 :   v8::HandleScope scope(CcTest::isolate());
    2123             : 
    2124             :   // Create a huge external internalized string to use as variable name.
    2125             :   Vector<const uint8_t> string =
    2126             :       ConstructSource(StaticCharVector(""), StaticCharVector("abcdef"),
    2127           5 :                       StaticCharVector(""), 999999);
    2128          10 :   Handle<String> name = f->NewStringFromOneByte(string).ToHandleChecked();
    2129             :   SerializerOneByteResource one_byte_resource(
    2130           5 :       reinterpret_cast<const char*>(string.start()), string.length());
    2131           5 :   name = f->InternalizeString(name);
    2132           5 :   name->MakeExternal(&one_byte_resource);
    2133          10 :   CHECK(name->IsExternalOneByteString());
    2134          10 :   CHECK(name->IsInternalizedString());
    2135           5 :   CHECK(isolate->heap()->InSpace(*name, LO_SPACE));
    2136             : 
    2137             :   // Create the source, which is "var <literal> = 42; <literal>".
    2138             :   Handle<String> source_str =
    2139             :       f->NewConsString(
    2140           5 :              f->NewConsString(f->NewStringFromAsciiChecked("var "), name)
    2141             :                  .ToHandleChecked(),
    2142           5 :              f->NewConsString(f->NewStringFromAsciiChecked(" = 42; "), name)
    2143          20 :                  .ToHandleChecked()).ToHandleChecked();
    2144             : 
    2145          10 :   Handle<JSObject> global(isolate->context()->global_object(), isolate);
    2146           5 :   ScriptData* cache = nullptr;
    2147             : 
    2148             :   Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
    2149             :       isolate, source_str, Handle<String>(), &cache,
    2150           5 :       v8::ScriptCompiler::kNoCompileOptions);
    2151             : 
    2152             :   Handle<SharedFunctionInfo> copy;
    2153             :   {
    2154             :     DisallowCompilation no_compile_expected(isolate);
    2155             :     copy = CompileScript(isolate, source_str, Handle<String>(), cache,
    2156          10 :                          v8::ScriptCompiler::kConsumeCodeCache);
    2157             :   }
    2158          15 :   CHECK_NE(*orig, *copy);
    2159             : 
    2160             :   Handle<JSFunction> copy_fun =
    2161          10 :       f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
    2162             : 
    2163             :   Handle<Object> copy_result =
    2164          10 :       Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
    2165             : 
    2166           5 :   CHECK_EQ(42.0, copy_result->Number());
    2167             : 
    2168             :   // This avoids the GC from trying to free stack allocated resources.
    2169          10 :   i::Handle<i::ExternalOneByteString>::cast(name)->SetResource(isolate,
    2170           5 :                                                                nullptr);
    2171          10 :   delete cache;
    2172           5 :   string.Dispose();
    2173           5 : }
    2174             : 
    2175       28342 : TEST(CodeSerializerExternalScriptName) {
    2176           5 :   LocalContext context;
    2177           5 :   Isolate* isolate = CcTest::i_isolate();
    2178           5 :   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
    2179             : 
    2180             :   Factory* f = isolate->factory();
    2181             : 
    2182          10 :   v8::HandleScope scope(CcTest::isolate());
    2183             : 
    2184             :   const char* source =
    2185             :       "var a = [1, 2, 3, 4];"
    2186             :       "a.reduce(function(x, y) { return x + y }, 0)";
    2187             : 
    2188             :   Handle<String> source_string =
    2189          10 :       f->NewStringFromUtf8(CStrVector(source)).ToHandleChecked();
    2190             : 
    2191             :   const SerializerOneByteResource one_byte_resource("one_byte", 8);
    2192             :   Handle<String> name =
    2193          10 :       f->NewExternalStringFromOneByte(&one_byte_resource).ToHandleChecked();
    2194          10 :   CHECK(name->IsExternalOneByteString());
    2195          10 :   CHECK(!name->IsInternalizedString());
    2196             : 
    2197          10 :   Handle<JSObject> global(isolate->context()->global_object(), isolate);
    2198           5 :   ScriptData* cache = nullptr;
    2199             : 
    2200             :   Handle<SharedFunctionInfo> orig =
    2201             :       CompileScriptAndProduceCache(isolate, source_string, name, &cache,
    2202           5 :                                    v8::ScriptCompiler::kNoCompileOptions);
    2203             : 
    2204             :   Handle<SharedFunctionInfo> copy;
    2205             :   {
    2206             :     DisallowCompilation no_compile_expected(isolate);
    2207             :     copy = CompileScript(isolate, source_string, name, cache,
    2208           5 :                          v8::ScriptCompiler::kConsumeCodeCache);
    2209             :   }
    2210          15 :   CHECK_NE(*orig, *copy);
    2211             : 
    2212             :   Handle<JSFunction> copy_fun =
    2213          10 :       f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
    2214             : 
    2215             :   Handle<Object> copy_result =
    2216          10 :       Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
    2217             : 
    2218           5 :   CHECK_EQ(10.0, copy_result->Number());
    2219             : 
    2220             :   // This avoids the GC from trying to free stack allocated resources.
    2221          10 :   i::Handle<i::ExternalOneByteString>::cast(name)->SetResource(isolate,
    2222           5 :                                                                nullptr);
    2223          15 :   delete cache;
    2224           5 : }
    2225             : 
    2226             : 
    2227             : static bool toplevel_test_code_event_found = false;
    2228             : 
    2229             : 
    2230          88 : static void SerializerCodeEventListener(const v8::JitCodeEvent* event) {
    2231         118 :   if (event->type == v8::JitCodeEvent::CODE_ADDED &&
    2232          50 :       (memcmp(event->name.str, "Script:~ test", 13) == 0 ||
    2233          20 :        memcmp(event->name.str, "Script: test", 12) == 0)) {
    2234          10 :     toplevel_test_code_event_found = true;
    2235             :   }
    2236          88 : }
    2237             : 
    2238          25 : v8::ScriptCompiler::CachedData* CompileRunAndProduceCache(
    2239             :     const char* source, CodeCacheType cacheType = CodeCacheType::kLazy) {
    2240             :   v8::ScriptCompiler::CachedData* cache;
    2241             :   v8::Isolate::CreateParams create_params;
    2242          25 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2243          25 :   v8::Isolate* isolate1 = v8::Isolate::New(create_params);
    2244             :   {
    2245             :     v8::Isolate::Scope iscope(isolate1);
    2246          50 :     v8::HandleScope scope(isolate1);
    2247          25 :     v8::Local<v8::Context> context = v8::Context::New(isolate1);
    2248             :     v8::Context::Scope context_scope(context);
    2249             : 
    2250          25 :     v8::Local<v8::String> source_str = v8_str(source);
    2251          25 :     v8::ScriptOrigin origin(v8_str("test"));
    2252             :     v8::ScriptCompiler::Source source(source_str, origin);
    2253             :     v8::ScriptCompiler::CompileOptions options;
    2254          25 :     switch (cacheType) {
    2255             :       case CodeCacheType::kEager:
    2256             :         options = v8::ScriptCompiler::kEagerCompile;
    2257             :         break;
    2258             :       case CodeCacheType::kLazy:
    2259             :       case CodeCacheType::kAfterExecute:
    2260             :         options = v8::ScriptCompiler::kNoCompileOptions;
    2261          20 :         break;
    2262             :       default:
    2263           0 :         UNREACHABLE();
    2264             :     }
    2265             :     v8::Local<v8::UnboundScript> script =
    2266             :         v8::ScriptCompiler::CompileUnboundScript(isolate1, &source, options)
    2267          25 :             .ToLocalChecked();
    2268             : 
    2269          25 :     if (cacheType != CodeCacheType::kAfterExecute) {
    2270          20 :       cache = ScriptCompiler::CreateCodeCache(script);
    2271             :     }
    2272             : 
    2273             :     v8::Local<v8::Value> result = script->BindToCurrentContext()
    2274          50 :                                       ->Run(isolate1->GetCurrentContext())
    2275          25 :                                       .ToLocalChecked();
    2276             :     v8::Local<v8::String> result_string =
    2277          25 :         result->ToString(isolate1->GetCurrentContext()).ToLocalChecked();
    2278          75 :     CHECK(result_string->Equals(isolate1->GetCurrentContext(), v8_str("abcdef"))
    2279             :               .FromJust());
    2280             : 
    2281          25 :     if (cacheType == CodeCacheType::kAfterExecute) {
    2282           5 :       cache = ScriptCompiler::CreateCodeCache(script);
    2283             :     }
    2284          25 :     CHECK(cache);
    2285             :   }
    2286          25 :   isolate1->Dispose();
    2287          25 :   return cache;
    2288             : }
    2289             : 
    2290       28342 : TEST(CodeSerializerIsolates) {
    2291             :   const char* source = "function f() { return 'abc'; }; f() + 'def'";
    2292           5 :   v8::ScriptCompiler::CachedData* cache = CompileRunAndProduceCache(source);
    2293             : 
    2294             :   v8::Isolate::CreateParams create_params;
    2295           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2296           5 :   v8::Isolate* isolate2 = v8::Isolate::New(create_params);
    2297             :   isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
    2298           5 :                                    SerializerCodeEventListener);
    2299           5 :   toplevel_test_code_event_found = false;
    2300             :   {
    2301             :     v8::Isolate::Scope iscope(isolate2);
    2302          10 :     v8::HandleScope scope(isolate2);
    2303           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate2);
    2304             :     v8::Context::Scope context_scope(context);
    2305             : 
    2306           5 :     v8::Local<v8::String> source_str = v8_str(source);
    2307           5 :     v8::ScriptOrigin origin(v8_str("test"));
    2308             :     v8::ScriptCompiler::Source source(source_str, origin, cache);
    2309             :     v8::Local<v8::UnboundScript> script;
    2310             :     {
    2311             :       DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
    2312             :       script = v8::ScriptCompiler::CompileUnboundScript(
    2313             :                    isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
    2314           5 :                    .ToLocalChecked();
    2315             :     }
    2316           5 :     CHECK(!cache->rejected);
    2317             :     v8::Local<v8::Value> result = script->BindToCurrentContext()
    2318          10 :                                       ->Run(isolate2->GetCurrentContext())
    2319           5 :                                       .ToLocalChecked();
    2320          20 :     CHECK(result->ToString(isolate2->GetCurrentContext())
    2321             :               .ToLocalChecked()
    2322             :               ->Equals(isolate2->GetCurrentContext(), v8_str("abcdef"))
    2323             :               .FromJust());
    2324             :   }
    2325           5 :   CHECK(toplevel_test_code_event_found);
    2326           5 :   isolate2->Dispose();
    2327           5 : }
    2328             : 
    2329       28342 : TEST(CodeSerializerIsolatesEager) {
    2330             :   const char* source =
    2331             :       "function f() {"
    2332             :       "  return function g() {"
    2333             :       "    return 'abc';"
    2334             :       "  }"
    2335             :       "}"
    2336             :       "f()() + 'def'";
    2337             :   v8::ScriptCompiler::CachedData* cache =
    2338           5 :       CompileRunAndProduceCache(source, CodeCacheType::kEager);
    2339             : 
    2340             :   v8::Isolate::CreateParams create_params;
    2341           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2342           5 :   v8::Isolate* isolate2 = v8::Isolate::New(create_params);
    2343             :   isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
    2344           5 :                                    SerializerCodeEventListener);
    2345           5 :   toplevel_test_code_event_found = false;
    2346             :   {
    2347             :     v8::Isolate::Scope iscope(isolate2);
    2348          10 :     v8::HandleScope scope(isolate2);
    2349           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate2);
    2350             :     v8::Context::Scope context_scope(context);
    2351             : 
    2352           5 :     v8::Local<v8::String> source_str = v8_str(source);
    2353           5 :     v8::ScriptOrigin origin(v8_str("test"));
    2354             :     v8::ScriptCompiler::Source source(source_str, origin, cache);
    2355             :     v8::Local<v8::UnboundScript> script;
    2356             :     {
    2357             :       DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
    2358             :       script = v8::ScriptCompiler::CompileUnboundScript(
    2359             :                    isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
    2360           5 :                    .ToLocalChecked();
    2361             :     }
    2362           5 :     CHECK(!cache->rejected);
    2363             :     v8::Local<v8::Value> result = script->BindToCurrentContext()
    2364          10 :                                       ->Run(isolate2->GetCurrentContext())
    2365           5 :                                       .ToLocalChecked();
    2366          20 :     CHECK(result->ToString(isolate2->GetCurrentContext())
    2367             :               .ToLocalChecked()
    2368             :               ->Equals(isolate2->GetCurrentContext(), v8_str("abcdef"))
    2369             :               .FromJust());
    2370             :   }
    2371           5 :   CHECK(toplevel_test_code_event_found);
    2372           5 :   isolate2->Dispose();
    2373           5 : }
    2374             : 
    2375       28342 : TEST(CodeSerializerAfterExecute) {
    2376             :   // We test that no compilations happen when running this code. Forcing
    2377             :   // to always optimize breaks this test.
    2378           5 :   bool prev_always_opt_value = FLAG_always_opt;
    2379           5 :   FLAG_always_opt = false;
    2380             :   const char* source = "function f() { return 'abc'; }; f() + 'def'";
    2381             :   v8::ScriptCompiler::CachedData* cache =
    2382           5 :       CompileRunAndProduceCache(source, CodeCacheType::kAfterExecute);
    2383             : 
    2384             :   v8::Isolate::CreateParams create_params;
    2385           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2386           5 :   v8::Isolate* isolate2 = v8::Isolate::New(create_params);
    2387             : 
    2388             :   {
    2389             :     v8::Isolate::Scope iscope(isolate2);
    2390          10 :     v8::HandleScope scope(isolate2);
    2391           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate2);
    2392             :     v8::Context::Scope context_scope(context);
    2393             : 
    2394           5 :     v8::Local<v8::String> source_str = v8_str(source);
    2395           5 :     v8::ScriptOrigin origin(v8_str("test"));
    2396             :     v8::ScriptCompiler::Source source(source_str, origin, cache);
    2397             :     v8::Local<v8::UnboundScript> script;
    2398             :     {
    2399             :       DisallowCompilation no_compile_expected(
    2400             :           reinterpret_cast<Isolate*>(isolate2));
    2401             :       script = v8::ScriptCompiler::CompileUnboundScript(
    2402             :                    isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
    2403           5 :                    .ToLocalChecked();
    2404             :     }
    2405           5 :     CHECK(!cache->rejected);
    2406             : 
    2407             :     Handle<SharedFunctionInfo> sfi = v8::Utils::OpenHandle(*script);
    2408           5 :     CHECK(sfi->HasBytecodeArray());
    2409           5 :     BytecodeArray bytecode = sfi->GetBytecodeArray();
    2410          10 :     CHECK_EQ(bytecode->interrupt_budget(),
    2411             :              interpreter::Interpreter::InterruptBudget());
    2412           5 :     CHECK_EQ(bytecode->osr_loop_nesting_level(), 0);
    2413             : 
    2414             :     {
    2415             :       DisallowCompilation no_compile_expected(
    2416             :           reinterpret_cast<Isolate*>(isolate2));
    2417             :       v8::Local<v8::Value> result = script->BindToCurrentContext()
    2418          10 :                                         ->Run(isolate2->GetCurrentContext())
    2419           5 :                                         .ToLocalChecked();
    2420             :       v8::Local<v8::String> result_string =
    2421           5 :           result->ToString(isolate2->GetCurrentContext()).ToLocalChecked();
    2422          15 :       CHECK(
    2423             :           result_string->Equals(isolate2->GetCurrentContext(), v8_str("abcdef"))
    2424             :               .FromJust());
    2425             :     }
    2426             :   }
    2427           5 :   isolate2->Dispose();
    2428             : 
    2429             :   // Restore the flags.
    2430           5 :   FLAG_always_opt = prev_always_opt_value;
    2431           5 : }
    2432             : 
    2433       28342 : TEST(CodeSerializerFlagChange) {
    2434             :   const char* source = "function f() { return 'abc'; }; f() + 'def'";
    2435           5 :   v8::ScriptCompiler::CachedData* cache = CompileRunAndProduceCache(source);
    2436             : 
    2437             :   v8::Isolate::CreateParams create_params;
    2438           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2439           5 :   v8::Isolate* isolate2 = v8::Isolate::New(create_params);
    2440             : 
    2441           5 :   FLAG_allow_natives_syntax = true;  // Flag change should trigger cache reject.
    2442           5 :   FlagList::EnforceFlagImplications();
    2443             :   {
    2444             :     v8::Isolate::Scope iscope(isolate2);
    2445          10 :     v8::HandleScope scope(isolate2);
    2446           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate2);
    2447             :     v8::Context::Scope context_scope(context);
    2448             : 
    2449           5 :     v8::Local<v8::String> source_str = v8_str(source);
    2450           5 :     v8::ScriptOrigin origin(v8_str("test"));
    2451             :     v8::ScriptCompiler::Source source(source_str, origin, cache);
    2452             :     v8::ScriptCompiler::CompileUnboundScript(
    2453             :         isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
    2454           5 :         .ToLocalChecked();
    2455           5 :     CHECK(cache->rejected);
    2456             :   }
    2457           5 :   isolate2->Dispose();
    2458           5 : }
    2459             : 
    2460       28342 : TEST(CodeSerializerBitFlip) {
    2461             :   const char* source = "function f() { return 'abc'; }; f() + 'def'";
    2462           5 :   v8::ScriptCompiler::CachedData* cache = CompileRunAndProduceCache(source);
    2463             : 
    2464             :   // Random bit flip.
    2465           5 :   const_cast<uint8_t*>(cache->data)[337] ^= 0x40;
    2466             : 
    2467             :   v8::Isolate::CreateParams create_params;
    2468           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2469           5 :   v8::Isolate* isolate2 = v8::Isolate::New(create_params);
    2470             :   {
    2471             :     v8::Isolate::Scope iscope(isolate2);
    2472          10 :     v8::HandleScope scope(isolate2);
    2473           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate2);
    2474             :     v8::Context::Scope context_scope(context);
    2475             : 
    2476           5 :     v8::Local<v8::String> source_str = v8_str(source);
    2477           5 :     v8::ScriptOrigin origin(v8_str("test"));
    2478             :     v8::ScriptCompiler::Source source(source_str, origin, cache);
    2479             :     v8::ScriptCompiler::CompileUnboundScript(
    2480             :         isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
    2481           5 :         .ToLocalChecked();
    2482           5 :     CHECK(cache->rejected);
    2483             :   }
    2484           5 :   isolate2->Dispose();
    2485           5 : }
    2486             : 
    2487       28342 : TEST(CodeSerializerWithHarmonyScoping) {
    2488             :   const char* source1 = "'use strict'; let x = 'X'";
    2489             :   const char* source2 = "'use strict'; let y = 'Y'";
    2490             :   const char* source3 = "'use strict'; x + y";
    2491             : 
    2492             :   v8::ScriptCompiler::CachedData* cache;
    2493             : 
    2494             :   v8::Isolate::CreateParams create_params;
    2495           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2496           5 :   v8::Isolate* isolate1 = v8::Isolate::New(create_params);
    2497             :   {
    2498             :     v8::Isolate::Scope iscope(isolate1);
    2499          10 :     v8::HandleScope scope(isolate1);
    2500           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate1);
    2501             :     v8::Context::Scope context_scope(context);
    2502             : 
    2503             :     CompileRun(source1);
    2504             :     CompileRun(source2);
    2505             : 
    2506           5 :     v8::Local<v8::String> source_str = v8_str(source3);
    2507           5 :     v8::ScriptOrigin origin(v8_str("test"));
    2508             :     v8::ScriptCompiler::Source source(source_str, origin);
    2509             :     v8::Local<v8::UnboundScript> script =
    2510             :         v8::ScriptCompiler::CompileUnboundScript(
    2511             :             isolate1, &source, v8::ScriptCompiler::kNoCompileOptions)
    2512           5 :             .ToLocalChecked();
    2513           5 :     cache = v8::ScriptCompiler::CreateCodeCache(script);
    2514           5 :     CHECK(cache);
    2515             : 
    2516             :     v8::Local<v8::Value> result = script->BindToCurrentContext()
    2517          10 :                                       ->Run(isolate1->GetCurrentContext())
    2518           5 :                                       .ToLocalChecked();
    2519             :     v8::Local<v8::String> result_str =
    2520           5 :         result->ToString(isolate1->GetCurrentContext()).ToLocalChecked();
    2521          15 :     CHECK(result_str->Equals(isolate1->GetCurrentContext(), v8_str("XY"))
    2522             :               .FromJust());
    2523             :   }
    2524           5 :   isolate1->Dispose();
    2525             : 
    2526           5 :   v8::Isolate* isolate2 = v8::Isolate::New(create_params);
    2527             :   {
    2528             :     v8::Isolate::Scope iscope(isolate2);
    2529          10 :     v8::HandleScope scope(isolate2);
    2530           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate2);
    2531             :     v8::Context::Scope context_scope(context);
    2532             : 
    2533             :     // Reverse order of prior running scripts.
    2534             :     CompileRun(source2);
    2535             :     CompileRun(source1);
    2536             : 
    2537           5 :     v8::Local<v8::String> source_str = v8_str(source3);
    2538           5 :     v8::ScriptOrigin origin(v8_str("test"));
    2539             :     v8::ScriptCompiler::Source source(source_str, origin, cache);
    2540             :     v8::Local<v8::UnboundScript> script;
    2541             :     {
    2542             :       DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
    2543             :       script = v8::ScriptCompiler::CompileUnboundScript(
    2544             :                    isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
    2545           5 :                    .ToLocalChecked();
    2546             :     }
    2547             :     v8::Local<v8::Value> result = script->BindToCurrentContext()
    2548          10 :                                       ->Run(isolate2->GetCurrentContext())
    2549           5 :                                       .ToLocalChecked();
    2550             :     v8::Local<v8::String> result_str =
    2551           5 :         result->ToString(isolate2->GetCurrentContext()).ToLocalChecked();
    2552          15 :     CHECK(result_str->Equals(isolate2->GetCurrentContext(), v8_str("XY"))
    2553             :               .FromJust());
    2554             :   }
    2555           5 :   isolate2->Dispose();
    2556           5 : }
    2557             : 
    2558       28342 : TEST(Regress503552) {
    2559           5 :   if (!FLAG_incremental_marking) return;
    2560             :   // Test that the code serializer can deal with weak cells that form a linked
    2561             :   // list during incremental marking.
    2562           5 :   CcTest::InitializeVM();
    2563             :   Isolate* isolate = CcTest::i_isolate();
    2564             : 
    2565             :   HandleScope scope(isolate);
    2566             :   Handle<String> source = isolate->factory()->NewStringFromAsciiChecked(
    2567           5 :       "function f() {} function g() {}");
    2568           5 :   ScriptData* script_data = nullptr;
    2569             :   Handle<SharedFunctionInfo> shared = CompileScriptAndProduceCache(
    2570             :       isolate, source, Handle<String>(), &script_data,
    2571           5 :       v8::ScriptCompiler::kNoCompileOptions);
    2572          10 :   delete script_data;
    2573             : 
    2574           5 :   heap::SimulateIncrementalMarking(isolate->heap());
    2575             : 
    2576             :   v8::ScriptCompiler::CachedData* cache_data =
    2577           5 :       CodeSerializer::Serialize(shared);
    2578           5 :   delete cache_data;
    2579             : }
    2580             : 
    2581       28342 : TEST(SnapshotCreatorMultipleContexts) {
    2582             :   DisableAlwaysOpt();
    2583             :   v8::StartupData blob;
    2584             :   {
    2585           5 :     v8::SnapshotCreator creator;
    2586           5 :     v8::Isolate* isolate = creator.GetIsolate();
    2587             :     {
    2588           5 :       v8::HandleScope handle_scope(isolate);
    2589           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2590             :       v8::Context::Scope context_scope(context);
    2591             :       CompileRun("var f = function() { return 1; }");
    2592          10 :       creator.SetDefaultContext(context);
    2593             :     }
    2594             :     {
    2595           5 :       v8::HandleScope handle_scope(isolate);
    2596           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2597             :       v8::Context::Scope context_scope(context);
    2598             :       CompileRun("var f = function() { return 2; }");
    2599          10 :       CHECK_EQ(0u, creator.AddContext(context));
    2600             :     }
    2601             :     {
    2602           5 :       v8::HandleScope handle_scope(isolate);
    2603           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2604           5 :       CHECK_EQ(1u, creator.AddContext(context));
    2605             :     }
    2606             :     blob =
    2607           5 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    2608             :   }
    2609             : 
    2610             :   v8::Isolate::CreateParams params;
    2611           5 :   params.snapshot_blob = &blob;
    2612           5 :   params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2613             :   // Test-appropriate equivalent of v8::Isolate::New.
    2614           5 :   v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    2615             :   {
    2616             :     v8::Isolate::Scope isolate_scope(isolate);
    2617             :     {
    2618           5 :       v8::HandleScope handle_scope(isolate);
    2619           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2620             :       v8::Context::Scope context_scope(context);
    2621          10 :       ExpectInt32("f()", 1);
    2622             :     }
    2623             :     {
    2624           5 :       v8::HandleScope handle_scope(isolate);
    2625             :       v8::Local<v8::Context> context =
    2626          10 :           v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
    2627             :       v8::Context::Scope context_scope(context);
    2628          10 :       ExpectInt32("f()", 2);
    2629             :     }
    2630             :     {
    2631           5 :       v8::HandleScope handle_scope(isolate);
    2632             :       v8::Local<v8::Context> context =
    2633          10 :           v8::Context::FromSnapshot(isolate, 1).ToLocalChecked();
    2634             :       v8::Context::Scope context_scope(context);
    2635          10 :       ExpectUndefined("this.f");
    2636             :     }
    2637             :   }
    2638             : 
    2639           5 :   isolate->Dispose();
    2640           5 :   delete[] blob.data;
    2641           5 : }
    2642             : 
    2643             : static int serialized_static_field = 314;
    2644             : 
    2645          65 : static void SerializedCallback(
    2646         170 :     const v8::FunctionCallbackInfo<v8::Value>& args) {
    2647          65 :   if (args.Data()->IsExternal()) {
    2648          20 :     CHECK_EQ(args.Data().As<v8::External>()->Value(),
    2649             :              static_cast<void*>(&serialized_static_field));
    2650             :     int* value =
    2651          20 :         reinterpret_cast<int*>(args.Data().As<v8::External>()->Value());
    2652          20 :     (*value)++;
    2653             :   }
    2654          65 :   args.GetReturnValue().Set(v8_num(42));
    2655          65 : }
    2656             : 
    2657          10 : static void SerializedCallbackReplacement(
    2658          10 :     const v8::FunctionCallbackInfo<v8::Value>& args) {
    2659          10 :   args.GetReturnValue().Set(v8_num(1337));
    2660          10 : }
    2661             : 
    2662         145 : static void NamedPropertyGetterForSerialization(
    2663             :     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    2664         435 :   if (name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("x"))
    2665         290 :           .FromJust()) {
    2666          20 :     info.GetReturnValue().Set(v8_num(2016));
    2667             :   }
    2668         145 : }
    2669             : 
    2670          10 : static void AccessorForSerialization(
    2671             :     v8::Local<v8::String> property,
    2672             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    2673          10 :   info.GetReturnValue().Set(v8_num(2017));
    2674          10 : }
    2675             : 
    2676             : 
    2677       28337 : static SerializerOneByteResource serializable_one_byte_resource("one_byte", 8);
    2678       28337 : static SerializerTwoByteResource serializable_two_byte_resource("two_byte", 8);
    2679             : 
    2680             : intptr_t original_external_references[] = {
    2681             :     reinterpret_cast<intptr_t>(SerializedCallback),
    2682             :     reinterpret_cast<intptr_t>(&serialized_static_field),
    2683             :     reinterpret_cast<intptr_t>(&NamedPropertyGetterForSerialization),
    2684             :     reinterpret_cast<intptr_t>(&AccessorForSerialization),
    2685             :     reinterpret_cast<intptr_t>(&serialized_static_field),  // duplicate entry
    2686             :     reinterpret_cast<intptr_t>(&serializable_one_byte_resource),
    2687             :     reinterpret_cast<intptr_t>(&serializable_two_byte_resource),
    2688             :     0};
    2689             : 
    2690             : intptr_t replaced_external_references[] = {
    2691             :     reinterpret_cast<intptr_t>(SerializedCallbackReplacement),
    2692             :     reinterpret_cast<intptr_t>(&serialized_static_field),
    2693             :     reinterpret_cast<intptr_t>(&NamedPropertyGetterForSerialization),
    2694             :     reinterpret_cast<intptr_t>(&AccessorForSerialization),
    2695             :     reinterpret_cast<intptr_t>(&serialized_static_field),
    2696             :     reinterpret_cast<intptr_t>(&serializable_one_byte_resource),
    2697             :     reinterpret_cast<intptr_t>(&serializable_two_byte_resource),
    2698             :     0};
    2699             : 
    2700             : intptr_t short_external_references[] = {
    2701             :     reinterpret_cast<intptr_t>(SerializedCallbackReplacement), 0};
    2702             : 
    2703       28342 : TEST(SnapshotCreatorExternalReferences) {
    2704             :   DisableAlwaysOpt();
    2705             :   v8::StartupData blob;
    2706             :   {
    2707           5 :     v8::SnapshotCreator creator(original_external_references);
    2708           5 :     v8::Isolate* isolate = creator.GetIsolate();
    2709             :     {
    2710           5 :       v8::HandleScope handle_scope(isolate);
    2711           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2712             :       v8::Context::Scope context_scope(context);
    2713             :       v8::Local<v8::FunctionTemplate> callback =
    2714           5 :           v8::FunctionTemplate::New(isolate, SerializedCallback);
    2715             :       v8::Local<v8::Value> function =
    2716           5 :           callback->GetFunction(context).ToLocalChecked();
    2717          20 :       CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
    2718             : 
    2719          25 :       CHECK(context->Global()
    2720             :                 ->Set(context, v8_str("one_byte"),
    2721             :                       v8::String::NewExternalOneByte(
    2722             :                           isolate, &serializable_one_byte_resource)
    2723             :                           .ToLocalChecked())
    2724             :                 .FromJust());
    2725          25 :       CHECK(context->Global()
    2726             :                 ->Set(context, v8_str("two_byte"),
    2727             :                       v8::String::NewExternalTwoByte(
    2728             :                           isolate, &serializable_two_byte_resource)
    2729             :                           .ToLocalChecked())
    2730             :                 .FromJust());
    2731             : 
    2732           5 :       ExpectInt32("f()", 42);
    2733           5 :       ExpectString("one_byte", "one_byte");
    2734           5 :       ExpectString("two_byte", "two_byte");
    2735          10 :       creator.SetDefaultContext(context);
    2736             :     }
    2737             :     blob =
    2738           5 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    2739             :   }
    2740             : 
    2741           5 :   CHECK_EQ(1, serializable_one_byte_resource.dispose_count());
    2742           5 :   CHECK_EQ(1, serializable_two_byte_resource.dispose_count());
    2743             : 
    2744             :   // Deserialize with the original external reference.
    2745             :   {
    2746             :     v8::Isolate::CreateParams params;
    2747           5 :     params.snapshot_blob = &blob;
    2748           5 :     params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2749           5 :     params.external_references = original_external_references;
    2750             :     // Test-appropriate equivalent of v8::Isolate::New.
    2751           5 :     v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    2752             :     {
    2753             :       v8::Isolate::Scope isolate_scope(isolate);
    2754          10 :       v8::HandleScope handle_scope(isolate);
    2755           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2756             :       v8::Context::Scope context_scope(context);
    2757           5 :       ExpectInt32("f()", 42);
    2758           5 :       ExpectString("one_byte", "one_byte");
    2759           5 :       ExpectString("two_byte", "two_byte");
    2760           5 :       CHECK(CompileRun("one_byte").As<v8::String>()->IsExternalOneByte());
    2761           5 :       CHECK(CompileRun("two_byte").As<v8::String>()->IsExternal());
    2762             :     }
    2763           5 :     isolate->Dispose();
    2764             :   }
    2765             : 
    2766           5 :   CHECK_EQ(2, serializable_one_byte_resource.dispose_count());
    2767           5 :   CHECK_EQ(2, serializable_two_byte_resource.dispose_count());
    2768             : 
    2769             :   // Deserialize with some other external reference.
    2770             :   {
    2771             :     v8::Isolate::CreateParams params;
    2772           5 :     params.snapshot_blob = &blob;
    2773           5 :     params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2774           5 :     params.external_references = replaced_external_references;
    2775             :     // Test-appropriate equivalent of v8::Isolate::New.
    2776           5 :     v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    2777             :     {
    2778             :       v8::Isolate::Scope isolate_scope(isolate);
    2779          10 :       v8::HandleScope handle_scope(isolate);
    2780           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2781             :       v8::Context::Scope context_scope(context);
    2782           5 :       ExpectInt32("f()", 1337);
    2783             :     }
    2784           5 :     isolate->Dispose();
    2785             :   }
    2786             : 
    2787           5 :   CHECK_EQ(3, serializable_one_byte_resource.dispose_count());
    2788           5 :   CHECK_EQ(3, serializable_two_byte_resource.dispose_count());
    2789             : 
    2790           5 :   delete[] blob.data;
    2791           5 : }
    2792             : 
    2793       28342 : TEST(SnapshotCreatorShortExternalReferences) {
    2794             :   DisableAlwaysOpt();
    2795             :   v8::StartupData blob;
    2796             :   {
    2797           5 :     v8::SnapshotCreator creator(original_external_references);
    2798           5 :     v8::Isolate* isolate = creator.GetIsolate();
    2799             :     {
    2800           5 :       v8::HandleScope handle_scope(isolate);
    2801           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2802             :       v8::Context::Scope context_scope(context);
    2803             :       v8::Local<v8::FunctionTemplate> callback =
    2804           5 :           v8::FunctionTemplate::New(isolate, SerializedCallback);
    2805             :       v8::Local<v8::Value> function =
    2806           5 :           callback->GetFunction(context).ToLocalChecked();
    2807          20 :       CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
    2808           5 :       ExpectInt32("f()", 42);
    2809          10 :       creator.SetDefaultContext(context);
    2810             :     }
    2811             :     blob =
    2812           5 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    2813             :   }
    2814             : 
    2815             :   // Deserialize with an incomplete list of external references.
    2816             :   {
    2817             :     v8::Isolate::CreateParams params;
    2818           5 :     params.snapshot_blob = &blob;
    2819           5 :     params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2820           5 :     params.external_references = short_external_references;
    2821             :     // Test-appropriate equivalent of v8::Isolate::New.
    2822           5 :     v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    2823             :     {
    2824             :       v8::Isolate::Scope isolate_scope(isolate);
    2825          10 :       v8::HandleScope handle_scope(isolate);
    2826           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2827             :       v8::Context::Scope context_scope(context);
    2828           5 :       ExpectInt32("f()", 1337);
    2829             :     }
    2830           5 :     isolate->Dispose();
    2831             :   }
    2832           5 :   delete[] blob.data;
    2833           5 : }
    2834             : 
    2835           5 : v8::StartupData CreateSnapshotWithDefaultAndCustom() {
    2836           5 :   v8::SnapshotCreator creator(original_external_references);
    2837           5 :   v8::Isolate* isolate = creator.GetIsolate();
    2838             :   {
    2839           5 :     v8::HandleScope handle_scope(isolate);
    2840             :     {
    2841           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2842             :       v8::Context::Scope context_scope(context);
    2843             :       CompileRun("function f() { return 41; }");
    2844           5 :       creator.SetDefaultContext(context);
    2845           5 :       ExpectInt32("f()", 41);
    2846             :     }
    2847             :     {
    2848           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2849             :       v8::Context::Scope context_scope(context);
    2850             :       v8::Local<v8::FunctionTemplate> function_template =
    2851           5 :           v8::FunctionTemplate::New(isolate, SerializedCallback);
    2852             :       v8::Local<v8::Value> function =
    2853           5 :           function_template->GetFunction(context).ToLocalChecked();
    2854          20 :       CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
    2855             :       v8::Local<v8::ObjectTemplate> object_template =
    2856           5 :           v8::ObjectTemplate::New(isolate);
    2857           5 :       object_template->SetAccessor(v8_str("x"), AccessorForSerialization);
    2858             :       v8::Local<v8::Object> object =
    2859           5 :           object_template->NewInstance(context).ToLocalChecked();
    2860          20 :       CHECK(context->Global()->Set(context, v8_str("o"), object).FromJust());
    2861           5 :       ExpectInt32("f()", 42);
    2862           5 :       ExpectInt32("o.x", 2017);
    2863           5 :       creator.AddContext(context);
    2864           5 :     }
    2865             :   }
    2866           5 :   return creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    2867             : }
    2868             : 
    2869       28342 : TEST(SnapshotCreatorNoExternalReferencesDefault) {
    2870             :   DisableAlwaysOpt();
    2871           5 :   v8::StartupData blob = CreateSnapshotWithDefaultAndCustom();
    2872             : 
    2873             :   // Deserialize with an incomplete list of external references.
    2874             :   {
    2875             :     v8::Isolate::CreateParams params;
    2876           5 :     params.snapshot_blob = &blob;
    2877           5 :     params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2878             :     params.external_references = nullptr;
    2879             :     // Test-appropriate equivalent of v8::Isolate::New.
    2880           5 :     v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    2881             :     {
    2882             :       v8::Isolate::Scope isolate_scope(isolate);
    2883          10 :       v8::HandleScope handle_scope(isolate);
    2884           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2885             :       v8::Context::Scope context_scope(context);
    2886           5 :       ExpectInt32("f()", 41);
    2887             :     }
    2888           5 :     isolate->Dispose();
    2889             :   }
    2890           5 :   delete[] blob.data;
    2891           5 : }
    2892             : 
    2893           5 : v8::StartupData CreateCustomSnapshotWithPreparseDataAndNoOuterScope() {
    2894           5 :   v8::SnapshotCreator creator;
    2895           5 :   v8::Isolate* isolate = creator.GetIsolate();
    2896             :   {
    2897           5 :     v8::HandleScope handle_scope(isolate);
    2898             :     {
    2899           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2900             :       v8::Context::Scope context_scope(context);
    2901             :       CompileRun(
    2902             :           "var foo = {\n"
    2903             :           "  // This function is not top-level, but also has no outer scope.\n"
    2904             :           "  bar: function(){\n"
    2905             :           "    // Add an inner function so that the outer one has preparse\n"
    2906             :           "    // scope data.\n"
    2907             :           "    return function(){}\n"
    2908             :           "  }\n"
    2909             :           "};\n");
    2910           5 :       creator.SetDefaultContext(context);
    2911           5 :     }
    2912             :   }
    2913           5 :   return creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    2914             : }
    2915             : 
    2916       28342 : TEST(SnapshotCreatorPreparseDataAndNoOuterScope) {
    2917             :   DisableAlwaysOpt();
    2918           5 :   v8::StartupData blob = CreateCustomSnapshotWithPreparseDataAndNoOuterScope();
    2919             : 
    2920             :   // Deserialize with an incomplete list of external references.
    2921             :   {
    2922             :     v8::Isolate::CreateParams params;
    2923           5 :     params.snapshot_blob = &blob;
    2924           5 :     params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2925             :     // Test-appropriate equivalent of v8::Isolate::New.
    2926           5 :     v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    2927             :     {
    2928             :       v8::Isolate::Scope isolate_scope(isolate);
    2929          10 :       v8::HandleScope handle_scope(isolate);
    2930           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2931             :       v8::Context::Scope context_scope(context);
    2932             :     }
    2933           5 :     isolate->Dispose();
    2934             :   }
    2935           5 :   delete[] blob.data;
    2936           5 : }
    2937             : 
    2938           5 : v8::StartupData CreateCustomSnapshotArrayJoinWithKeep() {
    2939           5 :   v8::SnapshotCreator creator;
    2940           5 :   v8::Isolate* isolate = creator.GetIsolate();
    2941             :   {
    2942           5 :     v8::HandleScope handle_scope(isolate);
    2943             :     {
    2944           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2945             :       v8::Context::Scope context_scope(context);
    2946             :       CompileRun(
    2947             :           "[].join('');\n"
    2948             :           "function g() { return String([1,2,3]); }\n");
    2949           5 :       ExpectString("g()", "1,2,3");
    2950           5 :       creator.SetDefaultContext(context);
    2951           5 :     }
    2952             :   }
    2953           5 :   return creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kKeep);
    2954             : }
    2955             : 
    2956       28342 : TEST(SnapshotCreatorArrayJoinWithKeep) {
    2957             :   DisableAlwaysOpt();
    2958           5 :   v8::StartupData blob = CreateCustomSnapshotArrayJoinWithKeep();
    2959             : 
    2960             :   // Deserialize with an incomplete list of external references.
    2961             :   {
    2962             :     v8::Isolate::CreateParams params;
    2963           5 :     params.snapshot_blob = &blob;
    2964           5 :     params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2965             :     // Test-appropriate equivalent of v8::Isolate::New.
    2966           5 :     v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    2967             :     {
    2968             :       v8::Isolate::Scope isolate_scope(isolate);
    2969          10 :       v8::HandleScope handle_scope(isolate);
    2970           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    2971             :       v8::Context::Scope context_scope(context);
    2972           5 :       ExpectString("g()", "1,2,3");
    2973             :     }
    2974           5 :     isolate->Dispose();
    2975             :   }
    2976           5 :   delete[] blob.data;
    2977           5 : }
    2978             : 
    2979       28337 : TEST(SnapshotCreatorNoExternalReferencesCustomFail1) {
    2980             :   DisableAlwaysOpt();
    2981           0 :   v8::StartupData blob = CreateSnapshotWithDefaultAndCustom();
    2982             : 
    2983             :   // Deserialize with an incomplete list of external references.
    2984             :   {
    2985             :     v8::Isolate::CreateParams params;
    2986           0 :     params.snapshot_blob = &blob;
    2987           0 :     params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2988             :     params.external_references = nullptr;
    2989             :     // Test-appropriate equivalent of v8::Isolate::New.
    2990           0 :     v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    2991             :     {
    2992             :       v8::Isolate::Scope isolate_scope(isolate);
    2993           0 :       v8::HandleScope handle_scope(isolate);
    2994             :       v8::Local<v8::Context> context =
    2995           0 :           v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
    2996             :       v8::Context::Scope context_scope(context);
    2997           0 :       ExpectInt32("f()", 42);
    2998             :     }
    2999           0 :     isolate->Dispose();
    3000             :   }
    3001           0 :   delete[] blob.data;
    3002           0 : }
    3003             : 
    3004       28337 : TEST(SnapshotCreatorNoExternalReferencesCustomFail2) {
    3005             :   DisableAlwaysOpt();
    3006           0 :   v8::StartupData blob = CreateSnapshotWithDefaultAndCustom();
    3007             : 
    3008             :   // Deserialize with an incomplete list of external references.
    3009             :   {
    3010             :     v8::Isolate::CreateParams params;
    3011           0 :     params.snapshot_blob = &blob;
    3012           0 :     params.array_buffer_allocator = CcTest::array_buffer_allocator();
    3013             :     params.external_references = nullptr;
    3014             :     // Test-appropriate equivalent of v8::Isolate::New.
    3015           0 :     v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    3016             :     {
    3017             :       v8::Isolate::Scope isolate_scope(isolate);
    3018           0 :       v8::HandleScope handle_scope(isolate);
    3019             :       v8::Local<v8::Context> context =
    3020           0 :           v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
    3021             :       v8::Context::Scope context_scope(context);
    3022           0 :       ExpectInt32("o.x", 2017);
    3023             :     }
    3024           0 :     isolate->Dispose();
    3025             :   }
    3026           0 :   delete[] blob.data;
    3027           0 : }
    3028             : 
    3029       28337 : TEST(SnapshotCreatorUnknownExternalReferences) {
    3030             :   DisableAlwaysOpt();
    3031           0 :   v8::SnapshotCreator creator;
    3032           0 :   v8::Isolate* isolate = creator.GetIsolate();
    3033             :   {
    3034           0 :     v8::HandleScope handle_scope(isolate);
    3035           0 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
    3036             :     v8::Context::Scope context_scope(context);
    3037             : 
    3038             :     v8::Local<v8::FunctionTemplate> callback =
    3039           0 :         v8::FunctionTemplate::New(isolate, SerializedCallback);
    3040             :     v8::Local<v8::Value> function =
    3041           0 :         callback->GetFunction(context).ToLocalChecked();
    3042           0 :     CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
    3043           0 :     ExpectInt32("f()", 42);
    3044             : 
    3045           0 :     creator.SetDefaultContext(context);
    3046             :   }
    3047             :   v8::StartupData blob =
    3048           0 :       creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    3049             : 
    3050           0 :   delete[] blob.data;
    3051           0 : }
    3052             : 
    3053       28342 : TEST(SnapshotCreatorTemplates) {
    3054             :   DisableAlwaysOpt();
    3055             :   v8::StartupData blob;
    3056             : 
    3057             :   {
    3058           5 :     InternalFieldData* a1 = new InternalFieldData{11};
    3059           5 :     InternalFieldData* b1 = new InternalFieldData{20};
    3060           5 :     InternalFieldData* c1 = new InternalFieldData{30};
    3061             : 
    3062           5 :     v8::SnapshotCreator creator(original_external_references);
    3063           5 :     v8::Isolate* isolate = creator.GetIsolate();
    3064             :     {
    3065           5 :       v8::HandleScope handle_scope(isolate);
    3066             :       v8::ExtensionConfiguration* no_extension = nullptr;
    3067             :       v8::Local<v8::ObjectTemplate> global_template =
    3068           5 :           v8::ObjectTemplate::New(isolate);
    3069             :       v8::Local<v8::External> external =
    3070           5 :           v8::External::New(isolate, &serialized_static_field);
    3071             :       v8::Local<v8::FunctionTemplate> callback =
    3072           5 :           v8::FunctionTemplate::New(isolate, SerializedCallback, external);
    3073          10 :       global_template->Set(v8_str("f"), callback);
    3074             :       v8::Local<v8::Context> context =
    3075           5 :           v8::Context::New(isolate, no_extension, global_template);
    3076           5 :       creator.SetDefaultContext(context);
    3077           5 :       context = v8::Context::New(isolate, no_extension, global_template);
    3078             :       v8::Local<v8::ObjectTemplate> object_template =
    3079           5 :           v8::ObjectTemplate::New(isolate);
    3080           5 :       object_template->SetInternalFieldCount(3);
    3081             : 
    3082             :       v8::Context::Scope context_scope(context);
    3083           5 :       ExpectInt32("f()", 42);
    3084           5 :       CHECK_EQ(315, serialized_static_field);
    3085             : 
    3086             :       v8::Local<v8::Object> a =
    3087           5 :           object_template->NewInstance(context).ToLocalChecked();
    3088             :       v8::Local<v8::Object> b =
    3089           5 :           object_template->NewInstance(context).ToLocalChecked();
    3090             :       v8::Local<v8::Object> c =
    3091           5 :           object_template->NewInstance(context).ToLocalChecked();
    3092             :       v8::Local<v8::External> null_external =
    3093           5 :           v8::External::New(isolate, nullptr);
    3094             :       v8::Local<v8::External> field_external =
    3095           5 :           v8::External::New(isolate, &serialized_static_field);
    3096             : 
    3097           5 :       a->SetInternalField(0, b);
    3098           5 :       b->SetInternalField(0, c);
    3099             : 
    3100           5 :       a->SetAlignedPointerInInternalField(1, a1);
    3101           5 :       b->SetAlignedPointerInInternalField(1, b1);
    3102           5 :       c->SetAlignedPointerInInternalField(1, c1);
    3103             : 
    3104           5 :       a->SetInternalField(2, null_external);
    3105           5 :       b->SetInternalField(2, field_external);
    3106           5 :       c->SetInternalField(2, v8_num(35));
    3107          20 :       CHECK(context->Global()->Set(context, v8_str("a"), a).FromJust());
    3108             : 
    3109           5 :       CHECK_EQ(0u,
    3110             :                creator.AddContext(context, v8::SerializeInternalFieldsCallback(
    3111             :                                                SerializeInternalFields,
    3112             :                                                reinterpret_cast<void*>(2000))));
    3113           5 :       CHECK_EQ(0u, creator.AddTemplate(callback));
    3114          10 :       CHECK_EQ(1u, creator.AddTemplate(global_template));
    3115             :     }
    3116             :     blob =
    3117           5 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    3118             : 
    3119           5 :     delete a1;
    3120           5 :     delete b1;
    3121           5 :     delete c1;
    3122             :   }
    3123             : 
    3124             :   {
    3125             :     v8::Isolate::CreateParams params;
    3126           5 :     params.snapshot_blob = &blob;
    3127           5 :     params.array_buffer_allocator = CcTest::array_buffer_allocator();
    3128           5 :     params.external_references = original_external_references;
    3129             :     // Test-appropriate equivalent of v8::Isolate::New.
    3130           5 :     v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    3131             :     {
    3132             :       v8::Isolate::Scope isolate_scope(isolate);
    3133             :       {
    3134             :         // Create a new context without a new object template.
    3135           5 :         v8::HandleScope handle_scope(isolate);
    3136             :         v8::Local<v8::Context> context =
    3137             :             v8::Context::FromSnapshot(
    3138             :                 isolate, 0,
    3139             :                 v8::DeserializeInternalFieldsCallback(
    3140           5 :                     DeserializeInternalFields, reinterpret_cast<void*>(2017)))
    3141           5 :                 .ToLocalChecked();
    3142             :         v8::Context::Scope context_scope(context);
    3143           5 :         ExpectInt32("f()", 42);
    3144           5 :         CHECK_EQ(316, serialized_static_field);
    3145             : 
    3146             :         // Retrieve the snapshotted object template.
    3147             :         v8::Local<v8::ObjectTemplate> obj_template =
    3148           5 :             v8::ObjectTemplate::FromSnapshot(isolate, 1).ToLocalChecked();
    3149           5 :         CHECK(!obj_template.IsEmpty());
    3150             :         v8::Local<v8::Object> object =
    3151           5 :             obj_template->NewInstance(context).ToLocalChecked();
    3152          20 :         CHECK(context->Global()->Set(context, v8_str("o"), object).FromJust());
    3153           5 :         ExpectInt32("o.f()", 42);
    3154           5 :         CHECK_EQ(317, serialized_static_field);
    3155             :         // Check that it instantiates to the same prototype.
    3156             :         ExpectTrue("o.f.prototype === f.prototype");
    3157             : 
    3158             :         // Retrieve the snapshotted function template.
    3159             :         v8::Local<v8::FunctionTemplate> fun_template =
    3160           5 :             v8::FunctionTemplate::FromSnapshot(isolate, 0).ToLocalChecked();
    3161           5 :         CHECK(!fun_template.IsEmpty());
    3162             :         v8::Local<v8::Function> fun =
    3163           5 :             fun_template->GetFunction(context).ToLocalChecked();
    3164          20 :         CHECK(context->Global()->Set(context, v8_str("g"), fun).FromJust());
    3165           5 :         ExpectInt32("g()", 42);
    3166             :         // Check that it instantiates to the same prototype.
    3167             :         ExpectTrue("g.prototype === f.prototype");
    3168             : 
    3169             :         // Retrieve embedder fields.
    3170             :         v8::Local<v8::Object> a = context->Global()
    3171          15 :                                       ->Get(context, v8_str("a"))
    3172           5 :                                       .ToLocalChecked()
    3173             :                                       ->ToObject(context)
    3174           5 :                                       .ToLocalChecked();
    3175             :         v8::Local<v8::Object> b =
    3176           5 :             a->GetInternalField(0)->ToObject(context).ToLocalChecked();
    3177             :         v8::Local<v8::Object> c =
    3178           5 :             b->GetInternalField(0)->ToObject(context).ToLocalChecked();
    3179             : 
    3180             :         InternalFieldData* a1 = reinterpret_cast<InternalFieldData*>(
    3181             :             a->GetAlignedPointerFromInternalField(1));
    3182             :         v8::Local<v8::Value> a2 = a->GetInternalField(2);
    3183             : 
    3184             :         InternalFieldData* b1 = reinterpret_cast<InternalFieldData*>(
    3185             :             b->GetAlignedPointerFromInternalField(1));
    3186             :         v8::Local<v8::Value> b2 = b->GetInternalField(2);
    3187             : 
    3188             :         v8::Local<v8::Value> c0 = c->GetInternalField(0);
    3189             :         InternalFieldData* c1 = reinterpret_cast<InternalFieldData*>(
    3190             :             c->GetAlignedPointerFromInternalField(1));
    3191             :         v8::Local<v8::Value> c2 = c->GetInternalField(2);
    3192             : 
    3193           5 :         CHECK(c0->IsUndefined());
    3194             : 
    3195           5 :         CHECK_EQ(11u, a1->data);
    3196           5 :         CHECK_EQ(20u, b1->data);
    3197           5 :         CHECK_EQ(30u, c1->data);
    3198             : 
    3199           5 :         CHECK(a2->IsExternal());
    3200           5 :         CHECK_NULL(v8::Local<v8::External>::Cast(a2)->Value());
    3201           5 :         CHECK(b2->IsExternal());
    3202           5 :         CHECK_EQ(static_cast<void*>(&serialized_static_field),
    3203             :                  v8::Local<v8::External>::Cast(b2)->Value());
    3204          10 :         CHECK(c2->IsInt32() && c2->Int32Value(context).FromJust() == 35);
    3205             : 
    3206             :         // Accessing out of bound returns empty MaybeHandle.
    3207          10 :         CHECK(v8::ObjectTemplate::FromSnapshot(isolate, 2).IsEmpty());
    3208          10 :         CHECK(v8::FunctionTemplate::FromSnapshot(isolate, 2).IsEmpty());
    3209          10 :         CHECK(v8::Context::FromSnapshot(isolate, 1).IsEmpty());
    3210             : 
    3211          25 :         for (auto data : deserialized_data) delete data;
    3212           5 :         deserialized_data.clear();
    3213             :       }
    3214             :     }
    3215           5 :     isolate->Dispose();
    3216             :   }
    3217           5 :   delete[] blob.data;
    3218           5 : }
    3219             : 
    3220       28342 : TEST(SnapshotCreatorAddData) {
    3221             :   DisableAlwaysOpt();
    3222             :   v8::StartupData blob;
    3223             : 
    3224             :   {
    3225           5 :     v8::SnapshotCreator creator;
    3226           5 :     v8::Isolate* isolate = creator.GetIsolate();
    3227             :     v8::Eternal<v8::Value> eternal_number;
    3228             :     v8::Persistent<v8::Value> persistent_number_1;
    3229             :     v8::Persistent<v8::Value> persistent_number_2;
    3230             :     v8::Persistent<v8::Context> persistent_context;
    3231             :     {
    3232           5 :       v8::HandleScope handle_scope(isolate);
    3233             : 
    3234           5 :       eternal_number.Set(isolate, v8_num(2017));
    3235          10 :       persistent_number_1.Reset(isolate, v8_num(2018));
    3236          10 :       persistent_number_2.Reset(isolate, v8_num(2019));
    3237             : 
    3238           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    3239           5 :       CHECK_EQ(0u, creator.AddData(context, persistent_number_2.Get(isolate)));
    3240           5 :       creator.SetDefaultContext(context);
    3241           5 :       context = v8::Context::New(isolate);
    3242             :       persistent_context.Reset(isolate, context);
    3243             : 
    3244             :       v8::Context::Scope context_scope(context);
    3245             : 
    3246             :       v8::Local<v8::Object> object = CompileRun("({ p: 12 })").As<v8::Object>();
    3247             : 
    3248             :       v8::Local<v8::ObjectTemplate> object_template =
    3249           5 :           v8::ObjectTemplate::New(isolate);
    3250           5 :       object_template->SetInternalFieldCount(3);
    3251             : 
    3252             :       v8::Local<v8::Private> private_symbol =
    3253           5 :           v8::Private::ForApi(isolate, v8_str("private_symbol"));
    3254             : 
    3255             :       v8::Local<v8::Signature> signature =
    3256           5 :         v8::Signature::New(isolate, v8::FunctionTemplate::New(isolate));
    3257             : 
    3258             :       v8::Local<v8::AccessorSignature> accessor_signature =
    3259             :            v8::AccessorSignature::New(isolate,
    3260           5 :                                       v8::FunctionTemplate::New(isolate));
    3261             : 
    3262           5 :       CHECK_EQ(0u, creator.AddData(context, object));
    3263          10 :       CHECK_EQ(1u, creator.AddData(context, v8_str("context-dependent")));
    3264           5 :       CHECK_EQ(2u, creator.AddData(context, persistent_number_1.Get(isolate)));
    3265           5 :       CHECK_EQ(3u, creator.AddData(context, object_template));
    3266           5 :       CHECK_EQ(4u, creator.AddData(context, persistent_context.Get(isolate)));
    3267           5 :       creator.AddContext(context);
    3268             : 
    3269          10 :       CHECK_EQ(0u, creator.AddData(v8_str("context-independent")));
    3270           5 :       CHECK_EQ(1u, creator.AddData(eternal_number.Get(isolate)));
    3271           5 :       CHECK_EQ(2u, creator.AddData(object_template));
    3272          10 :       CHECK_EQ(3u, creator.AddData(v8::FunctionTemplate::New(isolate)));
    3273           5 :       CHECK_EQ(4u, creator.AddData(private_symbol));
    3274           5 :       CHECK_EQ(5u, creator.AddData(signature));
    3275          10 :       CHECK_EQ(6u, creator.AddData(accessor_signature));
    3276             :     }
    3277             : 
    3278             :     blob =
    3279           5 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    3280             :   }
    3281             : 
    3282             :   {
    3283             :     v8::Isolate::CreateParams params;
    3284           5 :     params.snapshot_blob = &blob;
    3285           5 :     params.array_buffer_allocator = CcTest::array_buffer_allocator();
    3286             :     // Test-appropriate equivalent of v8::Isolate::New.
    3287           5 :     v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    3288             :     {
    3289             :       v8::Isolate::Scope isolate_scope(isolate);
    3290          10 :       v8::HandleScope handle_scope(isolate);
    3291             :       v8::Local<v8::Context> context =
    3292          10 :           v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
    3293             : 
    3294             :       // Check serialized data on the context.
    3295             :       v8::Local<v8::Object> object =
    3296             :           context->GetDataFromSnapshotOnce<v8::Object>(0).ToLocalChecked();
    3297           5 :       CHECK(context->GetDataFromSnapshotOnce<v8::Object>(0).IsEmpty());
    3298          20 :       CHECK_EQ(12, object->Get(context, v8_str("p"))
    3299             :                        .ToLocalChecked()
    3300             :                        ->Int32Value(context)
    3301             :                        .FromJust());
    3302             : 
    3303             :       v8::Local<v8::String> string =
    3304             :           context->GetDataFromSnapshotOnce<v8::String>(1).ToLocalChecked();
    3305           5 :       CHECK(context->GetDataFromSnapshotOnce<v8::String>(1).IsEmpty());
    3306          15 :       CHECK(string->Equals(context, v8_str("context-dependent")).FromJust());
    3307             : 
    3308             :       v8::Local<v8::Number> number =
    3309             :           context->GetDataFromSnapshotOnce<v8::Number>(2).ToLocalChecked();
    3310           5 :       CHECK(context->GetDataFromSnapshotOnce<v8::Number>(2).IsEmpty());
    3311          10 :       CHECK_EQ(2018, number->Int32Value(context).FromJust());
    3312             : 
    3313             :       v8::Local<v8::ObjectTemplate> templ =
    3314             :           context->GetDataFromSnapshotOnce<v8::ObjectTemplate>(3)
    3315             :               .ToLocalChecked();
    3316           5 :       CHECK(context->GetDataFromSnapshotOnce<v8::ObjectTemplate>(3).IsEmpty());
    3317           5 :       CHECK_EQ(3, templ->InternalFieldCount());
    3318             : 
    3319             :       v8::Local<v8::Context> serialized_context =
    3320             :           context->GetDataFromSnapshotOnce<v8::Context>(4).ToLocalChecked();
    3321           5 :       CHECK(context->GetDataFromSnapshotOnce<v8::Context>(4).IsEmpty());
    3322          15 :       CHECK_EQ(*v8::Utils::OpenHandle(*serialized_context),
    3323             :                *v8::Utils::OpenHandle(*context));
    3324             : 
    3325           5 :       CHECK(context->GetDataFromSnapshotOnce<v8::Value>(5).IsEmpty());
    3326             : 
    3327             :       // Check serialized data on the isolate.
    3328             :       string = isolate->GetDataFromSnapshotOnce<v8::String>(0).ToLocalChecked();
    3329           5 :       CHECK(context->GetDataFromSnapshotOnce<v8::String>(0).IsEmpty());
    3330          15 :       CHECK(string->Equals(context, v8_str("context-independent")).FromJust());
    3331             : 
    3332             :       number = isolate->GetDataFromSnapshotOnce<v8::Number>(1).ToLocalChecked();
    3333           5 :       CHECK(isolate->GetDataFromSnapshotOnce<v8::Number>(1).IsEmpty());
    3334          10 :       CHECK_EQ(2017, number->Int32Value(context).FromJust());
    3335             : 
    3336             :       templ = isolate->GetDataFromSnapshotOnce<v8::ObjectTemplate>(2)
    3337             :                   .ToLocalChecked();
    3338           5 :       CHECK(isolate->GetDataFromSnapshotOnce<v8::ObjectTemplate>(2).IsEmpty());
    3339           5 :       CHECK_EQ(3, templ->InternalFieldCount());
    3340             : 
    3341             :       isolate->GetDataFromSnapshotOnce<v8::FunctionTemplate>(3)
    3342             :           .ToLocalChecked();
    3343           5 :       CHECK(
    3344             :           isolate->GetDataFromSnapshotOnce<v8::FunctionTemplate>(3).IsEmpty());
    3345             : 
    3346             :       isolate->GetDataFromSnapshotOnce<v8::Private>(4).ToLocalChecked();
    3347           5 :       CHECK(
    3348             :           isolate->GetDataFromSnapshotOnce<v8::Private>(4).IsEmpty());
    3349             : 
    3350             :       isolate->GetDataFromSnapshotOnce<v8::Signature>(5).ToLocalChecked();
    3351           5 :       CHECK(isolate->GetDataFromSnapshotOnce<v8::Signature>(5).IsEmpty());
    3352             : 
    3353             :       isolate->GetDataFromSnapshotOnce<v8::AccessorSignature>(6)
    3354             :           .ToLocalChecked();
    3355           5 :       CHECK(
    3356             :           isolate->GetDataFromSnapshotOnce<v8::AccessorSignature>(6).IsEmpty());
    3357             : 
    3358           5 :       CHECK(isolate->GetDataFromSnapshotOnce<v8::Value>(7).IsEmpty());
    3359             :     }
    3360           5 :     isolate->Dispose();
    3361             :   }
    3362             :   {
    3363           5 :     SnapshotCreator creator(nullptr, &blob);
    3364           5 :     v8::Isolate* isolate = creator.GetIsolate();
    3365             :     {
    3366             :       // Adding data to a snapshot replaces the list of existing data.
    3367           5 :       v8::HandleScope hscope(isolate);
    3368           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    3369           5 :       creator.SetDefaultContext(context);
    3370          10 :       context = v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
    3371             :       v8::Local<v8::String> string =
    3372             :           context->GetDataFromSnapshotOnce<v8::String>(1).ToLocalChecked();
    3373           5 :       CHECK(context->GetDataFromSnapshotOnce<v8::String>(1).IsEmpty());
    3374          15 :       CHECK(string->Equals(context, v8_str("context-dependent")).FromJust());
    3375             :       v8::Local<v8::Number> number =
    3376             :           isolate->GetDataFromSnapshotOnce<v8::Number>(1).ToLocalChecked();
    3377           5 :       CHECK(isolate->GetDataFromSnapshotOnce<v8::Number>(1).IsEmpty());
    3378          10 :       CHECK_EQ(2017, number->Int32Value(context).FromJust());
    3379             : 
    3380          10 :       CHECK_EQ(0u, creator.AddData(context, v8_num(2016)));
    3381           5 :       CHECK_EQ(0u, creator.AddContext(context));
    3382          10 :       CHECK_EQ(0u, creator.AddData(v8_str("stuff")));
    3383             :     }
    3384           5 :     delete[] blob.data;
    3385             :     blob =
    3386           5 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    3387             :   }
    3388             :   {
    3389             :     v8::Isolate::CreateParams params;
    3390           5 :     params.snapshot_blob = &blob;
    3391           5 :     params.array_buffer_allocator = CcTest::array_buffer_allocator();
    3392             :     // Test-appropriate equivalent of v8::Isolate::New.
    3393           5 :     v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    3394             :     {
    3395             :       v8::Isolate::Scope isolate_scope(isolate);
    3396          10 :       v8::HandleScope handle_scope(isolate);
    3397             : 
    3398             :       // Context where we did not re-add data no longer has data.
    3399           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    3400           5 :       CHECK(context->GetDataFromSnapshotOnce<v8::Object>(0).IsEmpty());
    3401             : 
    3402             :       // Context where we re-added data has completely new ones.
    3403          10 :       context = v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
    3404             :       v8::Local<v8::Value> value =
    3405             :           context->GetDataFromSnapshotOnce<v8::Value>(0).ToLocalChecked();
    3406          10 :       CHECK_EQ(2016, value->Int32Value(context).FromJust());
    3407           5 :       CHECK(context->GetDataFromSnapshotOnce<v8::Value>(1).IsEmpty());
    3408             : 
    3409             :       // Ditto for the isolate.
    3410             :       v8::Local<v8::String> string =
    3411             :           isolate->GetDataFromSnapshotOnce<v8::String>(0).ToLocalChecked();
    3412          15 :       CHECK(string->Equals(context, v8_str("stuff")).FromJust());
    3413           5 :       CHECK(context->GetDataFromSnapshotOnce<v8::String>(1).IsEmpty());
    3414             :     }
    3415           5 :     isolate->Dispose();
    3416             :   }
    3417           5 :   delete[] blob.data;
    3418           5 : }
    3419             : 
    3420       28337 : TEST(SnapshotCreatorUnknownHandles) {
    3421             :   DisableAlwaysOpt();
    3422             :   v8::StartupData blob;
    3423             : 
    3424             :   {
    3425           0 :     v8::SnapshotCreator creator;
    3426           0 :     v8::Isolate* isolate = creator.GetIsolate();
    3427             :     v8::Eternal<v8::Value> eternal_number;
    3428             :     v8::Persistent<v8::Value> persistent_number;
    3429             :     {
    3430           0 :       v8::HandleScope handle_scope(isolate);
    3431             : 
    3432           0 :       eternal_number.Set(isolate, v8_num(2017));
    3433           0 :       persistent_number.Reset(isolate, v8_num(2018));
    3434             : 
    3435           0 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    3436           0 :       creator.SetDefaultContext(context);
    3437             :     }
    3438             : 
    3439             :     blob =
    3440           0 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    3441             :   }
    3442           0 :   delete[] blob.data;
    3443           0 : }
    3444             : 
    3445       28342 : TEST(SnapshotCreatorIncludeGlobalProxy) {
    3446             :   DisableAlwaysOpt();
    3447             :   v8::StartupData blob;
    3448             : 
    3449             :   {
    3450           5 :     v8::SnapshotCreator creator(original_external_references);
    3451           5 :     v8::Isolate* isolate = creator.GetIsolate();
    3452             :     {
    3453             :       // Set default context. This context implicitly does *not* serialize
    3454             :       // the global proxy, and upon deserialization one has to be created
    3455             :       // in the bootstrapper from the global object template.
    3456             :       // Side effects from extensions are persisted though.
    3457           5 :       v8::HandleScope handle_scope(isolate);
    3458             :       v8::Local<v8::ObjectTemplate> global_template =
    3459           5 :           v8::ObjectTemplate::New(isolate);
    3460             :       v8::Local<v8::FunctionTemplate> callback =
    3461           5 :           v8::FunctionTemplate::New(isolate, SerializedCallback);
    3462          10 :       global_template->Set(v8_str("f"), callback);
    3463             :       global_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
    3464           5 :           NamedPropertyGetterForSerialization));
    3465             :       v8::Local<v8::Context> context =
    3466           5 :           v8::Context::New(isolate, nullptr, global_template);
    3467             :       v8::Context::Scope context_scope(context);
    3468             :       CompileRun(
    3469             :           "function h() { return 13; };"
    3470             :           "function i() { return 14; };"
    3471             :           "var o = { p: 7 };");
    3472           5 :       ExpectInt32("f()", 42);
    3473           5 :       ExpectInt32("h()", 13);
    3474           5 :       ExpectInt32("o.p", 7);
    3475           5 :       ExpectInt32("x", 2016);
    3476          10 :       creator.SetDefaultContext(context);
    3477             :     }
    3478             :     {
    3479             :       // Add additional context. This context implicitly *does* serialize
    3480             :       // the global proxy, and upon deserialization one has to be created
    3481             :       // in the bootstrapper from the global object template.
    3482             :       // Side effects from extensions are persisted.
    3483           5 :       v8::HandleScope handle_scope(isolate);
    3484             :       v8::Local<v8::ObjectTemplate> global_template =
    3485           5 :           v8::ObjectTemplate::New(isolate);
    3486             :       v8::Local<v8::FunctionTemplate> callback =
    3487           5 :           v8::FunctionTemplate::New(isolate, SerializedCallback);
    3488           5 :       global_template->SetInternalFieldCount(3);
    3489          10 :       global_template->Set(v8_str("f"), callback);
    3490             :       global_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
    3491           5 :           NamedPropertyGetterForSerialization));
    3492           5 :       global_template->SetAccessor(v8_str("y"), AccessorForSerialization);
    3493             :       v8::Local<v8::Private> priv =
    3494           5 :           v8::Private::ForApi(isolate, v8_str("cached"));
    3495             :       global_template->SetAccessorProperty(
    3496             :           v8_str("cached"),
    3497             :           v8::FunctionTemplate::NewWithCache(isolate, SerializedCallback, priv,
    3498          10 :                                              v8::Local<v8::Value>()));
    3499             :       v8::Local<v8::Context> context =
    3500           5 :           v8::Context::New(isolate, nullptr, global_template);
    3501             :       v8::Context::Scope context_scope(context);
    3502             : 
    3503          20 :       CHECK(context->Global()
    3504             :                 ->SetPrivate(context, priv, v8_str("cached string"))
    3505             :                 .FromJust());
    3506             :       v8::Local<v8::Private> hidden =
    3507           5 :           v8::Private::ForApi(isolate, v8_str("hidden"));
    3508          20 :       CHECK(context->Global()
    3509             :                 ->SetPrivate(context, hidden, v8_str("hidden string"))
    3510             :                 .FromJust());
    3511             : 
    3512           5 :       ExpectInt32("f()", 42);
    3513           5 :       ExpectInt32("x", 2016);
    3514           5 :       ExpectInt32("y", 2017);
    3515          25 :       CHECK(v8_str("hidden string")
    3516             :                 ->Equals(context, context->Global()
    3517             :                                       ->GetPrivate(context, hidden)
    3518             :                                       .ToLocalChecked())
    3519             :                 .FromJust());
    3520             : 
    3521           5 :       CHECK_EQ(0u,
    3522             :                creator.AddContext(context, v8::SerializeInternalFieldsCallback(
    3523             :                                                SerializeInternalFields,
    3524           5 :                                                reinterpret_cast<void*>(2016))));
    3525             :     }
    3526             :     blob =
    3527           5 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    3528             :   }
    3529             : 
    3530             :   {
    3531             :     v8::Isolate::CreateParams params;
    3532           5 :     params.snapshot_blob = &blob;
    3533           5 :     params.array_buffer_allocator = CcTest::array_buffer_allocator();
    3534           5 :     params.external_references = original_external_references;
    3535             :     // Test-appropriate equivalent of v8::Isolate::New.
    3536           5 :     v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    3537             :     {
    3538             :       v8::Isolate::Scope isolate_scope(isolate);
    3539             :       // We can introduce new extensions, which could override functions already
    3540             :       // in the snapshot.
    3541             :       v8::Extension* extension = new v8::Extension("new extension",
    3542             :                                                    "function i() { return 24; }"
    3543             :                                                    "function j() { return 25; }"
    3544             :                                                    "try {"
    3545             :                                                    "  if (o.p == 7) o.p++;"
    3546           5 :                                                    "} catch {}");
    3547             :       extension->set_auto_enable(true);
    3548           5 :       v8::RegisterExtension(extension);
    3549             :       {
    3550             :         // Create a new context from default context snapshot. This will
    3551             :         // create a new global object from a new global object template
    3552             :         // without the interceptor.
    3553           5 :         v8::HandleScope handle_scope(isolate);
    3554           5 :         v8::Local<v8::Context> context = v8::Context::New(isolate);
    3555             :         v8::Context::Scope context_scope(context);
    3556           5 :         ExpectInt32("f()", 42);
    3557           5 :         ExpectInt32("h()", 13);
    3558           5 :         ExpectInt32("i()", 24);
    3559           5 :         ExpectInt32("j()", 25);
    3560           5 :         ExpectInt32("o.p", 8);
    3561          10 :         v8::TryCatch try_catch(isolate);
    3562           5 :         CHECK(CompileRun("x").IsEmpty());
    3563          10 :         CHECK(try_catch.HasCaught());
    3564             :       }
    3565             :       {
    3566             :         // Create a new context from first additional context snapshot. This
    3567             :         // will use the global object from the snapshot, including interceptor.
    3568           5 :         v8::HandleScope handle_scope(isolate);
    3569             :         v8::Local<v8::Context> context =
    3570             :             v8::Context::FromSnapshot(
    3571             :                 isolate, 0,
    3572             :                 v8::DeserializeInternalFieldsCallback(
    3573           5 :                     DeserializeInternalFields, reinterpret_cast<void*>(2017)))
    3574           5 :                 .ToLocalChecked();
    3575             : 
    3576             :         {
    3577             :           v8::Context::Scope context_scope(context);
    3578           5 :           ExpectInt32("f()", 42);
    3579           5 :           ExpectInt32("i()", 24);
    3580           5 :           ExpectInt32("j()", 25);
    3581           5 :           ExpectInt32("x", 2016);
    3582             :           v8::Local<v8::Private> hidden =
    3583           5 :               v8::Private::ForApi(isolate, v8_str("hidden"));
    3584          25 :           CHECK(v8_str("hidden string")
    3585             :                     ->Equals(context, context->Global()
    3586             :                                           ->GetPrivate(context, hidden)
    3587             :                                           .ToLocalChecked())
    3588             :                     .FromJust());
    3589           5 :           ExpectString("cached", "cached string");
    3590             :         }
    3591             : 
    3592           5 :         v8::Local<v8::Object> global = context->Global();
    3593           5 :         CHECK_EQ(3, global->InternalFieldCount());
    3594           5 :         context->DetachGlobal();
    3595             : 
    3596             :         // New context, but reuse global proxy.
    3597             :         v8::ExtensionConfiguration* no_extensions = nullptr;
    3598             :         v8::Local<v8::Context> context2 =
    3599             :             v8::Context::FromSnapshot(
    3600             :                 isolate, 0,
    3601             :                 v8::DeserializeInternalFieldsCallback(
    3602             :                     DeserializeInternalFields, reinterpret_cast<void*>(2017)),
    3603           5 :                 no_extensions, global)
    3604           5 :                 .ToLocalChecked();
    3605             :         {
    3606             :           v8::Context::Scope context_scope(context2);
    3607           5 :           ExpectInt32("f()", 42);
    3608           5 :           ExpectInt32("i()", 24);
    3609           5 :           ExpectInt32("j()", 25);
    3610           5 :           ExpectInt32("x", 2016);
    3611             :           v8::Local<v8::Private> hidden =
    3612           5 :               v8::Private::ForApi(isolate, v8_str("hidden"));
    3613          25 :           CHECK(v8_str("hidden string")
    3614             :                     ->Equals(context2, context2->Global()
    3615             :                                            ->GetPrivate(context2, hidden)
    3616             :                                            .ToLocalChecked())
    3617             :                     .FromJust());
    3618             : 
    3619             :           // Set cached accessor property again.
    3620             :           v8::Local<v8::Private> priv =
    3621           5 :               v8::Private::ForApi(isolate, v8_str("cached"));
    3622          20 :           CHECK(context2->Global()
    3623             :                     ->SetPrivate(context2, priv, v8_str("cached string 1"))
    3624             :                     .FromJust());
    3625           5 :           ExpectString("cached", "cached string 1");
    3626             :         }
    3627             : 
    3628          15 :         CHECK(context2->Global()->Equals(context2, global).FromJust());
    3629             :       }
    3630             :     }
    3631           5 :     isolate->Dispose();
    3632             :   }
    3633           5 :   delete[] blob.data;
    3634           5 : }
    3635             : 
    3636       28342 : UNINITIALIZED_TEST(ReinitializeHashSeedNotRehashable) {
    3637             :   DisableAlwaysOpt();
    3638           5 :   i::FLAG_rehash_snapshot = true;
    3639           5 :   i::FLAG_hash_seed = 42;
    3640           5 :   i::FLAG_allow_natives_syntax = true;
    3641           5 :   DisableEmbeddedBlobRefcounting();
    3642             :   v8::StartupData blob;
    3643             :   {
    3644           5 :     v8::SnapshotCreator creator;
    3645           5 :     v8::Isolate* isolate = creator.GetIsolate();
    3646             :     {
    3647           5 :       v8::HandleScope handle_scope(isolate);
    3648           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    3649             :       v8::Context::Scope context_scope(context);
    3650             :       // Create an object with an ordered hash table.
    3651             :       CompileRun(
    3652             :           "var m = new Map();"
    3653             :           "m.set('a', 1);"
    3654             :           "m.set('b', 2);");
    3655           5 :       ExpectInt32("m.get('b')", 2);
    3656          10 :       creator.SetDefaultContext(context);
    3657             :     }
    3658             :     blob =
    3659           5 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    3660             :   }
    3661             : 
    3662           5 :   i::FLAG_hash_seed = 1337;
    3663             :   v8::Isolate::CreateParams create_params;
    3664           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    3665           5 :   create_params.snapshot_blob = &blob;
    3666           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
    3667             :   {
    3668             :     // Check that no rehashing has been performed.
    3669           5 :     CHECK_EQ(static_cast<uint64_t>(42),
    3670             :              reinterpret_cast<i::Isolate*>(isolate)->heap()->HashSeed());
    3671             :     v8::Isolate::Scope isolate_scope(isolate);
    3672          10 :     v8::HandleScope handle_scope(isolate);
    3673           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
    3674           5 :     CHECK(!context.IsEmpty());
    3675             :     v8::Context::Scope context_scope(context);
    3676           5 :     ExpectInt32("m.get('b')", 2);
    3677             :   }
    3678           5 :   isolate->Dispose();
    3679           5 :   delete[] blob.data;
    3680           5 :   FreeCurrentEmbeddedBlob();
    3681           5 : }
    3682             : 
    3683       28342 : UNINITIALIZED_TEST(ReinitializeHashSeedRehashable) {
    3684             :   DisableAlwaysOpt();
    3685           5 :   i::FLAG_rehash_snapshot = true;
    3686           5 :   i::FLAG_hash_seed = 42;
    3687           5 :   i::FLAG_allow_natives_syntax = true;
    3688           5 :   DisableEmbeddedBlobRefcounting();
    3689             :   v8::StartupData blob;
    3690             :   {
    3691           5 :     v8::SnapshotCreator creator;
    3692           5 :     v8::Isolate* isolate = creator.GetIsolate();
    3693             :     {
    3694           5 :       v8::HandleScope handle_scope(isolate);
    3695           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    3696             :       v8::Context::Scope context_scope(context);
    3697             :       // Create dictionary mode object.
    3698             :       CompileRun(
    3699             :           "var a = new Array(10000);"
    3700             :           "%NormalizeElements(a);"
    3701             :           "a[133] = 1;"
    3702             :           "a[177] = 2;"
    3703             :           "a[971] = 3;"
    3704             :           "a[7997] = 4;"
    3705             :           "a[2111] = 5;"
    3706             :           "var o = {};"
    3707             :           "%OptimizeObjectForAddingMultipleProperties(o, 3);"
    3708             :           "o.a = 1;"
    3709             :           "o.b = 2;"
    3710             :           "o.c = 3;"
    3711             :           "var p = { foo: 1 };"  // Test rehashing of transition arrays.
    3712             :           "p = JSON.parse('{\"foo\": {\"x\": 1}}');");
    3713             :       i::Handle<i::Object> i_a = v8::Utils::OpenHandle(*CompileRun("a"));
    3714           5 :       i::Handle<i::Object> i_o = v8::Utils::OpenHandle(*CompileRun("o"));
    3715          10 :       CHECK(i_a->IsJSArray());
    3716          10 :       CHECK(i_a->IsJSObject());
    3717          15 :       CHECK(!i::Handle<i::JSArray>::cast(i_a)->HasFastElements());
    3718          10 :       CHECK(!i::Handle<i::JSObject>::cast(i_o)->HasFastProperties());
    3719           5 :       ExpectInt32("a[2111]", 5);
    3720           5 :       ExpectInt32("o.c", 3);
    3721          10 :       creator.SetDefaultContext(context);
    3722             :     }
    3723             :     blob =
    3724           5 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    3725             :   }
    3726             : 
    3727           5 :   i::FLAG_hash_seed = 1337;
    3728             :   v8::Isolate::CreateParams create_params;
    3729           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    3730           5 :   create_params.snapshot_blob = &blob;
    3731           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
    3732             :   {
    3733             :     // Check that rehashing has been performed.
    3734           5 :     CHECK_EQ(static_cast<uint64_t>(1337),
    3735             :              reinterpret_cast<i::Isolate*>(isolate)->heap()->HashSeed());
    3736             :     v8::Isolate::Scope isolate_scope(isolate);
    3737          10 :     v8::HandleScope handle_scope(isolate);
    3738           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
    3739           5 :     CHECK(!context.IsEmpty());
    3740             :     v8::Context::Scope context_scope(context);
    3741             :     i::Handle<i::Object> i_a = v8::Utils::OpenHandle(*CompileRun("a"));
    3742           5 :     i::Handle<i::Object> i_o = v8::Utils::OpenHandle(*CompileRun("o"));
    3743          10 :     CHECK(i_a->IsJSArray());
    3744          10 :     CHECK(i_a->IsJSObject());
    3745          15 :     CHECK(!i::Handle<i::JSArray>::cast(i_a)->HasFastElements());
    3746          10 :     CHECK(!i::Handle<i::JSObject>::cast(i_o)->HasFastProperties());
    3747           5 :     ExpectInt32("a[2111]", 5);
    3748           5 :     ExpectInt32("o.c", 3);
    3749             :   }
    3750           5 :   isolate->Dispose();
    3751           5 :   delete[] blob.data;
    3752           5 :   FreeCurrentEmbeddedBlob();
    3753           5 : }
    3754             : 
    3755       28342 : TEST(SerializationStats) {
    3756           5 :   FLAG_profile_deserialization = true;
    3757           5 :   FLAG_always_opt = false;
    3758             :   v8::StartupData blob = CreateSnapshotDataBlob();
    3759           5 :   delete[] blob.data;
    3760             : 
    3761             :   // Track the embedded blob size as well.
    3762             :   {
    3763             :     int embedded_blob_size = 0;
    3764             :     if (FLAG_embedded_builtins) {
    3765             :       i::EmbeddedData d = i::EmbeddedData::FromBlob();
    3766           5 :       embedded_blob_size = static_cast<int>(d.size());
    3767             :     }
    3768           5 :     PrintF("Embedded blob is %d bytes\n", embedded_blob_size);
    3769             :   }
    3770           5 : }
    3771             : 
    3772          10 : void CheckSFIsAreWeak(WeakFixedArray sfis, Isolate* isolate) {
    3773          10 :   CHECK_GT(sfis->length(), 0);
    3774             :   int no_of_weak = 0;
    3775          50 :   for (int i = 0; i < sfis->length(); ++i) {
    3776          20 :     MaybeObject maybe_object = sfis->Get(i);
    3777          20 :     HeapObject heap_object;
    3778          20 :     CHECK(maybe_object->IsWeakOrCleared() ||
    3779             :           (maybe_object->GetHeapObjectIfStrong(&heap_object) &&
    3780             :            heap_object->IsUndefined(isolate)));
    3781          20 :     if (maybe_object->IsWeak()) {
    3782          15 :       ++no_of_weak;
    3783             :     }
    3784             :   }
    3785          10 :   CHECK_GT(no_of_weak, 0);
    3786          10 : }
    3787             : 
    3788       28342 : TEST(WeakArraySerializizationInSnapshot) {
    3789             :   const char* code = "var my_func = function() { }";
    3790             : 
    3791             :   DisableAlwaysOpt();
    3792           5 :   i::FLAG_allow_natives_syntax = true;
    3793             :   v8::StartupData blob;
    3794             :   {
    3795           5 :     v8::SnapshotCreator creator;
    3796           5 :     v8::Isolate* isolate = creator.GetIsolate();
    3797             :     {
    3798           5 :       v8::HandleScope handle_scope(isolate);
    3799           5 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
    3800             :       v8::Context::Scope context_scope(context);
    3801             : 
    3802             :       CompileRun(code);
    3803             :       creator.SetDefaultContext(
    3804             :           context, v8::SerializeInternalFieldsCallback(
    3805          10 :                        SerializeInternalFields, reinterpret_cast<void*>(2016)));
    3806             :     }
    3807             :     blob =
    3808           5 :         creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
    3809             :   }
    3810             : 
    3811             :   v8::Isolate::CreateParams create_params;
    3812           5 :   create_params.snapshot_blob = &blob;
    3813           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    3814           5 :   v8::Isolate* isolate = TestSerializer::NewIsolate(create_params);
    3815             :   {
    3816             :     v8::Isolate::Scope i_scope(isolate);
    3817          10 :     v8::HandleScope h_scope(isolate);
    3818             :     v8::Local<v8::Context> context = v8::Context::New(
    3819             :         isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
    3820             :         v8::MaybeLocal<v8::Value>(),
    3821             :         v8::DeserializeInternalFieldsCallback(DeserializeInternalFields,
    3822           5 :                                               reinterpret_cast<void*>(2017)));
    3823             :     v8::Context::Scope c_scope(context);
    3824             : 
    3825             :     v8::Local<v8::Value> x = CompileRun("my_func");
    3826           5 :     CHECK(x->IsFunction());
    3827             :     Handle<JSFunction> function =
    3828           5 :         Handle<JSFunction>::cast(v8::Utils::OpenHandle(*x));
    3829             : 
    3830             :     // Verify that the pointers in shared_function_infos are weak.
    3831             :     WeakFixedArray sfis =
    3832          10 :         Script::cast(function->shared()->script())->shared_function_infos();
    3833           5 :     CheckSFIsAreWeak(sfis, CcTest::i_isolate());
    3834             :   }
    3835           5 :   isolate->Dispose();
    3836           5 :   delete[] blob.data;
    3837           5 : }
    3838             : 
    3839       28342 : TEST(WeakArraySerializationInCodeCache) {
    3840           5 :   LocalContext context;
    3841           5 :   Isolate* isolate = CcTest::i_isolate();
    3842           5 :   isolate->compilation_cache()->Disable();
    3843             : 
    3844          10 :   v8::HandleScope scope(CcTest::isolate());
    3845             : 
    3846             :   const char* source = "function foo() { }";
    3847             : 
    3848             :   Handle<String> src = isolate->factory()
    3849             :                            ->NewStringFromUtf8(CStrVector(source))
    3850          10 :                            .ToHandleChecked();
    3851           5 :   ScriptData* cache = nullptr;
    3852             : 
    3853             :   CompileScriptAndProduceCache(isolate, src, src, &cache,
    3854           5 :                                v8::ScriptCompiler::kNoCompileOptions);
    3855             : 
    3856             :   DisallowCompilation no_compile_expected(isolate);
    3857             :   Handle<SharedFunctionInfo> copy = CompileScript(
    3858           5 :       isolate, src, src, cache, v8::ScriptCompiler::kConsumeCodeCache);
    3859             : 
    3860             :   // Verify that the pointers in shared_function_infos are weak.
    3861          10 :   WeakFixedArray sfis = Script::cast(copy->script())->shared_function_infos();
    3862           5 :   CheckSFIsAreWeak(sfis, isolate);
    3863             : 
    3864          15 :   delete cache;
    3865           5 : }
    3866             : 
    3867       28342 : TEST(CachedCompileFunctionInContext) {
    3868             :   DisableAlwaysOpt();
    3869           5 :   LocalContext env;
    3870           5 :   Isolate* isolate = CcTest::i_isolate();
    3871           5 :   isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
    3872             : 
    3873          10 :   v8::HandleScope scope(CcTest::isolate());
    3874             : 
    3875           5 :   v8::Local<v8::String> source = v8_str("return x*x;");
    3876           5 :   v8::Local<v8::String> arg_str = v8_str("x");
    3877             :   ScriptCompiler::CachedData* cache;
    3878             :   {
    3879             :     v8::ScriptCompiler::Source script_source(source);
    3880             :     v8::Local<v8::Function> fun =
    3881             :         v8::ScriptCompiler::CompileFunctionInContext(
    3882             :             env.local(), &script_source, 1, &arg_str, 0, nullptr,
    3883           5 :             v8::ScriptCompiler::kEagerCompile)
    3884          10 :             .ToLocalChecked();
    3885           5 :     cache = v8::ScriptCompiler::CreateCodeCacheForFunction(fun);
    3886             :   }
    3887             : 
    3888             :   {
    3889             :     DisallowCompilation no_compile_expected(isolate);
    3890             :     v8::ScriptCompiler::Source script_source(source, cache);
    3891             :     v8::Local<v8::Function> fun =
    3892             :         v8::ScriptCompiler::CompileFunctionInContext(
    3893             :             env.local(), &script_source, 1, &arg_str, 0, nullptr,
    3894           5 :             v8::ScriptCompiler::kConsumeCodeCache)
    3895           5 :             .ToLocalChecked();
    3896           5 :     v8::Local<v8::Value> arg = v8_num(3);
    3897             :     v8::Local<v8::Value> result =
    3898          15 :         fun->Call(env.local(), v8::Undefined(CcTest::isolate()), 1, &arg)
    3899           5 :             .ToLocalChecked();
    3900          10 :     CHECK_EQ(9, result->Int32Value(env.local()).FromJust());
    3901           5 :   }
    3902           5 : }
    3903             : 
    3904             : }  // namespace internal
    3905       85011 : }  // namespace v8

Generated by: LCOV version 1.10