test-serialize.cc 146 KB
Newer Older
1
// Copyright 2007-2010 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <signal.h>

30
#include <sys/stat.h>
31

32
#include "src/init/v8.h"
33

34
#include "src/api/api-inl.h"
35 36 37 38
#include "src/codegen/assembler-inl.h"
#include "src/codegen/compilation-cache.h"
#include "src/codegen/compiler.h"
#include "src/codegen/macro-assembler-inl.h"
39
#include "src/debug/debug.h"
40
#include "src/heap/heap-inl.h"
41
#include "src/heap/read-only-heap.h"
42
#include "src/heap/spaces.h"
43
#include "src/init/bootstrapper.h"
44
#include "src/interpreter/interpreter.h"
45
#include "src/numbers/hash-seed-inl.h"
46
#include "src/objects/js-array-buffer-inl.h"
47
#include "src/objects/js-array-inl.h"
48
#include "src/objects/js-regexp-inl.h"
49
#include "src/objects/objects-inl.h"
50
#include "src/runtime/runtime.h"
51
#include "src/snapshot/code-serializer.h"
52
#include "src/snapshot/partial-deserializer.h"
53
#include "src/snapshot/partial-serializer.h"
54
#include "src/snapshot/read-only-deserializer.h"
55
#include "src/snapshot/read-only-serializer.h"
56
#include "src/snapshot/snapshot.h"
57
#include "src/snapshot/startup-deserializer.h"
58
#include "src/snapshot/startup-serializer.h"
59
#include "test/cctest/cctest.h"
60
#include "test/cctest/heap/heap-utils.h"
61
#include "test/cctest/setup-isolate-for-tests.h"
62

63 64
namespace v8 {
namespace internal {
65

66 67
enum CodeCacheType { kLazy, kEager, kAfterExecute };

68 69 70 71
void DisableAlwaysOpt() {
  // Isolates prepared for serialization do not optimize. The only exception is
  // with the flag --always-opt.
  FLAG_always_opt = false;
72 73
}

74 75 76 77 78
// A convenience struct to simplify management of the blobs required to
// deserialize an isolate.
struct StartupBlobs {
  Vector<const byte> startup;
  Vector<const byte> read_only;
79

80 81 82 83 84 85 86 87
  void Dispose() {
    startup.Dispose();
    read_only.Dispose();
  }
};

// TestSerializer is used for testing isolate serialization.
class TestSerializer {
88
 public:
89
  static v8::Isolate* NewIsolateInitialized() {
90 91
    const bool kEnableSerializer = true;
    const bool kGenerateHeap = true;
92
    DisableEmbeddedBlobRefcounting();
93
    v8::Isolate* v8_isolate = NewIsolate(kEnableSerializer, kGenerateHeap);
94
    v8::Isolate::Scope isolate_scope(v8_isolate);
95
    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
96
    isolate->Init(nullptr, nullptr);
97 98
    return v8_isolate;
  }
99

100
  static v8::Isolate* NewIsolateFromBlob(const StartupBlobs& blobs) {
101 102
    SnapshotData startup_snapshot(blobs.startup);
    SnapshotData read_only_snapshot(blobs.read_only);
103 104
    ReadOnlyDeserializer read_only_deserializer(&read_only_snapshot);
    StartupDeserializer startup_deserializer(&startup_snapshot);
105 106 107 108 109
    const bool kEnableSerializer = false;
    const bool kGenerateHeap = false;
    v8::Isolate* v8_isolate = NewIsolate(kEnableSerializer, kGenerateHeap);
    v8::Isolate::Scope isolate_scope(v8_isolate);
    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
110
    isolate->Init(&read_only_deserializer, &startup_deserializer);
111 112 113 114
    return v8_isolate;
  }

  // Wraps v8::Isolate::New, but with a test isolate under the hood.
115 116
  // Allows flexibility to bootstrap with or without snapshot even when
  // the production Isolate class has one or the other behavior baked in.
117
  static v8::Isolate* NewIsolate(const v8::Isolate::CreateParams& params) {
118 119
    const bool kEnableSerializer = false;
    const bool kGenerateHeap = params.snapshot_blob == nullptr;
120
    v8::Isolate* v8_isolate = NewIsolate(kEnableSerializer, kGenerateHeap);
121 122
    v8::Isolate::Initialize(v8_isolate, params);
    return v8_isolate;
123
  }
124 125 126 127 128 129 130 131 132 133

 private:
  // Creates an Isolate instance configured for testing.
  static v8::Isolate* NewIsolate(bool with_serializer, bool generate_heap) {
    i::Isolate* isolate = i::Isolate::New();
    v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);

    if (with_serializer) isolate->enable_serializer();
    isolate->set_array_buffer_allocator(CcTest::array_buffer_allocator());
    isolate->setup_delegate_ = new SetupIsolateDelegateForTests(generate_heap);
134

135
    return v8_isolate;
136
  }
137 138
};

139 140 141 142 143
static Vector<const byte> WritePayload(const Vector<const byte>& payload) {
  int length = payload.length();
  byte* blob = NewArray<byte>(length);
  memcpy(blob, payload.begin(), length);
  return Vector<const byte>(const_cast<const byte*>(blob), length);
144
}
145

146 147
namespace {

148 149
// Convenience wrapper around the convenience wrapper.
v8::StartupData CreateSnapshotDataBlob(const char* embedded_source) {
150
  v8::StartupData data = CreateSnapshotDataBlobInternal(
151
      v8::SnapshotCreator::FunctionCodeHandling::kClear, embedded_source);
152 153
  ReadOnlyHeap::ClearSharedHeapForTest();
  return data;
154 155
}

156 157
}  // namespace

158
static StartupBlobs Serialize(v8::Isolate* isolate) {
159
  // We have to create one context.  One reason for this is so that the builtins
160 161 162 163
  // can be loaded from self hosted JS builtins and their addresses can be
  // processed.  This will clear the pending fixups array, which would otherwise
  // contain GC roots that would confuse the serialization/deserialization
  // process.
164
  v8::Isolate::Scope isolate_scope(isolate);
165 166 167 168
  {
    v8::HandleScope scope(isolate);
    v8::Context::New(isolate);
  }
169

170
  Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
171 172
  internal_isolate->heap()->CollectAllAvailableGarbage(
      i::GarbageCollectionReason::kTesting);
173 174 175 176 177

  ReadOnlySerializer read_only_serializer(internal_isolate);
  read_only_serializer.SerializeReadOnlyRoots();

  StartupSerializer ser(internal_isolate, &read_only_serializer);
178
  ser.SerializeStrongReferences();
179

180
  ser.SerializeWeakReferencesAndDeferred();
181
  read_only_serializer.FinalizeSerialization();
182
  SnapshotData startup_snapshot(&ser);
183
  SnapshotData read_only_snapshot(&read_only_serializer);
184
  return {WritePayload(startup_snapshot.RawData()),
185
          WritePayload(read_only_snapshot.RawData())};
186 187 188
}


189 190 191 192 193
Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head,
                                      Vector<const uint8_t> body,
                                      Vector<const uint8_t> tail, int repeats) {
  int source_length = head.length() + body.length() * repeats + tail.length();
  uint8_t* source = NewArray<uint8_t>(static_cast<size_t>(source_length));
194
  CopyChars(source, head.begin(), head.length());
195
  for (int i = 0; i < repeats; i++) {
196
    CopyChars(source + head.length() + i * body.length(), body.begin(),
197 198
              body.length());
  }
199
  CopyChars(source + head.length() + repeats * body.length(), tail.begin(),
200 201 202 203 204
            tail.length());
  return Vector<const uint8_t>(const_cast<const uint8_t*>(source),
                               source_length);
}

205
static v8::Isolate* Deserialize(const StartupBlobs& blobs) {
206
  v8::Isolate* isolate = TestSerializer::NewIsolateFromBlob(blobs);
207 208
  CHECK(isolate);
  return isolate;
209 210
}

211 212 213
static void SanityCheck(v8::Isolate* v8_isolate) {
  Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
  v8::HandleScope scope(v8_isolate);
214
#ifdef VERIFY_HEAP
215
  isolate->heap()->Verify();
216
#endif
217 218
  CHECK(isolate->global_object()->IsJSObject());
  CHECK(isolate->native_context()->IsContext());
219
  isolate->factory()->InternalizeString(StaticCharVector("Empty"));
220 221
}

222
void TestStartupSerializerOnceImpl() {
223
  v8::Isolate* isolate = TestSerializer::NewIsolateInitialized();
224
  StartupBlobs blobs = Serialize(isolate);
225
  isolate->Dispose();
226
  ReadOnlyHeap::ClearSharedHeapForTest();
227
  isolate = Deserialize(blobs);
228 229 230
  {
    v8::HandleScope handle_scope(isolate);
    v8::Isolate::Scope isolate_scope(isolate);
231

232 233
    v8::Local<v8::Context> env = v8::Context::New(isolate);
    env->Enter();
234

235
    SanityCheck(isolate);
236
  }
237
  isolate->Dispose();
238
  blobs.Dispose();
239
  FreeCurrentEmbeddedBlob();
240 241
}

242 243 244 245 246
UNINITIALIZED_TEST(StartupSerializerOnce) {
  DisableAlwaysOpt();
  TestStartupSerializerOnceImpl();
}

247 248 249 250 251 252
UNINITIALIZED_TEST(StartupSerializerOnce1) {
  DisableAlwaysOpt();
  FLAG_serialization_chunk_size = 1;
  TestStartupSerializerOnceImpl();
}

253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
UNINITIALIZED_TEST(StartupSerializerOnce32) {
  DisableAlwaysOpt();
  FLAG_serialization_chunk_size = 32;
  TestStartupSerializerOnceImpl();
}

UNINITIALIZED_TEST(StartupSerializerOnce1K) {
  DisableAlwaysOpt();
  FLAG_serialization_chunk_size = 1 * KB;
  TestStartupSerializerOnceImpl();
}

UNINITIALIZED_TEST(StartupSerializerOnce4K) {
  DisableAlwaysOpt();
  FLAG_serialization_chunk_size = 4 * KB;
  TestStartupSerializerOnceImpl();
}

UNINITIALIZED_TEST(StartupSerializerOnce32K) {
  DisableAlwaysOpt();
  FLAG_serialization_chunk_size = 32 * KB;
  TestStartupSerializerOnceImpl();
}

277
UNINITIALIZED_TEST(StartupSerializerTwice) {
278
  DisableAlwaysOpt();
279
  v8::Isolate* isolate = TestSerializer::NewIsolateInitialized();
280 281
  StartupBlobs blobs1 = Serialize(isolate);
  StartupBlobs blobs2 = Serialize(isolate);
282
  isolate->Dispose();
283
  blobs1.Dispose();
284
  ReadOnlyHeap::ClearSharedHeapForTest();
285
  isolate = Deserialize(blobs2);
286 287 288
  {
    v8::Isolate::Scope isolate_scope(isolate);
    v8::HandleScope handle_scope(isolate);
289

290 291
    v8::Local<v8::Context> env = v8::Context::New(isolate);
    env->Enter();
292

293
    SanityCheck(isolate);
294
  }
295
  isolate->Dispose();
296
  blobs2.Dispose();
297
  FreeCurrentEmbeddedBlob();
298 299
}

300
UNINITIALIZED_TEST(StartupSerializerOnceRunScript) {
301
  DisableAlwaysOpt();
302
  v8::Isolate* isolate = TestSerializer::NewIsolateInitialized();
303
  StartupBlobs blobs = Serialize(isolate);
304
  isolate->Dispose();
305
  ReadOnlyHeap::ClearSharedHeapForTest();
306
  isolate = Deserialize(blobs);
307 308 309
  {
    v8::Isolate::Scope isolate_scope(isolate);
    v8::HandleScope handle_scope(isolate);
310

311

312 313
    v8::Local<v8::Context> env = v8::Context::New(isolate);
    env->Enter();
314

315
    const char* c_source = "\"1234\".length";
316 317 318 319 320
    v8::Local<v8::Script> script = v8_compile(c_source);
    v8::Maybe<int32_t> result = script->Run(isolate->GetCurrentContext())
                                    .ToLocalChecked()
                                    ->Int32Value(isolate->GetCurrentContext());
    CHECK_EQ(4, result.FromJust());
321
  }
322
  isolate->Dispose();
323
  blobs.Dispose();
324
  FreeCurrentEmbeddedBlob();
325 326
}

327
UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) {
328
  DisableAlwaysOpt();
329
  v8::Isolate* isolate = TestSerializer::NewIsolateInitialized();
330 331
  StartupBlobs blobs1 = Serialize(isolate);
  StartupBlobs blobs2 = Serialize(isolate);
332
  isolate->Dispose();
333
  blobs1.Dispose();
334
  ReadOnlyHeap::ClearSharedHeapForTest();
335
  isolate = Deserialize(blobs2);
336 337 338
  {
    v8::Isolate::Scope isolate_scope(isolate);
    v8::HandleScope handle_scope(isolate);
339

340 341
    v8::Local<v8::Context> env = v8::Context::New(isolate);
    env->Enter();
342

343
    const char* c_source = "\"1234\".length";
344 345 346 347 348
    v8::Local<v8::Script> script = v8_compile(c_source);
    v8::Maybe<int32_t> result = script->Run(isolate->GetCurrentContext())
                                    .ToLocalChecked()
                                    ->Int32Value(isolate->GetCurrentContext());
    CHECK_EQ(4, result.FromJust());
349
  }
350
  isolate->Dispose();
351
  blobs2.Dispose();
352
  FreeCurrentEmbeddedBlob();
353 354
}

355
static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
356
                                      Vector<const byte>* read_only_blob_out,
357
                                      Vector<const byte>* partial_blob_out) {
358
  v8::Isolate* v8_isolate = TestSerializer::NewIsolateInitialized();
359 360 361 362
  Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
  Heap* heap = isolate->heap();
  {
    v8::Isolate::Scope isolate_scope(v8_isolate);
363

364 365 366 367 368
    v8::Persistent<v8::Context> env;
    {
      HandleScope scope(isolate);
      env.Reset(v8_isolate, v8::Context::New(v8_isolate));
    }
369
    CHECK(!env.IsEmpty());
370 371 372 373
    {
      v8::HandleScope handle_scope(v8_isolate);
      v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
    }
374

375 376
    // If we don't do this then we end up with a stray root pointing at the
    // context even after we have disposed of env.
377
    heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
378

379 380 381 382
    {
      v8::HandleScope handle_scope(v8_isolate);
      v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
    }
383

384
    i::Context raw_context = i::Context::cast(*v8::Utils::OpenPersistent(env));
385

386
    env.Reset();
387

388 389 390 391
    SnapshotByteSink read_only_sink;
    ReadOnlySerializer read_only_serializer(isolate);
    read_only_serializer.SerializeReadOnlyRoots();

392
    SnapshotByteSink startup_sink;
393
    StartupSerializer startup_serializer(isolate, &read_only_serializer);
394
    startup_serializer.SerializeStrongReferences();
395

396
    SnapshotByteSink partial_sink;
397 398
    PartialSerializer partial_serializer(isolate, &startup_serializer,
                                         v8::SerializeInternalFieldsCallback());
399
    partial_serializer.Serialize(&raw_context, false);
400

401
    startup_serializer.SerializeWeakReferencesAndDeferred();
402

403 404 405
    read_only_serializer.FinalizeSerialization();

    SnapshotData read_only_snapshot(&read_only_serializer);
406 407
    SnapshotData startup_snapshot(&startup_serializer);
    SnapshotData partial_snapshot(&partial_serializer);
408

409 410
    *partial_blob_out = WritePayload(partial_snapshot.RawData());
    *startup_blob_out = WritePayload(startup_snapshot.RawData());
411
    *read_only_blob_out = WritePayload(read_only_snapshot.RawData());
412
  }
413
  v8_isolate->Dispose();
414
  ReadOnlyHeap::ClearSharedHeapForTest();
415 416
}

417
UNINITIALIZED_TEST(PartialSerializerContext) {
418
  DisableAlwaysOpt();
419
  Vector<const byte> startup_blob;
420
  Vector<const byte> read_only_blob;
421
  Vector<const byte> partial_blob;
422
  PartiallySerializeContext(&startup_blob, &read_only_blob, &partial_blob);
423

424
  StartupBlobs blobs = {startup_blob, read_only_blob};
425
  v8::Isolate* v8_isolate = TestSerializer::NewIsolateFromBlob(blobs);
426 427 428
  CHECK(v8_isolate);
  {
    v8::Isolate::Scope isolate_scope(v8_isolate);
429

430 431 432 433
    Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
    HandleScope handle_scope(isolate);
    Handle<Object> root;
    Handle<JSGlobalProxy> global_proxy =
434
        isolate->factory()->NewUninitializedJSGlobalProxy(
435
            JSGlobalProxy::SizeWithEmbedderFields(0));
436
    {
437
      SnapshotData snapshot_data(partial_blob);
438 439 440
      root = PartialDeserializer::DeserializeContext(
                 isolate, &snapshot_data, false, global_proxy,
                 v8::DeserializeInternalFieldsCallback())
441
                 .ToHandleChecked();
442 443 444
      CHECK(root->IsContext());
      CHECK(Handle<Context>::cast(root)->global_proxy() == *global_proxy);
    }
445

446 447
    Handle<Object> root2;
    {
448
      SnapshotData snapshot_data(partial_blob);
449 450 451
      root2 = PartialDeserializer::DeserializeContext(
                  isolate, &snapshot_data, false, global_proxy,
                  v8::DeserializeInternalFieldsCallback())
452
                  .ToHandleChecked();
453 454
      CHECK(root2->IsContext());
      CHECK(!root.is_identical_to(root2));
455
    }
456
    partial_blob.Dispose();
457
  }
458
  v8_isolate->Dispose();
459
  blobs.Dispose();
460
  FreeCurrentEmbeddedBlob();
461 462
}

463
static void PartiallySerializeCustomContext(
464
    Vector<const byte>* startup_blob_out,
465
    Vector<const byte>* read_only_blob_out,
466
    Vector<const byte>* partial_blob_out) {
467
  v8::Isolate* v8_isolate = TestSerializer::NewIsolateInitialized();
468 469 470
  Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
  {
    v8::Isolate::Scope isolate_scope(v8_isolate);
471

472 473 474 475 476
    v8::Persistent<v8::Context> env;
    {
      HandleScope scope(isolate);
      env.Reset(v8_isolate, v8::Context::New(v8_isolate));
    }
477
    CHECK(!env.IsEmpty());
478 479 480 481 482 483 484 485 486 487
    {
      v8::HandleScope handle_scope(v8_isolate);
      v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
      // After execution, e's function context refers to the global object.
      CompileRun(
          "var e;"
          "(function() {"
          "  e = function(s) { return eval (s); }"
          "})();"
          "var o = this;"
488 489
          "var r = Math.random();"
          "var c = Math.sin(0) + Math.cos(0);"
490
          "var f = (function(a, b) { return a + b; }).bind(1, 2, 3);"
491 492 493
          "var s = parseInt('12345');"
          "var p = 0;"
          "(async ()=>{ p = await 42; })();");
494 495

      Vector<const uint8_t> source = ConstructSource(
496 497
          StaticCharVector("function g() { return [,"), StaticCharVector("1,"),
          StaticCharVector("];} a = g(); b = g(); b.push(1);"), 100000);
498
      v8::MaybeLocal<v8::String> source_str = v8::String::NewFromOneByte(
499
          v8_isolate, source.begin(), v8::NewStringType::kNormal,
500
          source.length());
501
      CompileRun(source_str.ToLocalChecked());
502 503 504 505
      source.Dispose();
    }
    // If we don't do this then we end up with a stray root pointing at the
    // context even after we have disposed of env.
506 507
    isolate->heap()->CollectAllAvailableGarbage(
        i::GarbageCollectionReason::kTesting);
508

509 510 511 512
    {
      v8::HandleScope handle_scope(v8_isolate);
      v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
    }
513

514
    i::Context raw_context = i::Context::cast(*v8::Utils::OpenPersistent(env));
515

516
    env.Reset();
517

518 519 520 521
    SnapshotByteSink read_only_sink;
    ReadOnlySerializer read_only_serializer(isolate);
    read_only_serializer.SerializeReadOnlyRoots();

522
    SnapshotByteSink startup_sink;
523
    StartupSerializer startup_serializer(isolate, &read_only_serializer);
524
    startup_serializer.SerializeStrongReferences();
525

526
    SnapshotByteSink partial_sink;
527 528
    PartialSerializer partial_serializer(isolate, &startup_serializer,
                                         v8::SerializeInternalFieldsCallback());
529
    partial_serializer.Serialize(&raw_context, false);
530

531
    startup_serializer.SerializeWeakReferencesAndDeferred();
532

533 534 535
    read_only_serializer.FinalizeSerialization();

    SnapshotData read_only_snapshot(&read_only_serializer);
536 537
    SnapshotData startup_snapshot(&startup_serializer);
    SnapshotData partial_snapshot(&partial_serializer);
538

539 540
    *partial_blob_out = WritePayload(partial_snapshot.RawData());
    *startup_blob_out = WritePayload(startup_snapshot.RawData());
541
    *read_only_blob_out = WritePayload(read_only_snapshot.RawData());
542
  }
543
  v8_isolate->Dispose();
544
  ReadOnlyHeap::ClearSharedHeapForTest();
545 546
}

547
UNINITIALIZED_TEST(PartialSerializerCustomContext) {
548
  DisableAlwaysOpt();
549
  Vector<const byte> startup_blob;
550
  Vector<const byte> read_only_blob;
551
  Vector<const byte> partial_blob;
552
  PartiallySerializeCustomContext(&startup_blob, &read_only_blob,
553
                                  &partial_blob);
554

555
  StartupBlobs blobs = {startup_blob, read_only_blob};
556
  v8::Isolate* v8_isolate = TestSerializer::NewIsolateFromBlob(blobs);
557 558 559
  CHECK(v8_isolate);
  {
    v8::Isolate::Scope isolate_scope(v8_isolate);
560

561 562 563 564
    Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
    HandleScope handle_scope(isolate);
    Handle<Object> root;
    Handle<JSGlobalProxy> global_proxy =
565
        isolate->factory()->NewUninitializedJSGlobalProxy(
566
            JSGlobalProxy::SizeWithEmbedderFields(0));
567
    {
568
      SnapshotData snapshot_data(partial_blob);
569 570 571
      root = PartialDeserializer::DeserializeContext(
                 isolate, &snapshot_data, false, global_proxy,
                 v8::DeserializeInternalFieldsCallback())
572
                 .ToHandleChecked();
573 574
      CHECK(root->IsContext());
      Handle<Context> context = Handle<Context>::cast(root);
575 576 577 578 579 580 581

      // Add context to the weak native context list
      context->set(Context::NEXT_CONTEXT_LINK,
                   isolate->heap()->native_contexts_list(),
                   UPDATE_WEAK_WRITE_BARRIER);
      isolate->heap()->set_native_contexts_list(*context);

582 583 584
      CHECK(context->global_proxy() == *global_proxy);
      Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o");
      Handle<JSObject> global_object(context->global_object(), isolate);
585
      Handle<Object> property = JSReceiver::GetDataProperty(global_object, o);
586 587
      CHECK(property.is_identical_to(global_proxy));

588
      v8::Local<v8::Context> v8_context = v8::Utils::ToLocal(context);
589
      v8::Context::Scope context_scope(v8_context);
590 591 592 593
      double r = CompileRun("r")
                     ->ToNumber(v8_isolate->GetCurrentContext())
                     .ToLocalChecked()
                     ->Value();
594 595 596 597 598 599 600 601 602 603 604 605
      CHECK(0.0 <= r && r < 1.0);
      // Math.random still works.
      double random = CompileRun("Math.random()")
                          ->ToNumber(v8_isolate->GetCurrentContext())
                          .ToLocalChecked()
                          ->Value();
      CHECK(0.0 <= random && random < 1.0);
      double c = CompileRun("c")
                     ->ToNumber(v8_isolate->GetCurrentContext())
                     .ToLocalChecked()
                     ->Value();
      CHECK_EQ(1, c);
606 607 608 609 610
      int f = CompileRun("f()")
                  ->ToNumber(v8_isolate->GetCurrentContext())
                  .ToLocalChecked()
                  ->Int32Value(v8_isolate->GetCurrentContext())
                  .FromJust();
611
      CHECK_EQ(5, f);
612 613 614 615 616
      f = CompileRun("e('f()')")
              ->ToNumber(v8_isolate->GetCurrentContext())
              .ToLocalChecked()
              ->Int32Value(v8_isolate->GetCurrentContext())
              .FromJust();
617
      CHECK_EQ(5, f);
618 619 620 621 622
      v8::Local<v8::String> s = CompileRun("s")
                                    ->ToString(v8_isolate->GetCurrentContext())
                                    .ToLocalChecked();
      CHECK(s->Equals(v8_isolate->GetCurrentContext(), v8_str("12345"))
                .FromJust());
623 624 625 626 627
      v8::Local<v8::String> p = CompileRun("p")
                                    ->ToString(v8_isolate->GetCurrentContext())
                                    .ToLocalChecked();
      CHECK(
          p->Equals(v8_isolate->GetCurrentContext(), v8_str("42")).FromJust());
628 629 630 631 632
      int a = CompileRun("a.length")
                  ->ToNumber(v8_isolate->GetCurrentContext())
                  .ToLocalChecked()
                  ->Int32Value(v8_isolate->GetCurrentContext())
                  .FromJust();
633
      CHECK_EQ(100001, a);
634 635 636 637 638
      int b = CompileRun("b.length")
                  ->ToNumber(v8_isolate->GetCurrentContext())
                  .ToLocalChecked()
                  ->Int32Value(v8_isolate->GetCurrentContext())
                  .FromJust();
639
      CHECK_EQ(100002, b);
640
    }
641
    partial_blob.Dispose();
642 643
  }
  v8_isolate->Dispose();
644
  blobs.Dispose();
645
  FreeCurrentEmbeddedBlob();
646 647
}

648
UNINITIALIZED_TEST(CustomSnapshotDataBlob1) {
649
  DisableAlwaysOpt();
650 651
  const char* source1 = "function f() { return 42; }";

652
  DisableEmbeddedBlobRefcounting();
653
  v8::StartupData data1 = CreateSnapshotDataBlob(source1);
654 655 656

  v8::Isolate::CreateParams params1;
  params1.snapshot_blob = &data1;
657 658
  params1.array_buffer_allocator = CcTest::array_buffer_allocator();

659
  // Test-appropriate equivalent of v8::Isolate::New.
660
  v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
661 662 663 664 665
  {
    v8::Isolate::Scope i_scope(isolate1);
    v8::HandleScope h_scope(isolate1);
    v8::Local<v8::Context> context = v8::Context::New(isolate1);
    v8::Context::Scope c_scope(context);
666 667 668
    v8::Maybe<int32_t> result =
        CompileRun("f()")->Int32Value(isolate1->GetCurrentContext());
    CHECK_EQ(42, result.FromJust());
669 670 671
    CHECK(CompileRun("this.g")->IsUndefined());
  }
  isolate1->Dispose();
672
  delete[] data1.data;  // We can dispose of the snapshot blob now.
673
  FreeCurrentEmbeddedBlob();
674 675
}

676 677 678 679 680 681 682 683
static void UnreachableCallback(const FunctionCallbackInfo<Value>& args) {
  UNREACHABLE();
}

UNINITIALIZED_TEST(CustomSnapshotDataBlobOverwriteGlobal) {
  DisableAlwaysOpt();
  const char* source1 = "function f() { return 42; }";

684
  DisableEmbeddedBlobRefcounting();
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
  v8::StartupData data1 = CreateSnapshotDataBlob(source1);

  v8::Isolate::CreateParams params1;
  params1.snapshot_blob = &data1;
  params1.array_buffer_allocator = CcTest::array_buffer_allocator();

  // Test that the snapshot overwrites the object template when there are
  // duplicate global properties.
  v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
  {
    v8::Isolate::Scope i_scope(isolate1);
    v8::HandleScope h_scope(isolate1);
    v8::Local<v8::ObjectTemplate> global_template =
        v8::ObjectTemplate::New(isolate1);
    global_template->Set(
        v8_str("f"), v8::FunctionTemplate::New(isolate1, UnreachableCallback));
    v8::Local<v8::Context> context =
        v8::Context::New(isolate1, nullptr, global_template);
    v8::Context::Scope c_scope(context);
    v8::Maybe<int32_t> result =
        CompileRun("f()")->Int32Value(isolate1->GetCurrentContext());
    CHECK_EQ(42, result.FromJust());
  }
  isolate1->Dispose();
  delete[] data1.data;  // We can dispose of the snapshot blob now.
  FreeCurrentEmbeddedBlob();
}

713 714 715 716 717 718 719 720 721 722
UNINITIALIZED_TEST(CustomSnapshotDataBlobStringNotInternalized) {
  DisableAlwaysOpt();
  const char* source1 =
      R"javascript(
      // String would be internalized if it came from a literal so create "A"
      // via a function call.
      var global = String.fromCharCode(65);
      function f() { return global; }
      )javascript";

723
  DisableEmbeddedBlobRefcounting();
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
  v8::StartupData data1 = CreateSnapshotDataBlob(source1);

  v8::Isolate::CreateParams params1;
  params1.snapshot_blob = &data1;
  params1.array_buffer_allocator = CcTest::array_buffer_allocator();

  // Test-appropriate equivalent of v8::Isolate::New.
  v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
  {
    v8::Isolate::Scope i_scope(isolate1);
    v8::HandleScope h_scope(isolate1);
    v8::Local<v8::Context> context = v8::Context::New(isolate1);
    v8::Context::Scope c_scope(context);
    v8::Local<v8::Value> result = CompileRun("f()").As<v8::Value>();
    CHECK(result->IsString());
    i::String str = *v8::Utils::OpenHandle(*result.As<v8::String>());
740
    CHECK_EQ(std::string(str.ToCString().get()), "A");
741
    CHECK(!str.IsInternalizedString());
742
    CHECK(!i::ReadOnlyHeap::Contains(str));
743 744 745 746 747 748
  }
  isolate1->Dispose();
  delete[] data1.data;  // We can dispose of the snapshot blob now.
  FreeCurrentEmbeddedBlob();
}

749 750 751 752
namespace {

void TestCustomSnapshotDataBlobWithIrregexpCode(
    v8::SnapshotCreator::FunctionCodeHandling function_code_handling) {
753 754
  DisableAlwaysOpt();
  const char* source =
755 756 757 758 759 760 761
      "var re1 = /\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\//;\n"
      "function f() { return '/* a comment */'.search(re1); }\n"
      "function g() { return 'not a comment'.search(re1); }\n"
      "function h() { return '// this is a comment'.search(re1); }\n"
      "var re2 = /a/;\n"
      "function i() { return '/* a comment */'.search(re2); }\n"
      "f(); f(); g(); g(); h(); h(); i(); i();\n";
762

763
  DisableEmbeddedBlobRefcounting();
764
  v8::StartupData data1 =
765
      CreateSnapshotDataBlobInternal(function_code_handling, source);
766
  ReadOnlyHeap::ClearSharedHeapForTest();
767 768 769 770 771 772 773 774 775 776 777 778

  v8::Isolate::CreateParams params1;
  params1.snapshot_blob = &data1;
  params1.array_buffer_allocator = CcTest::array_buffer_allocator();

  // Test-appropriate equivalent of v8::Isolate::New.
  v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
  {
    v8::Isolate::Scope i_scope(isolate1);
    v8::HandleScope h_scope(isolate1);
    v8::Local<v8::Context> context = v8::Context::New(isolate1);
    v8::Context::Scope c_scope(context);
779 780 781 782
    {
      // Check that compiled irregexp code has not been flushed prior to
      // serialization.
      i::Handle<i::JSRegExp> re =
783
          Utils::OpenHandle(*CompileRun("re1").As<v8::RegExp>());
784 785 786 787
      CHECK_EQ(re->HasCompiledCode(),
               function_code_handling ==
                   v8::SnapshotCreator::FunctionCodeHandling::kKeep);
    }
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
    {
      v8::Maybe<int32_t> result =
          CompileRun("f()")->Int32Value(isolate1->GetCurrentContext());
      CHECK_EQ(0, result.FromJust());
    }
    {
      v8::Maybe<int32_t> result =
          CompileRun("g()")->Int32Value(isolate1->GetCurrentContext());
      CHECK_EQ(-1, result.FromJust());
    }
    {
      v8::Maybe<int32_t> result =
          CompileRun("h()")->Int32Value(isolate1->GetCurrentContext());
      CHECK_EQ(-1, result.FromJust());
    }
803 804 805 806 807 808 809
    {
      // Check that ATOM regexp remains valid.
      i::Handle<i::JSRegExp> re =
          Utils::OpenHandle(*CompileRun("re2").As<v8::RegExp>());
      CHECK_EQ(re->TypeTag(), JSRegExp::ATOM);
      CHECK(!re->HasCompiledCode());
    }
810 811 812 813 814 815
  }
  isolate1->Dispose();
  delete[] data1.data;  // We can dispose of the snapshot blob now.
  FreeCurrentEmbeddedBlob();
}

816 817 818 819 820 821 822 823 824 825 826 827
}  // namespace

UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCodeKeepCode) {
  TestCustomSnapshotDataBlobWithIrregexpCode(
      v8::SnapshotCreator::FunctionCodeHandling::kKeep);
}

UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCodeClearCode) {
  TestCustomSnapshotDataBlobWithIrregexpCode(
      v8::SnapshotCreator::FunctionCodeHandling::kClear);
}

828
UNINITIALIZED_TEST(SnapshotChecksum) {
829 830 831
  DisableAlwaysOpt();
  const char* source1 = "function f() { return 42; }";

832
  DisableEmbeddedBlobRefcounting();
833 834 835 836 837
  v8::StartupData data1 = CreateSnapshotDataBlob(source1);
  CHECK(i::Snapshot::VerifyChecksum(&data1));
  const_cast<char*>(data1.data)[142] = data1.data[142] ^ 4;  // Flip a bit.
  CHECK(!i::Snapshot::VerifyChecksum(&data1));
  delete[] data1.data;  // We can dispose of the snapshot blob now.
838
  FreeCurrentEmbeddedBlob();
839 840
}

841 842 843 844 845 846
struct InternalFieldData {
  uint32_t data;
};

v8::StartupData SerializeInternalFields(v8::Local<v8::Object> holder, int index,
                                        void* data) {
847 848 849 850 851 852 853 854
  if (data == reinterpret_cast<void*>(2000)) {
    // Used for SnapshotCreatorTemplates test. We check that none of the fields
    // have been cleared yet.
    CHECK_NOT_NULL(holder->GetAlignedPointerFromInternalField(1));
  } else {
    CHECK_EQ(reinterpret_cast<void*>(2016), data);
  }
  if (index != 1) return {nullptr, 0};
855 856
  InternalFieldData* embedder_field = static_cast<InternalFieldData*>(
      holder->GetAlignedPointerFromInternalField(index));
857
  if (embedder_field == nullptr) return {nullptr, 0};
858 859 860 861 862 863 864 865 866 867 868
  int size = sizeof(*embedder_field);
  char* payload = new char[size];
  // We simply use memcpy to serialize the content.
  memcpy(payload, embedder_field, size);
  return {payload, size};
}

std::vector<InternalFieldData*> deserialized_data;

void DeserializeInternalFields(v8::Local<v8::Object> holder, int index,
                               v8::StartupData payload, void* data) {
869 870 871 872
  if (payload.raw_size == 0) {
    holder->SetAlignedPointerInInternalField(index, nullptr);
    return;
  }
873 874 875 876 877 878 879
  CHECK_EQ(reinterpret_cast<void*>(2017), data);
  InternalFieldData* embedder_field = new InternalFieldData{0};
  memcpy(embedder_field, payload.data, payload.raw_size);
  holder->SetAlignedPointerInInternalField(index, embedder_field);
  deserialized_data.push_back(embedder_field);
}

880
using Int32Expectations = std::vector<std::tuple<const char*, int32_t>>;
881 882 883 884 885 886 887

void TestInt32Expectations(const Int32Expectations& expectations) {
  for (const auto& e : expectations) {
    ExpectInt32(std::get<0>(e), std::get<1>(e));
  }
}

888 889 890 891
void TypedArrayTestHelper(
    const char* code, const Int32Expectations& expectations,
    const char* code_to_run_after_restore = nullptr,
    const Int32Expectations& after_restore_expectations = Int32Expectations()) {
892 893
  DisableAlwaysOpt();
  i::FLAG_allow_natives_syntax = true;
894
  DisableEmbeddedBlobRefcounting();
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
  v8::StartupData blob;
  {
    v8::SnapshotCreator creator;
    v8::Isolate* isolate = creator.GetIsolate();
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);

      CompileRun(code);
      TestInt32Expectations(expectations);
      creator.SetDefaultContext(
          context, v8::SerializeInternalFieldsCallback(
                       SerializeInternalFields, reinterpret_cast<void*>(2016)));
    }
    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
  }

914
  ReadOnlyHeap::ClearSharedHeapForTest();
915 916 917
  v8::Isolate::CreateParams create_params;
  create_params.snapshot_blob = &blob;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
918
  v8::Isolate* isolate = TestSerializer::NewIsolate(create_params);
919 920 921 922
  {
    v8::Isolate::Scope i_scope(isolate);
    v8::HandleScope h_scope(isolate);
    v8::Local<v8::Context> context = v8::Context::New(
923
        isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
924 925 926
        v8::MaybeLocal<v8::Value>(),
        v8::DeserializeInternalFieldsCallback(DeserializeInternalFields,
                                              reinterpret_cast<void*>(2017)));
927
    CHECK(deserialized_data.empty());  // We do not expect any embedder data.
928 929
    v8::Context::Scope c_scope(context);
    TestInt32Expectations(expectations);
930 931 932 933
    if (code_to_run_after_restore) {
      CompileRun(code_to_run_after_restore);
    }
    TestInt32Expectations(after_restore_expectations);
934 935
  }
  isolate->Dispose();
936
  delete[] blob.data;  // We can dispose of the snapshot blob now.
937
  FreeCurrentEmbeddedBlob();
938 939
}

940
UNINITIALIZED_TEST(CustomSnapshotDataBlobWithOffHeapTypedArray) {
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
  const char* code =
      "var x = new Uint8Array(128);"
      "x[0] = 12;"
      "var arr = new Array(17);"
      "arr[1] = 24;"
      "var y = new Uint32Array(arr);"
      "var buffer = new ArrayBuffer(128);"
      "var z = new Int16Array(buffer);"
      "z[0] = 48;";
  Int32Expectations expectations = {std::make_tuple("x[0]", 12),
                                    std::make_tuple("y[1]", 24),
                                    std::make_tuple("z[0]", 48)};

  TypedArrayTestHelper(code, expectations);
}

957
UNINITIALIZED_TEST(CustomSnapshotDataBlobSharedArrayBuffer) {
958 959 960 961
  const char* code =
      "var x = new Int32Array([12, 24, 48, 96]);"
      "var y = new Uint8Array(x.buffer)";
  Int32Expectations expectations = {
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
    std::make_tuple("x[0]", 12),
    std::make_tuple("x[1]", 24),
#if !V8_TARGET_BIG_ENDIAN
    std::make_tuple("y[0]", 12),
    std::make_tuple("y[1]", 0),
    std::make_tuple("y[2]", 0),
    std::make_tuple("y[3]", 0),
    std::make_tuple("y[4]", 24)
#else
    std::make_tuple("y[3]", 12),
    std::make_tuple("y[2]", 0),
    std::make_tuple("y[1]", 0),
    std::make_tuple("y[0]", 0),
    std::make_tuple("y[7]", 24)
#endif
  };
978 979 980 981

  TypedArrayTestHelper(code, expectations);
}

982
UNINITIALIZED_TEST(CustomSnapshotDataBlobArrayBufferWithOffset) {
983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000
  const char* code =
      "var x = new Int32Array([12, 24, 48, 96]);"
      "var y = new Int32Array(x.buffer, 4, 2)";
  Int32Expectations expectations = {
      std::make_tuple("x[1]", 24), std::make_tuple("x[2]", 48),
      std::make_tuple("y[0]", 24), std::make_tuple("y[1]", 48),
  };

  // Verify that the typed arrays use the same buffer (not independent copies).
  const char* code_to_run_after_restore = "x[2] = 57; y[0] = 42;";
  Int32Expectations after_restore_expectations = {
      std::make_tuple("x[1]", 42), std::make_tuple("y[1]", 57),
  };

  TypedArrayTestHelper(code, expectations, code_to_run_after_restore,
                       after_restore_expectations);
}

1001
UNINITIALIZED_TEST(CustomSnapshotDataBlobDataView) {
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
  const char* code =
      "var x = new Int8Array([1, 2, 3, 4]);"
      "var v = new DataView(x.buffer)";
  Int32Expectations expectations = {std::make_tuple("v.getInt8(0)", 1),
                                    std::make_tuple("v.getInt8(1)", 2),
                                    std::make_tuple("v.getInt16(0)", 258),
                                    std::make_tuple("v.getInt16(1)", 515)};

  TypedArrayTestHelper(code, expectations);
}

1013
UNINITIALIZED_TEST(CustomSnapshotDataBlobDetachedArrayBuffer) {
1014 1015
  const char* code =
      "var x = new Int16Array([12, 24, 48]);"
1016
      "%ArrayBufferDetach(x.buffer);";
1017 1018 1019 1020 1021
  Int32Expectations expectations = {std::make_tuple("x.buffer.byteLength", 0),
                                    std::make_tuple("x.length", 0)};

  DisableAlwaysOpt();
  i::FLAG_allow_natives_syntax = true;
1022
  DisableEmbeddedBlobRefcounting();
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
  v8::StartupData blob;
  {
    v8::SnapshotCreator creator;
    v8::Isolate* isolate = creator.GetIsolate();
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);

      CompileRun(code);
      TestInt32Expectations(expectations);
      creator.SetDefaultContext(
          context, v8::SerializeInternalFieldsCallback(
                       SerializeInternalFields, reinterpret_cast<void*>(2016)));
    }
    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
  }

1042
  ReadOnlyHeap::ClearSharedHeapForTest();
1043 1044 1045
  v8::Isolate::CreateParams create_params;
  create_params.snapshot_blob = &blob;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
1046
  v8::Isolate* isolate = TestSerializer::NewIsolate(create_params);
1047 1048 1049 1050
  {
    v8::Isolate::Scope i_scope(isolate);
    v8::HandleScope h_scope(isolate);
    v8::Local<v8::Context> context = v8::Context::New(
1051
        isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
        v8::MaybeLocal<v8::Value>(),
        v8::DeserializeInternalFieldsCallback(DeserializeInternalFields,
                                              reinterpret_cast<void*>(2017)));
    v8::Context::Scope c_scope(context);
    TestInt32Expectations(expectations);

    v8::Local<v8::Value> x = CompileRun("x");
    CHECK(x->IsTypedArray());
    i::Handle<i::JSTypedArray> array =
        i::Handle<i::JSTypedArray>::cast(v8::Utils::OpenHandle(*x));
1062
    CHECK(array->WasDetached());
1063 1064
  }
  isolate->Dispose();
1065
  delete[] blob.data;  // We can dispose of the snapshot blob now.
1066
  FreeCurrentEmbeddedBlob();
1067 1068 1069 1070 1071 1072 1073 1074 1075
}

i::Handle<i::JSArrayBuffer> GetBufferFromTypedArray(
    v8::Local<v8::Value> typed_array) {
  CHECK(typed_array->IsTypedArray());

  i::Handle<i::JSArrayBufferView> view = i::Handle<i::JSArrayBufferView>::cast(
      v8::Utils::OpenHandle(*typed_array));

1076
  return i::handle(i::JSArrayBuffer::cast(view->buffer()), view->GetIsolate());
1077 1078
}

1079
UNINITIALIZED_TEST(CustomSnapshotDataBlobOnOrOffHeapTypedArray) {
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
  const char* code =
      "var x = new Uint8Array(8);"
      "x[0] = 12;"
      "x[7] = 24;"
      "var y = new Int16Array([12, 24, 48]);"
      "var z = new Int32Array(64);"
      "z[0] = 96;";
  Int32Expectations expectations = {
      std::make_tuple("x[0]", 12), std::make_tuple("x[7]", 24),
      std::make_tuple("y[2]", 48), std::make_tuple("z[0]", 96)};

  DisableAlwaysOpt();
  i::FLAG_allow_natives_syntax = true;
1093
  DisableEmbeddedBlobRefcounting();
1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
  v8::StartupData blob;
  {
    v8::SnapshotCreator creator;
    v8::Isolate* isolate = creator.GetIsolate();
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);

      CompileRun(code);
      TestInt32Expectations(expectations);
      creator.SetDefaultContext(
          context, v8::SerializeInternalFieldsCallback(
                       SerializeInternalFields, reinterpret_cast<void*>(2016)));
    }
    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
  }

1113
  ReadOnlyHeap::ClearSharedHeapForTest();
1114 1115 1116
  v8::Isolate::CreateParams create_params;
  create_params.snapshot_blob = &blob;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
1117
  v8::Isolate* isolate = TestSerializer::NewIsolate(create_params);
1118 1119 1120 1121
  {
    v8::Isolate::Scope i_scope(isolate);
    v8::HandleScope h_scope(isolate);
    v8::Local<v8::Context> context = v8::Context::New(
1122
        isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
        v8::MaybeLocal<v8::Value>(),
        v8::DeserializeInternalFieldsCallback(DeserializeInternalFields,
                                              reinterpret_cast<void*>(2017)));
    v8::Context::Scope c_scope(context);
    TestInt32Expectations(expectations);

    i::Handle<i::JSArrayBuffer> buffer =
        GetBufferFromTypedArray(CompileRun("x"));
    // The resulting buffer should be on-heap.
    CHECK_NULL(buffer->backing_store());

    buffer = GetBufferFromTypedArray(CompileRun("y"));
    CHECK_NULL(buffer->backing_store());

    buffer = GetBufferFromTypedArray(CompileRun("z"));
    // The resulting buffer should be off-heap.
    CHECK_NOT_NULL(buffer->backing_store());
  }
  isolate->Dispose();
1142
  delete[] blob.data;  // We can dispose of the snapshot blob now.
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
  FreeCurrentEmbeddedBlob();
}

UNINITIALIZED_TEST(CustomSnapshotDataBlobTypedArrayNoEmbedderFieldCallback) {
  const char* code = "var x = new Uint8Array(8);";
  DisableAlwaysOpt();
  i::FLAG_allow_natives_syntax = true;
  DisableEmbeddedBlobRefcounting();
  v8::StartupData blob;
  {
    v8::SnapshotCreator creator;
    v8::Isolate* isolate = creator.GetIsolate();
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);

      CompileRun(code);
      creator.SetDefaultContext(context, v8::SerializeInternalFieldsCallback());
    }
    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
  }

1167
  ReadOnlyHeap::ClearSharedHeapForTest();
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
  v8::Isolate::CreateParams create_params;
  create_params.snapshot_blob = &blob;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate = TestSerializer::NewIsolate(create_params);
  {
    v8::Isolate::Scope i_scope(isolate);
    v8::HandleScope h_scope(isolate);
    v8::Local<v8::Context> context = v8::Context::New(
        isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
        v8::MaybeLocal<v8::Value>(), v8::DeserializeInternalFieldsCallback());
    v8::Context::Scope c_scope(context);
  }
  isolate->Dispose();
  delete[] blob.data;  // We can dispose of the snapshot blob now.
1182
  FreeCurrentEmbeddedBlob();
1183 1184
}

1185
UNINITIALIZED_TEST(CustomSnapshotDataBlob2) {
1186
  DisableAlwaysOpt();
1187 1188 1189 1190 1191
  const char* source2 =
      "function f() { return g() * 2; }"
      "function g() { return 43; }"
      "/./.test('a')";

1192
  DisableEmbeddedBlobRefcounting();
1193
  v8::StartupData data2 = CreateSnapshotDataBlob(source2);
1194 1195 1196

  v8::Isolate::CreateParams params2;
  params2.snapshot_blob = &data2;
1197
  params2.array_buffer_allocator = CcTest::array_buffer_allocator();
1198
  // Test-appropriate equivalent of v8::Isolate::New.
1199
  v8::Isolate* isolate2 = TestSerializer::NewIsolate(params2);
1200 1201 1202 1203 1204
  {
    v8::Isolate::Scope i_scope(isolate2);
    v8::HandleScope h_scope(isolate2);
    v8::Local<v8::Context> context = v8::Context::New(isolate2);
    v8::Context::Scope c_scope(context);
1205 1206 1207 1208 1209
    v8::Maybe<int32_t> result =
        CompileRun("f()")->Int32Value(isolate2->GetCurrentContext());
    CHECK_EQ(86, result.FromJust());
    result = CompileRun("g()")->Int32Value(isolate2->GetCurrentContext());
    CHECK_EQ(43, result.FromJust());
1210
  }
1211
  isolate2->Dispose();
1212
  delete[] data2.data;  // We can dispose of the snapshot blob now.
1213
  FreeCurrentEmbeddedBlob();
1214 1215
}

1216 1217 1218 1219 1220
static void SerializationFunctionTemplate(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  args.GetReturnValue().Set(args[0]);
}

1221
UNINITIALIZED_TEST(CustomSnapshotDataBlobOutdatedContextWithOverflow) {
1222
  DisableAlwaysOpt();
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
  const char* source1 =
      "var o = {};"
      "(function() {"
      "  function f1(x) { return f2(x) instanceof Array; }"
      "  function f2(x) { return foo.bar(x); }"
      "  o.a = f2.bind(null);"
      "  o.b = 1;"
      "  o.c = 2;"
      "  o.d = 3;"
      "  o.e = 4;"
      "})();\n";

  const char* source2 = "o.a(42)";

1237
  DisableEmbeddedBlobRefcounting();
1238
  v8::StartupData data = CreateSnapshotDataBlob(source1);
1239 1240 1241 1242 1243

  v8::Isolate::CreateParams params;
  params.snapshot_blob = &data;
  params.array_buffer_allocator = CcTest::array_buffer_allocator();

1244
  // Test-appropriate equivalent of v8::Isolate::New.
1245
  v8::Isolate* isolate = TestSerializer::NewIsolate(params);
1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256
  {
    v8::Isolate::Scope i_scope(isolate);
    v8::HandleScope h_scope(isolate);

    v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
    v8::Local<v8::ObjectTemplate> property = v8::ObjectTemplate::New(isolate);
    v8::Local<v8::FunctionTemplate> function =
        v8::FunctionTemplate::New(isolate, SerializationFunctionTemplate);
    property->Set(isolate, "bar", function);
    global->Set(isolate, "foo", property);

1257
    v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);
1258 1259
    v8::Context::Scope c_scope(context);
    v8::Local<v8::Value> result = CompileRun(source2);
1260 1261
    v8::Maybe<bool> compare =
        v8_str("42")->Equals(isolate->GetCurrentContext(), result);
1262
    CHECK(compare.FromJust());
1263 1264
  }
  isolate->Dispose();
1265
  delete[] data.data;  // We can dispose of the snapshot blob now.
1266
  FreeCurrentEmbeddedBlob();
1267 1268
}

1269
UNINITIALIZED_TEST(CustomSnapshotDataBlobWithLocker) {
1270
  DisableAlwaysOpt();
1271
  DisableEmbeddedBlobRefcounting();
1272 1273 1274
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate0 = v8::Isolate::New(create_params);
1275 1276 1277 1278 1279 1280
  {
    v8::Locker locker(isolate0);
    v8::Isolate::Scope i_scope(isolate0);
    v8::HandleScope h_scope(isolate0);
    v8::Local<v8::Context> context = v8::Context::New(isolate0);
    v8::Context::Scope c_scope(context);
1281 1282 1283
    v8::Maybe<int32_t> result =
        CompileRun("Math.cos(0)")->Int32Value(isolate0->GetCurrentContext());
    CHECK_EQ(1, result.FromJust());
1284 1285 1286 1287 1288
  }
  isolate0->Dispose();

  const char* source1 = "function f() { return 42; }";

1289
  DisableEmbeddedBlobRefcounting();
1290
  ReadOnlyHeap::ClearSharedHeapForTest();
1291
  v8::StartupData data1 = CreateSnapshotDataBlob(source1);
1292 1293 1294

  v8::Isolate::CreateParams params1;
  params1.snapshot_blob = &data1;
1295
  params1.array_buffer_allocator = CcTest::array_buffer_allocator();
1296
  // Test-appropriate equivalent of v8::Isolate::New.
1297
  v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
1298 1299 1300 1301 1302 1303
  {
    v8::Locker locker(isolate1);
    v8::Isolate::Scope i_scope(isolate1);
    v8::HandleScope h_scope(isolate1);
    v8::Local<v8::Context> context = v8::Context::New(isolate1);
    v8::Context::Scope c_scope(context);
1304 1305
    v8::Maybe<int32_t> result = CompileRun("f()")->Int32Value(context);
    CHECK_EQ(42, result.FromJust());
1306 1307
  }
  isolate1->Dispose();
1308
  delete[] data1.data;  // We can dispose of the snapshot blob now.
1309
  FreeCurrentEmbeddedBlob();
1310 1311
}

1312
UNINITIALIZED_TEST(CustomSnapshotDataBlobStackOverflow) {
1313
  DisableAlwaysOpt();
1314 1315 1316 1317 1318 1319 1320 1321 1322 1323
  const char* source =
      "var a = [0];"
      "var b = a;"
      "for (var i = 0; i < 10000; i++) {"
      "  var c = [i];"
      "  b.push(c);"
      "  b.push(c);"
      "  b = c;"
      "}";

1324
  DisableEmbeddedBlobRefcounting();
1325
  v8::StartupData data = CreateSnapshotDataBlob(source);
1326 1327 1328 1329 1330

  v8::Isolate::CreateParams params;
  params.snapshot_blob = &data;
  params.array_buffer_allocator = CcTest::array_buffer_allocator();

1331
  // Test-appropriate equivalent of v8::Isolate::New.
1332
  v8::Isolate* isolate = TestSerializer::NewIsolate(params);
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
  {
    v8::Isolate::Scope i_scope(isolate);
    v8::HandleScope h_scope(isolate);
    v8::Local<v8::Context> context = v8::Context::New(isolate);
    v8::Context::Scope c_scope(context);
    const char* test =
        "var sum = 0;"
        "while (a) {"
        "  sum += a[0];"
        "  a = a[1];"
        "}"
        "sum";
1345 1346 1347
    v8::Maybe<int32_t> result =
        CompileRun(test)->Int32Value(isolate->GetCurrentContext());
    CHECK_EQ(9999 * 5000, result.FromJust());
1348 1349
  }
  isolate->Dispose();
1350
  delete[] data.data;  // We can dispose of the snapshot blob now.
1351
  FreeCurrentEmbeddedBlob();
1352 1353
}

1354 1355 1356 1357
bool IsCompiled(const char* name) {
  return i::Handle<i::JSFunction>::cast(
             v8::Utils::OpenHandle(*CompileRun(name)))
      ->shared()
1358
      .is_compiled();
1359 1360
}

1361
UNINITIALIZED_TEST(SnapshotDataBlobWithWarmup) {
1362
  DisableAlwaysOpt();
1363
  const char* warmup = "Math.abs(1); Math.random = 1;";
1364

1365
  DisableEmbeddedBlobRefcounting();
1366 1367 1368
  v8::StartupData cold = CreateSnapshotDataBlob(nullptr);
  v8::StartupData warm = WarmUpSnapshotDataBlobInternal(cold, warmup);
  ReadOnlyHeap::ClearSharedHeapForTest();
1369 1370 1371 1372 1373 1374
  delete[] cold.data;

  v8::Isolate::CreateParams params;
  params.snapshot_blob = &warm;
  params.array_buffer_allocator = CcTest::array_buffer_allocator();

1375
  // Test-appropriate equivalent of v8::Isolate::New.
1376
  v8::Isolate* isolate = TestSerializer::NewIsolate(params);
1377 1378 1379 1380 1381 1382 1383
  {
    v8::Isolate::Scope i_scope(isolate);
    v8::HandleScope h_scope(isolate);
    v8::Local<v8::Context> context = v8::Context::New(isolate);
    v8::Context::Scope c_scope(context);
    // Running the warmup script has effect on whether functions are
    // pre-compiled, but does not pollute the context.
1384
    CHECK(IsCompiled("Math.abs"));
1385
    CHECK(IsCompiled("String.raw"));
1386
    CHECK(CompileRun("Math.random")->IsFunction());
1387 1388
  }
  isolate->Dispose();
1389
  delete[] warm.data;
1390
  FreeCurrentEmbeddedBlob();
1391 1392
}

1393
UNINITIALIZED_TEST(CustomSnapshotDataBlobWithWarmup) {
1394
  DisableAlwaysOpt();
1395
  const char* source =
1396
      "function f() { return Math.abs(1); }\n"
1397
      "function g() { return String.raw(1); }\n"
1398
      "Object.valueOf(1);"
1399 1400 1401
      "var a = 5";
  const char* warmup = "a = f()";

1402
  DisableEmbeddedBlobRefcounting();
1403
  v8::StartupData cold = CreateSnapshotDataBlob(source);
1404 1405
  v8::StartupData warm = WarmUpSnapshotDataBlobInternal(cold, warmup);
  ReadOnlyHeap::ClearSharedHeapForTest();
1406 1407 1408 1409 1410 1411
  delete[] cold.data;

  v8::Isolate::CreateParams params;
  params.snapshot_blob = &warm;
  params.array_buffer_allocator = CcTest::array_buffer_allocator();

1412
  // Test-appropriate equivalent of v8::Isolate::New.
1413
  v8::Isolate* isolate = TestSerializer::NewIsolate(params);
1414 1415 1416 1417 1418 1419 1420 1421
  {
    v8::Isolate::Scope i_scope(isolate);
    v8::HandleScope h_scope(isolate);
    v8::Local<v8::Context> context = v8::Context::New(isolate);
    v8::Context::Scope c_scope(context);
    // Running the warmup script has effect on whether functions are
    // pre-compiled, but does not pollute the context.
    CHECK(IsCompiled("f"));
1422
    CHECK(IsCompiled("Math.abs"));
1423
    CHECK(!IsCompiled("g"));
1424
    CHECK(IsCompiled("String.raw"));
1425
    CHECK(IsCompiled("Array.prototype.lastIndexOf"));
1426 1427 1428
    CHECK_EQ(5, CompileRun("a")->Int32Value(context).FromJust());
  }
  isolate->Dispose();
1429
  delete[] warm.data;
1430
  FreeCurrentEmbeddedBlob();
1431
}
1432

1433
UNINITIALIZED_TEST(CustomSnapshotDataBlobImmortalImmovableRoots) {
1434
  DisableAlwaysOpt();
1435 1436 1437 1438
  // Flood the startup snapshot with shared function infos. If they are
  // serialized before the immortal immovable root, the root will no longer end
  // up on the first page.
  Vector<const uint8_t> source =
1439 1440 1441
      ConstructSource(StaticCharVector("var a = [];"),
                      StaticCharVector("a.push(function() {return 7});"),
                      StaticCharVector("\0"), 10000);
1442

1443
  DisableEmbeddedBlobRefcounting();
1444
  v8::StartupData data =
1445
      CreateSnapshotDataBlob(reinterpret_cast<const char*>(source.begin()));
1446 1447 1448 1449 1450

  v8::Isolate::CreateParams params;
  params.snapshot_blob = &data;
  params.array_buffer_allocator = CcTest::array_buffer_allocator();

1451
  // Test-appropriate equivalent of v8::Isolate::New.
1452
  v8::Isolate* isolate = TestSerializer::NewIsolate(params);
1453 1454 1455 1456 1457 1458 1459 1460 1461
  {
    v8::Isolate::Scope i_scope(isolate);
    v8::HandleScope h_scope(isolate);
    v8::Local<v8::Context> context = v8::Context::New(isolate);
    v8::Context::Scope c_scope(context);
    CHECK_EQ(7, CompileRun("a[0]()")->Int32Value(context).FromJust());
  }
  isolate->Dispose();
  source.Dispose();
1462
  delete[] data.data;  // We can dispose of the snapshot blob now.
1463
  FreeCurrentEmbeddedBlob();
1464 1465
}

1466 1467 1468 1469 1470 1471 1472 1473 1474 1475
TEST(TestThatAlwaysSucceeds) {
}


TEST(TestThatAlwaysFails) {
  bool ArtificialFailure = false;
  CHECK(ArtificialFailure);
}


1476 1477
int CountBuiltins() {
  // Check that we have not deserialized any additional builtin.
1478
  HeapObjectIterator iterator(CcTest::heap());
1479 1480
  DisallowHeapAllocation no_allocation;
  int counter = 0;
1481 1482
  for (HeapObject obj = iterator.Next(); !obj.is_null();
       obj = iterator.Next()) {
1483
    if (obj.IsCode() && Code::cast(obj).kind() == Code::BUILTIN) counter++;
1484 1485 1486 1487
  }
  return counter;
}

1488 1489
static Handle<SharedFunctionInfo> CompileScript(
    Isolate* isolate, Handle<String> source, Handle<String> name,
1490
    ScriptData* cached_data, v8::ScriptCompiler::CompileOptions options) {
1491
  return Compiler::GetSharedFunctionInfoForScript(
1492 1493 1494
             isolate, source, Compiler::ScriptDetails(name),
             v8::ScriptOriginOptions(), nullptr, cached_data, options,
             ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE)
1495
      .ToHandleChecked();
1496 1497
}

1498 1499 1500 1501 1502
static Handle<SharedFunctionInfo> CompileScriptAndProduceCache(
    Isolate* isolate, Handle<String> source, Handle<String> name,
    ScriptData** script_data, v8::ScriptCompiler::CompileOptions options) {
  Handle<SharedFunctionInfo> sfi =
      Compiler::GetSharedFunctionInfoForScript(
1503 1504 1505
          isolate, source, Compiler::ScriptDetails(name),
          v8::ScriptOriginOptions(), nullptr, nullptr, options,
          ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE)
1506 1507
          .ToHandleChecked();
  std::unique_ptr<ScriptCompiler::CachedData> cached_data(
1508
      ScriptCompiler::CreateCodeCache(ToApiHandle<UnboundScript>(sfi)));
1509 1510 1511 1512 1513 1514 1515
  uint8_t* buffer = NewArray<uint8_t>(cached_data->length);
  MemCopy(buffer, cached_data->data, cached_data->length);
  *script_data = new i::ScriptData(buffer, cached_data->length);
  (*script_data)->AcquireDataOwnership();
  return sfi;
}

1516 1517
TEST(CodeSerializerWithProfiler) {
  FLAG_enable_lazy_source_positions = true;
1518
  FLAG_stress_lazy_source_positions = false;
1519 1520 1521

  LocalContext context;
  Isolate* isolate = CcTest::i_isolate();
1522 1523
  isolate->compilation_cache()
      ->DisableScriptAndEval();  // Disable same-isolate code cache.
1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560

  v8::HandleScope scope(CcTest::isolate());

  const char* source = "1 + 1";

  Handle<String> orig_source = isolate->factory()
                                   ->NewStringFromUtf8(CStrVector(source))
                                   .ToHandleChecked();
  Handle<String> copy_source = isolate->factory()
                                   ->NewStringFromUtf8(CStrVector(source))
                                   .ToHandleChecked();
  CHECK(!orig_source.is_identical_to(copy_source));
  CHECK(orig_source->Equals(*copy_source));

  ScriptData* cache = nullptr;

  Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
      isolate, orig_source, Handle<String>(), &cache,
      v8::ScriptCompiler::kNoCompileOptions);

  CHECK(!orig->GetBytecodeArray().HasSourcePositionTable());

  isolate->set_is_profiling(true);

  // This does not assert that no compilation can happen as source position
  // collection could trigger it.
  Handle<SharedFunctionInfo> copy =
      CompileScript(isolate, copy_source, Handle<String>(), cache,
                    v8::ScriptCompiler::kConsumeCodeCache);

  // Since the profiler is now enabled, source positions should be collected
  // after deserialization.
  CHECK(copy->GetBytecodeArray().HasSourcePositionTable());

  delete cache;
}

1561
void TestCodeSerializerOnePlusOneImpl(bool verify_builtins_count = true) {
1562
  LocalContext context;
1563
  Isolate* isolate = CcTest::i_isolate();
1564 1565
  isolate->compilation_cache()
      ->DisableScriptAndEval();  // Disable same-isolate code cache.
1566

1567
  v8::HandleScope scope(CcTest::isolate());
1568

1569
  const char* source = "1 + 1";
1570

1571 1572 1573 1574 1575 1576 1577 1578
  Handle<String> orig_source = isolate->factory()
                                   ->NewStringFromUtf8(CStrVector(source))
                                   .ToHandleChecked();
  Handle<String> copy_source = isolate->factory()
                                   ->NewStringFromUtf8(CStrVector(source))
                                   .ToHandleChecked();
  CHECK(!orig_source.is_identical_to(copy_source));
  CHECK(orig_source->Equals(*copy_source));
1579

1580
  ScriptData* cache = nullptr;
1581

1582 1583 1584
  Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
      isolate, orig_source, Handle<String>(), &cache,
      v8::ScriptCompiler::kNoCompileOptions);
1585 1586 1587

  int builtins_count = CountBuiltins();

1588 1589 1590
  Handle<SharedFunctionInfo> copy;
  {
    DisallowCompilation no_compile_expected(isolate);
1591
    copy = CompileScript(isolate, copy_source, Handle<String>(), cache,
1592
                         v8::ScriptCompiler::kConsumeCodeCache);
1593
  }
1594

1595
  CHECK_NE(*orig, *copy);
1596
  CHECK(Script::cast(copy->script()).source() == *copy_source);
1597

1598
  Handle<JSFunction> copy_fun =
1599
      isolate->factory()->NewFunctionFromSharedFunctionInfo(
1600
          copy, isolate->native_context());
1601
  Handle<JSObject> global(isolate->context().global_object(), isolate);
1602
  Handle<Object> copy_result =
1603
      Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1604
  CHECK_EQ(2, Handle<Smi>::cast(copy_result)->value());
1605

1606
  if (verify_builtins_count) CHECK_EQ(builtins_count, CountBuiltins());
1607 1608 1609

  delete cache;
}
1610

1611 1612
TEST(CodeSerializerOnePlusOne) { TestCodeSerializerOnePlusOneImpl(); }

1613 1614 1615 1616 1617 1618 1619 1620 1621 1622
// See bug v8:9122
#ifndef V8_TARGET_ARCH_ARM
TEST(CodeSerializerOnePlusOneWithInterpretedFramesNativeStack) {
  FLAG_interpreted_frames_native_stack = true;
  // We pass false because this test will create IET copies (which are
  // builtins).
  TestCodeSerializerOnePlusOneImpl(false);
}
#endif

1623 1624 1625 1626 1627 1628 1629
TEST(CodeSerializerOnePlusOneWithDebugger) {
  v8::HandleScope scope(CcTest::isolate());
  static v8::debug::DebugDelegate dummy_delegate;
  v8::debug::SetDebugDelegate(CcTest::isolate(), &dummy_delegate);
  TestCodeSerializerOnePlusOneImpl();
}

1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644
TEST(CodeSerializerOnePlusOne1) {
  FLAG_serialization_chunk_size = 1;
  TestCodeSerializerOnePlusOneImpl();
}

TEST(CodeSerializerOnePlusOne32) {
  FLAG_serialization_chunk_size = 32;
  TestCodeSerializerOnePlusOneImpl();
}

TEST(CodeSerializerOnePlusOne4K) {
  FLAG_serialization_chunk_size = 4 * KB;
  TestCodeSerializerOnePlusOneImpl();
}

1645
TEST(CodeSerializerPromotedToCompilationCache) {
1646 1647 1648 1649 1650 1651 1652 1653 1654 1655
  LocalContext context;
  Isolate* isolate = CcTest::i_isolate();

  v8::HandleScope scope(CcTest::isolate());

  const char* source = "1 + 1";

  Handle<String> src = isolate->factory()
                           ->NewStringFromUtf8(CStrVector(source))
                           .ToHandleChecked();
1656
  ScriptData* cache = nullptr;
1657

1658 1659
  CompileScriptAndProduceCache(isolate, src, src, &cache,
                               v8::ScriptCompiler::kNoCompileOptions);
1660 1661 1662

  DisallowCompilation no_compile_expected(isolate);
  Handle<SharedFunctionInfo> copy = CompileScript(
1663
      isolate, src, src, cache, v8::ScriptCompiler::kConsumeCodeCache);
1664

1665 1666 1667 1668
  MaybeHandle<SharedFunctionInfo> shared =
      isolate->compilation_cache()->LookupScript(
          src, src, 0, 0, v8::ScriptOriginOptions(), isolate->native_context(),
          LanguageMode::kSloppy);
1669

1670
  CHECK(*shared.ToHandleChecked() == *copy);
1671 1672 1673 1674

  delete cache;
}

1675
TEST(CodeSerializerInternalizedString) {
1676
  LocalContext context;
1677
  Isolate* isolate = CcTest::i_isolate();
1678 1679
  isolate->compilation_cache()
      ->DisableScriptAndEval();  // Disable same-isolate code cache.
1680

1681 1682
  v8::HandleScope scope(CcTest::isolate());

1683
  const char* source = "'string1'";
1684

1685 1686 1687 1688 1689 1690 1691 1692
  Handle<String> orig_source = isolate->factory()
                                   ->NewStringFromUtf8(CStrVector(source))
                                   .ToHandleChecked();
  Handle<String> copy_source = isolate->factory()
                                   ->NewStringFromUtf8(CStrVector(source))
                                   .ToHandleChecked();
  CHECK(!orig_source.is_identical_to(copy_source));
  CHECK(orig_source->Equals(*copy_source));
1693

1694
  Handle<JSObject> global(isolate->context().global_object(), isolate);
1695

1696 1697 1698 1699
  i::ScriptData* script_data = nullptr;
  Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
      isolate, orig_source, Handle<String>(), &script_data,
      v8::ScriptCompiler::kNoCompileOptions);
1700 1701 1702 1703
  Handle<JSFunction> orig_fun =
      isolate->factory()->NewFunctionFromSharedFunctionInfo(
          orig, isolate->native_context());
  Handle<Object> orig_result =
1704
      Execution::Call(isolate, orig_fun, global, 0, nullptr).ToHandleChecked();
1705 1706 1707 1708
  CHECK(orig_result->IsInternalizedString());

  int builtins_count = CountBuiltins();

1709 1710 1711
  Handle<SharedFunctionInfo> copy;
  {
    DisallowCompilation no_compile_expected(isolate);
1712
    copy = CompileScript(isolate, copy_source, Handle<String>(), script_data,
1713
                         v8::ScriptCompiler::kConsumeCodeCache);
1714
  }
1715
  CHECK_NE(*orig, *copy);
1716
  CHECK(Script::cast(copy->script()).source() == *copy_source);
1717

1718 1719 1720 1721 1722
  Handle<JSFunction> copy_fun =
      isolate->factory()->NewFunctionFromSharedFunctionInfo(
          copy, isolate->native_context());
  CHECK_NE(*orig_fun, *copy_fun);
  Handle<Object> copy_result =
1723
      Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1724 1725 1726 1727 1728 1729 1730
  CHECK(orig_result.is_identical_to(copy_result));
  Handle<String> expected =
      isolate->factory()->NewStringFromAsciiChecked("string1");

  CHECK(Handle<String>::cast(copy_result)->Equals(*expected));
  CHECK_EQ(builtins_count, CountBuiltins());

1731
  delete script_data;
1732
}
1733

1734
TEST(CodeSerializerLargeCodeObject) {
1735 1736
  LocalContext context;
  Isolate* isolate = CcTest::i_isolate();
1737 1738
  isolate->compilation_cache()
      ->DisableScriptAndEval();  // Disable same-isolate code cache.
1739 1740 1741

  v8::HandleScope scope(CcTest::isolate());

1742 1743 1744 1745
  // The serializer only tests the shared code, which is always the unoptimized
  // code. Don't even bother generating optimized code to avoid timeouts.
  FLAG_always_opt = false;

1746
  Vector<const uint8_t> source = ConstructSource(
1747 1748
      StaticCharVector("var j=1; if (j == 0) {"),
      StaticCharVector(
1749
          "for (let i of Object.prototype) for (let k = 0; k < 0; ++k);"),
1750
      StaticCharVector("} j=7; j"), 2000);
1751 1752 1753
  Handle<String> source_str =
      isolate->factory()->NewStringFromOneByte(source).ToHandleChecked();

1754
  Handle<JSObject> global(isolate->context().global_object(), isolate);
1755
  ScriptData* cache = nullptr;
1756

1757 1758 1759
  Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
      isolate, source_str, Handle<String>(), &cache,
      v8::ScriptCompiler::kNoCompileOptions);
1760

1761
  CHECK(isolate->heap()->InSpace(orig->abstract_code(), LO_SPACE));
1762 1763 1764 1765

  Handle<SharedFunctionInfo> copy;
  {
    DisallowCompilation no_compile_expected(isolate);
1766
    copy = CompileScript(isolate, source_str, Handle<String>(), cache,
1767
                         v8::ScriptCompiler::kConsumeCodeCache);
1768 1769 1770 1771 1772 1773 1774 1775
  }
  CHECK_NE(*orig, *copy);

  Handle<JSFunction> copy_fun =
      isolate->factory()->NewFunctionFromSharedFunctionInfo(
          copy, isolate->native_context());

  Handle<Object> copy_result =
1776
      Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1777 1778 1779 1780 1781 1782 1783 1784 1785

  int result_int;
  CHECK(copy_result->ToInt32(&result_int));
  CHECK_EQ(7, result_int);

  delete cache;
  source.Dispose();
}

1786
TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) {
1787
  if (FLAG_never_compact) return;
1788
  ManualGCScope manual_gc_scope;
1789 1790
  FLAG_always_opt = false;
  const char* filter_flag = "--turbo-filter=NOTHING";
1791
  FlagList::SetFlagsFromString(filter_flag, strlen(filter_flag));
1792 1793 1794 1795 1796
  FLAG_manual_evacuation_candidates_selection = true;

  LocalContext context;
  Isolate* isolate = CcTest::i_isolate();
  Heap* heap = isolate->heap();
1797 1798
  isolate->compilation_cache()
      ->DisableScriptAndEval();  // Disable same-isolate code cache.
1799 1800 1801 1802

  v8::HandleScope scope(CcTest::isolate());

  Vector<const uint8_t> source = ConstructSource(
1803 1804 1805
      StaticCharVector("var j=1; if (j == 0) {"),
      StaticCharVector("for (var i = 0; i < Object.prototype; i++);"),
      StaticCharVector("} j=7; var s = 'happy_hippo'; j"), 20000);
1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816
  Handle<String> source_str =
      isolate->factory()->NewStringFromOneByte(source).ToHandleChecked();

  // Create a string on an evacuation candidate in old space.
  Handle<String> moving_object;
  Page* ec_page;
  {
    AlwaysAllocateScope always_allocate(isolate);
    heap::SimulateFullSpace(heap->old_space());
    moving_object = isolate->factory()->InternalizeString(
        isolate->factory()->NewStringFromAsciiChecked("happy_hippo"));
1817
    ec_page = Page::FromHeapObject(*moving_object);
1818 1819
  }

1820
  Handle<JSObject> global(isolate->context().global_object(), isolate);
1821
  ScriptData* cache = nullptr;
1822

1823 1824 1825
  Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
      isolate, source_str, Handle<String>(), &cache,
      v8::ScriptCompiler::kNoCompileOptions);
1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839

  CHECK(heap->InSpace(orig->abstract_code(), LO_SPACE));

  // Pretend that incremental marking is on when deserialization begins.
  heap::ForceEvacuationCandidate(ec_page);
  heap::SimulateIncrementalMarking(heap, false);
  IncrementalMarking* marking = heap->incremental_marking();
  marking->StartBlackAllocationForTesting();
  CHECK(marking->IsCompacting());
  CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*moving_object));

  Handle<SharedFunctionInfo> copy;
  {
    DisallowCompilation no_compile_expected(isolate);
1840
    copy = CompileScript(isolate, source_str, Handle<String>(), cache,
1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854
                         v8::ScriptCompiler::kConsumeCodeCache);
  }
  CHECK_NE(*orig, *copy);

  // We should have missed a write barrier. Complete incremental marking
  // to flush out the bug.
  heap::SimulateIncrementalMarking(heap, true);
  CcTest::CollectAllGarbage();

  Handle<JSFunction> copy_fun =
      isolate->factory()->NewFunctionFromSharedFunctionInfo(
          copy, isolate->native_context());

  Handle<Object> copy_result =
1855
      Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1856 1857 1858 1859 1860 1861 1862 1863

  int result_int;
  CHECK(copy_result->ToInt32(&result_int));
  CHECK_EQ(7, result_int);

  delete cache;
  source.Dispose();
}
1864
TEST(CodeSerializerLargeStrings) {
1865 1866
  LocalContext context;
  Isolate* isolate = CcTest::i_isolate();
1867
  Factory* f = isolate->factory();
1868 1869
  isolate->compilation_cache()
      ->DisableScriptAndEval();  // Disable same-isolate code cache.
1870 1871 1872

  v8::HandleScope scope(CcTest::isolate());

1873
  Vector<const uint8_t> source_s = ConstructSource(
1874 1875
      StaticCharVector("var s = \""), StaticCharVector("abcdef"),
      StaticCharVector("\";"), 1000000);
1876
  Vector<const uint8_t> source_t = ConstructSource(
1877 1878
      StaticCharVector("var t = \""), StaticCharVector("uvwxyz"),
      StaticCharVector("\"; s + t"), 999999);
1879
  Handle<String> source_str =
1880 1881 1882
      f->NewConsString(f->NewStringFromOneByte(source_s).ToHandleChecked(),
                       f->NewStringFromOneByte(source_t).ToHandleChecked())
          .ToHandleChecked();
1883

1884
  Handle<JSObject> global(isolate->context().global_object(), isolate);
1885
  ScriptData* cache = nullptr;
1886

1887 1888 1889
  Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
      isolate, source_str, Handle<String>(), &cache,
      v8::ScriptCompiler::kNoCompileOptions);
1890 1891 1892 1893

  Handle<SharedFunctionInfo> copy;
  {
    DisallowCompilation no_compile_expected(isolate);
1894
    copy = CompileScript(isolate, source_str, Handle<String>(), cache,
1895
                         v8::ScriptCompiler::kConsumeCodeCache);
1896 1897 1898 1899 1900 1901 1902 1903
  }
  CHECK_NE(*orig, *copy);

  Handle<JSFunction> copy_fun =
      isolate->factory()->NewFunctionFromSharedFunctionInfo(
          copy, isolate->native_context());

  Handle<Object> copy_result =
1904
      Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1905

1906
  CHECK_EQ(6 * 1999999, Handle<String>::cast(copy_result)->length());
1907
  Handle<Object> property = JSReceiver::GetDataProperty(
1908 1909
      isolate->global_object(), f->NewStringFromAsciiChecked("s"));
  CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
1910 1911
  property = JSReceiver::GetDataProperty(isolate->global_object(),
                                         f->NewStringFromAsciiChecked("t"));
1912
  CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
1913
  // Make sure we do not serialize too much, e.g. include the source string.
1914
  CHECK_LT(cache->length(), 13000000);
1915 1916

  delete cache;
1917 1918
  source_s.Dispose();
  source_t.Dispose();
1919 1920
}

1921
TEST(CodeSerializerThreeBigStrings) {
1922 1923 1924
  LocalContext context;
  Isolate* isolate = CcTest::i_isolate();
  Factory* f = isolate->factory();
1925 1926
  isolate->compilation_cache()
      ->DisableScriptAndEval();  // Disable same-isolate code cache.
1927 1928 1929

  v8::HandleScope scope(CcTest::isolate());

1930 1931 1932 1933
  const int32_t length_of_a = kMaxRegularHeapObjectSize * 2;
  const int32_t length_of_b = kMaxRegularHeapObjectSize / 2;
  const int32_t length_of_c = kMaxRegularHeapObjectSize / 2;

1934
  Vector<const uint8_t> source_a =
1935
      ConstructSource(StaticCharVector("var a = \""), StaticCharVector("a"),
1936
                      StaticCharVector("\";"), length_of_a);
1937 1938 1939
  Handle<String> source_a_str =
      f->NewStringFromOneByte(source_a).ToHandleChecked();

1940
  Vector<const uint8_t> source_b =
1941
      ConstructSource(StaticCharVector("var b = \""), StaticCharVector("b"),
1942
                      StaticCharVector("\";"), length_of_b);
1943 1944 1945
  Handle<String> source_b_str =
      f->NewStringFromOneByte(source_b).ToHandleChecked();

1946
  Vector<const uint8_t> source_c =
1947
      ConstructSource(StaticCharVector("var c = \""), StaticCharVector("c"),
1948
                      StaticCharVector("\";"), length_of_c);
1949 1950 1951 1952 1953 1954 1955 1956
  Handle<String> source_c_str =
      f->NewStringFromOneByte(source_c).ToHandleChecked();

  Handle<String> source_str =
      f->NewConsString(
             f->NewConsString(source_a_str, source_b_str).ToHandleChecked(),
             source_c_str).ToHandleChecked();

1957
  Handle<JSObject> global(isolate->context().global_object(), isolate);
1958
  ScriptData* cache = nullptr;
1959

1960 1961 1962
  Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
      isolate, source_str, Handle<String>(), &cache,
      v8::ScriptCompiler::kNoCompileOptions);
1963 1964 1965 1966

  Handle<SharedFunctionInfo> copy;
  {
    DisallowCompilation no_compile_expected(isolate);
1967
    copy = CompileScript(isolate, source_str, Handle<String>(), cache,
1968
                         v8::ScriptCompiler::kConsumeCodeCache);
1969 1970 1971 1972 1973 1974 1975
  }
  CHECK_NE(*orig, *copy);

  Handle<JSFunction> copy_fun =
      isolate->factory()->NewFunctionFromSharedFunctionInfo(
          copy, isolate->native_context());

1976
  USE(Execution::Call(isolate, copy_fun, global, 0, nullptr));
1977

1978 1979
  v8::Maybe<int32_t> result =
      CompileRun("(a + b).length")
1980
          ->Int32Value(CcTest::isolate()->GetCurrentContext());
1981
  CHECK_EQ(length_of_a + length_of_b, result.FromJust());
1982
  result = CompileRun("(b + c).length")
1983
               ->Int32Value(CcTest::isolate()->GetCurrentContext());
1984
  CHECK_EQ(length_of_b + length_of_c, result.FromJust());
1985
  Heap* heap = isolate->heap();
1986 1987 1988 1989
  v8::Local<v8::String> result_str =
      CompileRun("a")
          ->ToString(CcTest::isolate()->GetCurrentContext())
          .ToLocalChecked();
1990
  CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), LO_SPACE));
1991 1992 1993
  result_str = CompileRun("b")
                   ->ToString(CcTest::isolate()->GetCurrentContext())
                   .ToLocalChecked();
1994
  CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), OLD_SPACE));
1995

1996 1997 1998
  result_str = CompileRun("c")
                   ->ToString(CcTest::isolate()->GetCurrentContext())
                   .ToLocalChecked();
1999
  CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), OLD_SPACE));
2000 2001 2002 2003

  delete cache;
  source_a.Dispose();
  source_b.Dispose();
2004
  source_c.Dispose();
2005 2006 2007
}


2008 2009
class SerializerOneByteResource
    : public v8::String::ExternalOneByteStringResource {
2010
 public:
2011
  SerializerOneByteResource(const char* data, size_t length)
2012
      : data_(data), length_(length), dispose_count_(0) {}
2013 2014 2015
  const char* data() const override { return data_; }
  size_t length() const override { return length_; }
  void Dispose() override { dispose_count_++; }
2016
  int dispose_count() { return dispose_count_; }
2017 2018 2019 2020

 private:
  const char* data_;
  size_t length_;
2021
  int dispose_count_;
2022 2023 2024
};


2025
class SerializerTwoByteResource : public v8::String::ExternalStringResource {
2026
 public:
2027
  SerializerTwoByteResource(const char* data, size_t length)
2028
      : data_(AsciiToTwoByteString(data)), length_(length), dispose_count_(0) {}
2029
  ~SerializerTwoByteResource() override { DeleteArray<const uint16_t>(data_); }
2030

2031 2032 2033
  const uint16_t* data() const override { return data_; }
  size_t length() const override { return length_; }
  void Dispose() override { dispose_count_++; }
2034
  int dispose_count() { return dispose_count_; }
2035 2036 2037 2038

 private:
  const uint16_t* data_;
  size_t length_;
2039
  int dispose_count_;
2040 2041
};

2042
TEST(CodeSerializerExternalString) {
2043 2044
  LocalContext context;
  Isolate* isolate = CcTest::i_isolate();
2045 2046
  isolate->compilation_cache()
      ->DisableScriptAndEval();  // Disable same-isolate code cache.
2047 2048 2049 2050

  v8::HandleScope scope(CcTest::isolate());

  // Obtain external internalized one-byte string.
2051
  SerializerOneByteResource one_byte_resource("one_byte", 8);
2052
  Handle<String> one_byte_string =
2053
      isolate->factory()->NewStringFromAsciiChecked("one_byte");
2054 2055 2056 2057 2058 2059
  one_byte_string = isolate->factory()->InternalizeString(one_byte_string);
  one_byte_string->MakeExternal(&one_byte_resource);
  CHECK(one_byte_string->IsExternalOneByteString());
  CHECK(one_byte_string->IsInternalizedString());

  // Obtain external internalized two-byte string.
2060
  SerializerTwoByteResource two_byte_resource("two_byte", 8);
2061
  Handle<String> two_byte_string =
2062
      isolate->factory()->NewStringFromAsciiChecked("two_byte");
2063 2064 2065 2066 2067 2068 2069
  two_byte_string = isolate->factory()->InternalizeString(two_byte_string);
  two_byte_string->MakeExternal(&two_byte_resource);
  CHECK(two_byte_string->IsExternalTwoByteString());
  CHECK(two_byte_string->IsInternalizedString());

  const char* source =
      "var o = {}               \n"
2070 2071 2072
      "o.one_byte = 7;          \n"
      "o.two_byte = 8;          \n"
      "o.one_byte + o.two_byte; \n";
2073 2074 2075 2076
  Handle<String> source_string = isolate->factory()
                                     ->NewStringFromUtf8(CStrVector(source))
                                     .ToHandleChecked();

2077
  Handle<JSObject> global(isolate->context().global_object(), isolate);
2078
  ScriptData* cache = nullptr;
2079

2080 2081 2082
  Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
      isolate, source_string, Handle<String>(), &cache,
      v8::ScriptCompiler::kNoCompileOptions);
2083 2084 2085 2086

  Handle<SharedFunctionInfo> copy;
  {
    DisallowCompilation no_compile_expected(isolate);
2087
    copy = CompileScript(isolate, source_string, Handle<String>(), cache,
2088
                         v8::ScriptCompiler::kConsumeCodeCache);
2089 2090 2091 2092 2093 2094 2095 2096
  }
  CHECK_NE(*orig, *copy);

  Handle<JSFunction> copy_fun =
      isolate->factory()->NewFunctionFromSharedFunctionInfo(
          copy, isolate->native_context());

  Handle<Object> copy_result =
2097
      Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
2098

2099
  CHECK_EQ(15.0, copy_result->Number());
2100

2101 2102
  // This avoids the GC from trying to free stack allocated resources.
  i::Handle<i::ExternalOneByteString>::cast(one_byte_string)
2103
      ->SetResource(isolate, nullptr);
2104
  i::Handle<i::ExternalTwoByteString>::cast(two_byte_string)
2105
      ->SetResource(isolate, nullptr);
2106 2107 2108
  delete cache;
}

2109
TEST(CodeSerializerLargeExternalString) {
2110 2111
  LocalContext context;
  Isolate* isolate = CcTest::i_isolate();
2112 2113
  isolate->compilation_cache()
      ->DisableScriptAndEval();  // Disable same-isolate code cache.
2114 2115 2116 2117 2118 2119 2120

  Factory* f = isolate->factory();

  v8::HandleScope scope(CcTest::isolate());

  // Create a huge external internalized string to use as variable name.
  Vector<const uint8_t> string =
2121 2122
      ConstructSource(StaticCharVector(""), StaticCharVector("abcdef"),
                      StaticCharVector(""), 999999);
2123
  Handle<String> name = f->NewStringFromOneByte(string).ToHandleChecked();
2124
  SerializerOneByteResource one_byte_resource(
2125
      reinterpret_cast<const char*>(string.begin()), string.length());
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139
  name = f->InternalizeString(name);
  name->MakeExternal(&one_byte_resource);
  CHECK(name->IsExternalOneByteString());
  CHECK(name->IsInternalizedString());
  CHECK(isolate->heap()->InSpace(*name, LO_SPACE));

  // Create the source, which is "var <literal> = 42; <literal>".
  Handle<String> source_str =
      f->NewConsString(
             f->NewConsString(f->NewStringFromAsciiChecked("var "), name)
                 .ToHandleChecked(),
             f->NewConsString(f->NewStringFromAsciiChecked(" = 42; "), name)
                 .ToHandleChecked()).ToHandleChecked();

2140
  Handle<JSObject> global(isolate->context().global_object(), isolate);
2141
  ScriptData* cache = nullptr;
2142

2143 2144 2145
  Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
      isolate, source_str, Handle<String>(), &cache,
      v8::ScriptCompiler::kNoCompileOptions);
2146 2147 2148 2149

  Handle<SharedFunctionInfo> copy;
  {
    DisallowCompilation no_compile_expected(isolate);
2150
    copy = CompileScript(isolate, source_str, Handle<String>(), cache,
2151
                         v8::ScriptCompiler::kConsumeCodeCache);
2152 2153 2154 2155
  }
  CHECK_NE(*orig, *copy);

  Handle<JSFunction> copy_fun =
2156
      f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
2157 2158

  Handle<Object> copy_result =
2159
      Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
2160

2161
  CHECK_EQ(42.0, copy_result->Number());
2162

2163
  // This avoids the GC from trying to free stack allocated resources.
2164 2165
  i::Handle<i::ExternalOneByteString>::cast(name)->SetResource(isolate,
                                                               nullptr);
2166 2167 2168 2169
  delete cache;
  string.Dispose();
}

2170
TEST(CodeSerializerExternalScriptName) {
2171 2172
  LocalContext context;
  Isolate* isolate = CcTest::i_isolate();
2173 2174
  isolate->compilation_cache()
      ->DisableScriptAndEval();  // Disable same-isolate code cache.
2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192

  Factory* f = isolate->factory();

  v8::HandleScope scope(CcTest::isolate());

  const char* source =
      "var a = [1, 2, 3, 4];"
      "a.reduce(function(x, y) { return x + y }, 0)";

  Handle<String> source_string =
      f->NewStringFromUtf8(CStrVector(source)).ToHandleChecked();

  const SerializerOneByteResource one_byte_resource("one_byte", 8);
  Handle<String> name =
      f->NewExternalStringFromOneByte(&one_byte_resource).ToHandleChecked();
  CHECK(name->IsExternalOneByteString());
  CHECK(!name->IsInternalizedString());

2193
  Handle<JSObject> global(isolate->context().global_object(), isolate);
2194
  ScriptData* cache = nullptr;
2195

2196
  Handle<SharedFunctionInfo> orig =
2197 2198
      CompileScriptAndProduceCache(isolate, source_string, name, &cache,
                                   v8::ScriptCompiler::kNoCompileOptions);
2199 2200 2201 2202

  Handle<SharedFunctionInfo> copy;
  {
    DisallowCompilation no_compile_expected(isolate);
2203
    copy = CompileScript(isolate, source_string, name, cache,
2204
                         v8::ScriptCompiler::kConsumeCodeCache);
2205 2206 2207 2208 2209 2210 2211
  }
  CHECK_NE(*orig, *copy);

  Handle<JSFunction> copy_fun =
      f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());

  Handle<Object> copy_result =
2212
      Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
2213

2214
  CHECK_EQ(10.0, copy_result->Number());
2215

2216
  // This avoids the GC from trying to free stack allocated resources.
2217 2218
  i::Handle<i::ExternalOneByteString>::cast(name)->SetResource(isolate,
                                                               nullptr);
2219 2220 2221 2222
  delete cache;
}


2223 2224 2225 2226 2227
static bool toplevel_test_code_event_found = false;


static void SerializerCodeEventListener(const v8::JitCodeEvent* event) {
  if (event->type == v8::JitCodeEvent::CODE_ADDED &&
2228 2229
      (memcmp(event->name.str, "Script:~ test", 13) == 0 ||
       memcmp(event->name.str, "Script: test", 12) == 0)) {
2230 2231 2232 2233
    toplevel_test_code_event_found = true;
  }
}

2234
v8::ScriptCompiler::CachedData* CompileRunAndProduceCache(
2235
    const char* source, CodeCacheType cacheType = CodeCacheType::kLazy) {
2236
  v8::ScriptCompiler::CachedData* cache;
2237 2238 2239
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate1 = v8::Isolate::New(create_params);
2240
  {
2241 2242 2243
    v8::Isolate::Scope iscope(isolate1);
    v8::HandleScope scope(isolate1);
    v8::Local<v8::Context> context = v8::Context::New(isolate1);
2244 2245 2246 2247 2248
    v8::Context::Scope context_scope(context);

    v8::Local<v8::String> source_str = v8_str(source);
    v8::ScriptOrigin origin(v8_str("test"));
    v8::ScriptCompiler::Source source(source_str, origin);
2249 2250 2251
    v8::ScriptCompiler::CompileOptions options;
    switch (cacheType) {
      case CodeCacheType::kEager:
2252
        options = v8::ScriptCompiler::kEagerCompile;
2253
        break;
2254
      case CodeCacheType::kLazy:
2255 2256 2257 2258 2259 2260
      case CodeCacheType::kAfterExecute:
        options = v8::ScriptCompiler::kNoCompileOptions;
        break;
      default:
        UNREACHABLE();
    }
2261
    v8::Local<v8::UnboundScript> script =
2262
        v8::ScriptCompiler::CompileUnboundScript(isolate1, &source, options)
2263
            .ToLocalChecked();
2264

2265
    if (cacheType != CodeCacheType::kAfterExecute) {
2266
      cache = ScriptCompiler::CreateCodeCache(script);
2267 2268
    }

2269 2270 2271 2272 2273 2274 2275
    v8::Local<v8::Value> result = script->BindToCurrentContext()
                                      ->Run(isolate1->GetCurrentContext())
                                      .ToLocalChecked();
    v8::Local<v8::String> result_string =
        result->ToString(isolate1->GetCurrentContext()).ToLocalChecked();
    CHECK(result_string->Equals(isolate1->GetCurrentContext(), v8_str("abcdef"))
              .FromJust());
2276 2277

    if (cacheType == CodeCacheType::kAfterExecute) {
2278
      cache = ScriptCompiler::CreateCodeCache(script);
2279 2280
    }
    CHECK(cache);
2281
  }
2282
  isolate1->Dispose();
2283 2284 2285
  return cache;
}

2286
TEST(CodeSerializerIsolates) {
2287
  const char* source = "function f() { return 'abc'; }; f() + 'def'";
2288
  v8::ScriptCompiler::CachedData* cache = CompileRunAndProduceCache(source);
2289

2290 2291 2292
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate2 = v8::Isolate::New(create_params);
2293 2294 2295
  isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
                                   SerializerCodeEventListener);
  toplevel_test_code_event_found = false;
2296
  {
2297 2298 2299
    v8::Isolate::Scope iscope(isolate2);
    v8::HandleScope scope(isolate2);
    v8::Local<v8::Context> context = v8::Context::New(isolate2);
2300 2301 2302 2303 2304 2305 2306
    v8::Context::Scope context_scope(context);

    v8::Local<v8::String> source_str = v8_str(source);
    v8::ScriptOrigin origin(v8_str("test"));
    v8::ScriptCompiler::Source source(source_str, origin, cache);
    v8::Local<v8::UnboundScript> script;
    {
2307
      DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
2308 2309 2310
      script = v8::ScriptCompiler::CompileUnboundScript(
                   isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
                   .ToLocalChecked();
2311
    }
2312
    CHECK(!cache->rejected);
2313 2314 2315 2316 2317 2318 2319
    v8::Local<v8::Value> result = script->BindToCurrentContext()
                                      ->Run(isolate2->GetCurrentContext())
                                      .ToLocalChecked();
    CHECK(result->ToString(isolate2->GetCurrentContext())
              .ToLocalChecked()
              ->Equals(isolate2->GetCurrentContext(), v8_str("abcdef"))
              .FromJust());
2320
  }
2321
  CHECK(toplevel_test_code_event_found);
2322
  isolate2->Dispose();
2323
}
2324

2325 2326 2327 2328 2329 2330 2331 2332
TEST(CodeSerializerIsolatesEager) {
  const char* source =
      "function f() {"
      "  return function g() {"
      "    return 'abc';"
      "  }"
      "}"
      "f()() + 'def'";
2333
  v8::ScriptCompiler::CachedData* cache =
2334
      CompileRunAndProduceCache(source, CodeCacheType::kEager);
2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369

  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate2 = v8::Isolate::New(create_params);
  isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
                                   SerializerCodeEventListener);
  toplevel_test_code_event_found = false;
  {
    v8::Isolate::Scope iscope(isolate2);
    v8::HandleScope scope(isolate2);
    v8::Local<v8::Context> context = v8::Context::New(isolate2);
    v8::Context::Scope context_scope(context);

    v8::Local<v8::String> source_str = v8_str(source);
    v8::ScriptOrigin origin(v8_str("test"));
    v8::ScriptCompiler::Source source(source_str, origin, cache);
    v8::Local<v8::UnboundScript> script;
    {
      DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
      script = v8::ScriptCompiler::CompileUnboundScript(
                   isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
                   .ToLocalChecked();
    }
    CHECK(!cache->rejected);
    v8::Local<v8::Value> result = script->BindToCurrentContext()
                                      ->Run(isolate2->GetCurrentContext())
                                      .ToLocalChecked();
    CHECK(result->ToString(isolate2->GetCurrentContext())
              .ToLocalChecked()
              ->Equals(isolate2->GetCurrentContext(), v8_str("abcdef"))
              .FromJust());
  }
  CHECK(toplevel_test_code_event_found);
  isolate2->Dispose();
}
2370

2371 2372 2373 2374 2375 2376 2377
TEST(CodeSerializerAfterExecute) {
  // We test that no compilations happen when running this code. Forcing
  // to always optimize breaks this test.
  bool prev_always_opt_value = FLAG_always_opt;
  FLAG_always_opt = false;
  const char* source = "function f() { return 'abc'; }; f() + 'def'";
  v8::ScriptCompiler::CachedData* cache =
2378
      CompileRunAndProduceCache(source, CodeCacheType::kAfterExecute);
2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404

  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate2 = v8::Isolate::New(create_params);

  {
    v8::Isolate::Scope iscope(isolate2);
    v8::HandleScope scope(isolate2);
    v8::Local<v8::Context> context = v8::Context::New(isolate2);
    v8::Context::Scope context_scope(context);

    v8::Local<v8::String> source_str = v8_str(source);
    v8::ScriptOrigin origin(v8_str("test"));
    v8::ScriptCompiler::Source source(source_str, origin, cache);
    v8::Local<v8::UnboundScript> script;
    {
      DisallowCompilation no_compile_expected(
          reinterpret_cast<Isolate*>(isolate2));
      script = v8::ScriptCompiler::CompileUnboundScript(
                   isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
                   .ToLocalChecked();
    }
    CHECK(!cache->rejected);

    Handle<SharedFunctionInfo> sfi = v8::Utils::OpenHandle(*script);
    CHECK(sfi->HasBytecodeArray());
2405
    BytecodeArray bytecode = sfi->GetBytecodeArray();
2406
    CHECK_EQ(bytecode.osr_loop_nesting_level(), 0);
2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426

    {
      DisallowCompilation no_compile_expected(
          reinterpret_cast<Isolate*>(isolate2));
      v8::Local<v8::Value> result = script->BindToCurrentContext()
                                        ->Run(isolate2->GetCurrentContext())
                                        .ToLocalChecked();
      v8::Local<v8::String> result_string =
          result->ToString(isolate2->GetCurrentContext()).ToLocalChecked();
      CHECK(
          result_string->Equals(isolate2->GetCurrentContext(), v8_str("abcdef"))
              .FromJust());
    }
  }
  isolate2->Dispose();

  // Restore the flags.
  FLAG_always_opt = prev_always_opt_value;
}

2427
TEST(CodeSerializerFlagChange) {
2428
  const char* source = "function f() { return 'abc'; }; f() + 'def'";
2429
  v8::ScriptCompiler::CachedData* cache = CompileRunAndProduceCache(source);
2430

2431 2432 2433
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate2 = v8::Isolate::New(create_params);
2434

2435
  FLAG_allow_natives_syntax = true;  // Flag change should trigger cache reject.
2436
  FlagList::EnforceFlagImplications();
2437
  {
2438 2439 2440
    v8::Isolate::Scope iscope(isolate2);
    v8::HandleScope scope(isolate2);
    v8::Local<v8::Context> context = v8::Context::New(isolate2);
2441 2442 2443 2444
    v8::Context::Scope context_scope(context);

    v8::Local<v8::String> source_str = v8_str(source);
    v8::ScriptOrigin origin(v8_str("test"));
2445
    v8::ScriptCompiler::Source source(source_str, origin, cache);
2446 2447 2448
    v8::ScriptCompiler::CompileUnboundScript(
        isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
        .ToLocalChecked();
2449
    CHECK(cache->rejected);
2450
  }
2451 2452 2453
  isolate2->Dispose();
}

2454
TEST(CodeSerializerBitFlip) {
2455
  const char* source = "function f() { return 'abc'; }; f() + 'def'";
2456
  v8::ScriptCompiler::CachedData* cache = CompileRunAndProduceCache(source);
2457 2458 2459

  // Random bit flip.
  const_cast<uint8_t*>(cache->data)[337] ^= 0x40;
2460

2461 2462 2463
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate2 = v8::Isolate::New(create_params);
2464 2465 2466 2467 2468 2469 2470 2471 2472
  {
    v8::Isolate::Scope iscope(isolate2);
    v8::HandleScope scope(isolate2);
    v8::Local<v8::Context> context = v8::Context::New(isolate2);
    v8::Context::Scope context_scope(context);

    v8::Local<v8::String> source_str = v8_str(source);
    v8::ScriptOrigin origin(v8_str("test"));
    v8::ScriptCompiler::Source source(source_str, origin, cache);
2473 2474 2475
    v8::ScriptCompiler::CompileUnboundScript(
        isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
        .ToLocalChecked();
2476 2477 2478 2479 2480
    CHECK(cache->rejected);
  }
  isolate2->Dispose();
}

2481
TEST(CodeSerializerWithHarmonyScoping) {
2482 2483 2484 2485 2486 2487
  const char* source1 = "'use strict'; let x = 'X'";
  const char* source2 = "'use strict'; let y = 'Y'";
  const char* source3 = "'use strict'; x + y";

  v8::ScriptCompiler::CachedData* cache;

2488 2489 2490
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate1 = v8::Isolate::New(create_params);
2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502
  {
    v8::Isolate::Scope iscope(isolate1);
    v8::HandleScope scope(isolate1);
    v8::Local<v8::Context> context = v8::Context::New(isolate1);
    v8::Context::Scope context_scope(context);

    CompileRun(source1);
    CompileRun(source2);

    v8::Local<v8::String> source_str = v8_str(source3);
    v8::ScriptOrigin origin(v8_str("test"));
    v8::ScriptCompiler::Source source(source_str, origin);
2503 2504
    v8::Local<v8::UnboundScript> script =
        v8::ScriptCompiler::CompileUnboundScript(
2505
            isolate1, &source, v8::ScriptCompiler::kNoCompileOptions)
2506
            .ToLocalChecked();
2507
    cache = v8::ScriptCompiler::CreateCodeCache(script);
2508
    CHECK(cache);
2509

2510 2511 2512 2513 2514 2515 2516
    v8::Local<v8::Value> result = script->BindToCurrentContext()
                                      ->Run(isolate1->GetCurrentContext())
                                      .ToLocalChecked();
    v8::Local<v8::String> result_str =
        result->ToString(isolate1->GetCurrentContext()).ToLocalChecked();
    CHECK(result_str->Equals(isolate1->GetCurrentContext(), v8_str("XY"))
              .FromJust());
2517 2518 2519
  }
  isolate1->Dispose();

2520
  v8::Isolate* isolate2 = v8::Isolate::New(create_params);
2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536
  {
    v8::Isolate::Scope iscope(isolate2);
    v8::HandleScope scope(isolate2);
    v8::Local<v8::Context> context = v8::Context::New(isolate2);
    v8::Context::Scope context_scope(context);

    // Reverse order of prior running scripts.
    CompileRun(source2);
    CompileRun(source1);

    v8::Local<v8::String> source_str = v8_str(source3);
    v8::ScriptOrigin origin(v8_str("test"));
    v8::ScriptCompiler::Source source(source_str, origin, cache);
    v8::Local<v8::UnboundScript> script;
    {
      DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
2537 2538 2539
      script = v8::ScriptCompiler::CompileUnboundScript(
                   isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
                   .ToLocalChecked();
2540
    }
2541 2542 2543 2544 2545 2546 2547
    v8::Local<v8::Value> result = script->BindToCurrentContext()
                                      ->Run(isolate2->GetCurrentContext())
                                      .ToLocalChecked();
    v8::Local<v8::String> result_str =
        result->ToString(isolate2->GetCurrentContext()).ToLocalChecked();
    CHECK(result_str->Equals(isolate2->GetCurrentContext(), v8_str("XY"))
              .FromJust());
2548 2549 2550
  }
  isolate2->Dispose();
}
2551

2552
TEST(Regress503552) {
2553
  if (!FLAG_incremental_marking) return;
2554 2555 2556 2557 2558 2559 2560 2561
  // Test that the code serializer can deal with weak cells that form a linked
  // list during incremental marking.
  CcTest::InitializeVM();
  Isolate* isolate = CcTest::i_isolate();

  HandleScope scope(isolate);
  Handle<String> source = isolate->factory()->NewStringFromAsciiChecked(
      "function f() {} function g() {}");
2562
  ScriptData* script_data = nullptr;
2563 2564 2565
  Handle<SharedFunctionInfo> shared = CompileScriptAndProduceCache(
      isolate, source, Handle<String>(), &script_data,
      v8::ScriptCompiler::kNoCompileOptions);
2566 2567
  delete script_data;

2568
  heap::SimulateIncrementalMarking(isolate->heap());
2569

2570
  v8::ScriptCompiler::CachedData* cache_data =
2571
      CodeSerializer::Serialize(shared);
2572
  delete cache_data;
2573 2574
}

2575
UNINITIALIZED_TEST(SnapshotCreatorMultipleContexts) {
2576
  DisableAlwaysOpt();
2577
  DisableEmbeddedBlobRefcounting();
2578 2579 2580 2581 2582 2583 2584 2585 2586
  v8::StartupData blob;
  {
    v8::SnapshotCreator creator;
    v8::Isolate* isolate = creator.GetIsolate();
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      CompileRun("var f = function() { return 1; }");
2587
      creator.SetDefaultContext(context);
2588 2589 2590 2591 2592 2593
    }
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      CompileRun("var f = function() { return 2; }");
2594
      CHECK_EQ(0u, creator.AddContext(context));
2595 2596 2597 2598
    }
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
2599
      CHECK_EQ(1u, creator.AddContext(context));
2600 2601 2602 2603 2604
    }
    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
  }

2605
  ReadOnlyHeap::ClearSharedHeapForTest();
2606 2607 2608
  v8::Isolate::CreateParams params;
  params.snapshot_blob = &blob;
  params.array_buffer_allocator = CcTest::array_buffer_allocator();
2609
  // Test-appropriate equivalent of v8::Isolate::New.
2610
  v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2611 2612 2613 2614
  {
    v8::Isolate::Scope isolate_scope(isolate);
    {
      v8::HandleScope handle_scope(isolate);
2615
      v8::Local<v8::Context> context = v8::Context::New(isolate);
2616 2617 2618 2619 2620 2621
      v8::Context::Scope context_scope(context);
      ExpectInt32("f()", 1);
    }
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context =
2622
          v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
2623 2624 2625 2626 2627 2628
      v8::Context::Scope context_scope(context);
      ExpectInt32("f()", 2);
    }
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context =
2629
          v8::Context::FromSnapshot(isolate, 1).ToLocalChecked();
2630 2631 2632 2633 2634 2635 2636
      v8::Context::Scope context_scope(context);
      ExpectUndefined("this.f");
    }
  }

  isolate->Dispose();
  delete[] blob.data;
2637
  FreeCurrentEmbeddedBlob();
2638 2639
}

2640 2641
static int serialized_static_field = 314;

2642 2643
static void SerializedCallback(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
2644 2645 2646 2647 2648 2649 2650
  if (args.Data()->IsExternal()) {
    CHECK_EQ(args.Data().As<v8::External>()->Value(),
             static_cast<void*>(&serialized_static_field));
    int* value =
        reinterpret_cast<int*>(args.Data().As<v8::External>()->Value());
    (*value)++;
  }
2651 2652 2653
  args.GetReturnValue().Set(v8_num(42));
}

2654
static void SerializedCallbackReplacement(
2655 2656 2657 2658
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  args.GetReturnValue().Set(v8_num(1337));
}

2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673
static void NamedPropertyGetterForSerialization(
    v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
  if (name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("x"))
          .FromJust()) {
    info.GetReturnValue().Set(v8_num(2016));
  }
}

static void AccessorForSerialization(
    v8::Local<v8::String> property,
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  info.GetReturnValue().Set(v8_num(2017));
}


2674 2675 2676
static SerializerOneByteResource serializable_one_byte_resource("one_byte", 8);
static SerializerTwoByteResource serializable_two_byte_resource("two_byte", 8);

2677
intptr_t original_external_references[] = {
2678
    reinterpret_cast<intptr_t>(SerializedCallback),
2679 2680 2681
    reinterpret_cast<intptr_t>(&serialized_static_field),
    reinterpret_cast<intptr_t>(&NamedPropertyGetterForSerialization),
    reinterpret_cast<intptr_t>(&AccessorForSerialization),
2682
    reinterpret_cast<intptr_t>(&serialized_static_field),  // duplicate entry
2683 2684
    reinterpret_cast<intptr_t>(&serializable_one_byte_resource),
    reinterpret_cast<intptr_t>(&serializable_two_byte_resource),
2685
    0};
2686 2687

intptr_t replaced_external_references[] = {
2688
    reinterpret_cast<intptr_t>(SerializedCallbackReplacement),
2689 2690 2691
    reinterpret_cast<intptr_t>(&serialized_static_field),
    reinterpret_cast<intptr_t>(&NamedPropertyGetterForSerialization),
    reinterpret_cast<intptr_t>(&AccessorForSerialization),
2692
    reinterpret_cast<intptr_t>(&serialized_static_field),
2693 2694
    reinterpret_cast<intptr_t>(&serializable_one_byte_resource),
    reinterpret_cast<intptr_t>(&serializable_two_byte_resource),
2695
    0};
2696

2697 2698 2699
intptr_t short_external_references[] = {
    reinterpret_cast<intptr_t>(SerializedCallbackReplacement), 0};

2700
UNINITIALIZED_TEST(SnapshotCreatorExternalReferences) {
2701
  DisableAlwaysOpt();
2702
  DisableEmbeddedBlobRefcounting();
2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715
  v8::StartupData blob;
  {
    v8::SnapshotCreator creator(original_external_references);
    v8::Isolate* isolate = creator.GetIsolate();
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      v8::Local<v8::FunctionTemplate> callback =
          v8::FunctionTemplate::New(isolate, SerializedCallback);
      v8::Local<v8::Value> function =
          callback->GetFunction(context).ToLocalChecked();
      CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729

      CHECK(context->Global()
                ->Set(context, v8_str("one_byte"),
                      v8::String::NewExternalOneByte(
                          isolate, &serializable_one_byte_resource)
                          .ToLocalChecked())
                .FromJust());
      CHECK(context->Global()
                ->Set(context, v8_str("two_byte"),
                      v8::String::NewExternalTwoByte(
                          isolate, &serializable_two_byte_resource)
                          .ToLocalChecked())
                .FromJust());

2730
      ExpectInt32("f()", 42);
2731 2732
      ExpectString("one_byte", "one_byte");
      ExpectString("two_byte", "two_byte");
2733
      creator.SetDefaultContext(context);
2734 2735 2736 2737 2738
    }
    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
  }

2739 2740 2741
  CHECK_EQ(1, serializable_one_byte_resource.dispose_count());
  CHECK_EQ(1, serializable_two_byte_resource.dispose_count());

2742 2743
  // Deserialize with the original external reference.
  {
2744
    ReadOnlyHeap::ClearSharedHeapForTest();
2745 2746 2747 2748
    v8::Isolate::CreateParams params;
    params.snapshot_blob = &blob;
    params.array_buffer_allocator = CcTest::array_buffer_allocator();
    params.external_references = original_external_references;
2749
    // Test-appropriate equivalent of v8::Isolate::New.
2750
    v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2751 2752 2753
    {
      v8::Isolate::Scope isolate_scope(isolate);
      v8::HandleScope handle_scope(isolate);
2754
      v8::Local<v8::Context> context = v8::Context::New(isolate);
2755 2756
      v8::Context::Scope context_scope(context);
      ExpectInt32("f()", 42);
2757 2758 2759 2760
      ExpectString("one_byte", "one_byte");
      ExpectString("two_byte", "two_byte");
      CHECK(CompileRun("one_byte").As<v8::String>()->IsExternalOneByte());
      CHECK(CompileRun("two_byte").As<v8::String>()->IsExternal());
2761 2762 2763 2764
    }
    isolate->Dispose();
  }

2765 2766 2767
  CHECK_EQ(2, serializable_one_byte_resource.dispose_count());
  CHECK_EQ(2, serializable_two_byte_resource.dispose_count());

2768
  // Deserialize with some other external reference.
2769
  {
2770
    ReadOnlyHeap::ClearSharedHeapForTest();
2771 2772 2773 2774
    v8::Isolate::CreateParams params;
    params.snapshot_blob = &blob;
    params.array_buffer_allocator = CcTest::array_buffer_allocator();
    params.external_references = replaced_external_references;
2775
    // Test-appropriate equivalent of v8::Isolate::New.
2776
    v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2777 2778 2779
    {
      v8::Isolate::Scope isolate_scope(isolate);
      v8::HandleScope handle_scope(isolate);
2780
      v8::Local<v8::Context> context = v8::Context::New(isolate);
2781
      v8::Context::Scope context_scope(context);
2782 2783 2784 2785
      ExpectInt32("f()", 1337);
    }
    isolate->Dispose();
  }
2786 2787 2788 2789

  CHECK_EQ(3, serializable_one_byte_resource.dispose_count());
  CHECK_EQ(3, serializable_two_byte_resource.dispose_count());

2790
  delete[] blob.data;
2791
  FreeCurrentEmbeddedBlob();
2792 2793
}

2794
UNINITIALIZED_TEST(SnapshotCreatorShortExternalReferences) {
2795
  DisableAlwaysOpt();
2796
  DisableEmbeddedBlobRefcounting();
2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818
  v8::StartupData blob;
  {
    v8::SnapshotCreator creator(original_external_references);
    v8::Isolate* isolate = creator.GetIsolate();
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      v8::Local<v8::FunctionTemplate> callback =
          v8::FunctionTemplate::New(isolate, SerializedCallback);
      v8::Local<v8::Value> function =
          callback->GetFunction(context).ToLocalChecked();
      CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
      ExpectInt32("f()", 42);
      creator.SetDefaultContext(context);
    }
    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
  }

  // Deserialize with an incomplete list of external references.
  {
2819
    ReadOnlyHeap::ClearSharedHeapForTest();
2820 2821 2822 2823 2824
    v8::Isolate::CreateParams params;
    params.snapshot_blob = &blob;
    params.array_buffer_allocator = CcTest::array_buffer_allocator();
    params.external_references = short_external_references;
    // Test-appropriate equivalent of v8::Isolate::New.
2825
    v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2826 2827 2828 2829 2830
    {
      v8::Isolate::Scope isolate_scope(isolate);
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
2831 2832 2833 2834 2835
      ExpectInt32("f()", 1337);
    }
    isolate->Dispose();
  }
  delete[] blob.data;
2836
  FreeCurrentEmbeddedBlob();
2837 2838
}

2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872
v8::StartupData CreateSnapshotWithDefaultAndCustom() {
  v8::SnapshotCreator creator(original_external_references);
  v8::Isolate* isolate = creator.GetIsolate();
  {
    v8::HandleScope handle_scope(isolate);
    {
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      CompileRun("function f() { return 41; }");
      creator.SetDefaultContext(context);
      ExpectInt32("f()", 41);
    }
    {
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      v8::Local<v8::FunctionTemplate> function_template =
          v8::FunctionTemplate::New(isolate, SerializedCallback);
      v8::Local<v8::Value> function =
          function_template->GetFunction(context).ToLocalChecked();
      CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
      v8::Local<v8::ObjectTemplate> object_template =
          v8::ObjectTemplate::New(isolate);
      object_template->SetAccessor(v8_str("x"), AccessorForSerialization);
      v8::Local<v8::Object> object =
          object_template->NewInstance(context).ToLocalChecked();
      CHECK(context->Global()->Set(context, v8_str("o"), object).FromJust());
      ExpectInt32("f()", 42);
      ExpectInt32("o.x", 2017);
      creator.AddContext(context);
    }
  }
  return creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
}

2873
UNINITIALIZED_TEST(SnapshotCreatorNoExternalReferencesDefault) {
2874
  DisableAlwaysOpt();
2875
  DisableEmbeddedBlobRefcounting();
2876 2877 2878 2879
  v8::StartupData blob = CreateSnapshotWithDefaultAndCustom();

  // Deserialize with an incomplete list of external references.
  {
2880
    ReadOnlyHeap::ClearSharedHeapForTest();
2881 2882 2883 2884 2885
    v8::Isolate::CreateParams params;
    params.snapshot_blob = &blob;
    params.array_buffer_allocator = CcTest::array_buffer_allocator();
    params.external_references = nullptr;
    // Test-appropriate equivalent of v8::Isolate::New.
2886
    v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2887 2888 2889 2890 2891 2892 2893 2894 2895 2896
    {
      v8::Isolate::Scope isolate_scope(isolate);
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      ExpectInt32("f()", 41);
    }
    isolate->Dispose();
  }
  delete[] blob.data;
2897
  FreeCurrentEmbeddedBlob();
2898 2899
}

2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922
v8::StartupData CreateCustomSnapshotWithPreparseDataAndNoOuterScope() {
  v8::SnapshotCreator creator;
  v8::Isolate* isolate = creator.GetIsolate();
  {
    v8::HandleScope handle_scope(isolate);
    {
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      CompileRun(
          "var foo = {\n"
          "  // This function is not top-level, but also has no outer scope.\n"
          "  bar: function(){\n"
          "    // Add an inner function so that the outer one has preparse\n"
          "    // scope data.\n"
          "    return function(){}\n"
          "  }\n"
          "};\n");
      creator.SetDefaultContext(context);
    }
  }
  return creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
}

2923
UNINITIALIZED_TEST(SnapshotCreatorPreparseDataAndNoOuterScope) {
2924
  DisableAlwaysOpt();
2925
  DisableEmbeddedBlobRefcounting();
2926 2927 2928 2929
  v8::StartupData blob = CreateCustomSnapshotWithPreparseDataAndNoOuterScope();

  // Deserialize with an incomplete list of external references.
  {
2930
    ReadOnlyHeap::ClearSharedHeapForTest();
2931 2932 2933 2934
    v8::Isolate::CreateParams params;
    params.snapshot_blob = &blob;
    params.array_buffer_allocator = CcTest::array_buffer_allocator();
    // Test-appropriate equivalent of v8::Isolate::New.
2935
    v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2936 2937 2938 2939 2940 2941 2942 2943 2944
    {
      v8::Isolate::Scope isolate_scope(isolate);
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
    }
    isolate->Dispose();
  }
  delete[] blob.data;
2945
  FreeCurrentEmbeddedBlob();
2946 2947
}

2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965
v8::StartupData CreateCustomSnapshotArrayJoinWithKeep() {
  v8::SnapshotCreator creator;
  v8::Isolate* isolate = creator.GetIsolate();
  {
    v8::HandleScope handle_scope(isolate);
    {
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      CompileRun(
          "[].join('');\n"
          "function g() { return String([1,2,3]); }\n");
      ExpectString("g()", "1,2,3");
      creator.SetDefaultContext(context);
    }
  }
  return creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kKeep);
}

2966
UNINITIALIZED_TEST(SnapshotCreatorArrayJoinWithKeep) {
2967
  DisableAlwaysOpt();
2968
  DisableEmbeddedBlobRefcounting();
2969
  v8::StartupData blob = CreateCustomSnapshotArrayJoinWithKeep();
2970
  ReadOnlyHeap::ClearSharedHeapForTest();
2971 2972 2973 2974 2975 2976 2977

  // Deserialize with an incomplete list of external references.
  {
    v8::Isolate::CreateParams params;
    params.snapshot_blob = &blob;
    params.array_buffer_allocator = CcTest::array_buffer_allocator();
    // Test-appropriate equivalent of v8::Isolate::New.
2978
    v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2979 2980 2981 2982 2983 2984 2985 2986 2987 2988
    {
      v8::Isolate::Scope isolate_scope(isolate);
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      ExpectString("g()", "1,2,3");
    }
    isolate->Dispose();
  }
  delete[] blob.data;
2989
  FreeCurrentEmbeddedBlob();
2990 2991
}

2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038
v8::StartupData CreateCustomSnapshotWithDuplicateFunctions() {
  v8::SnapshotCreator creator;
  v8::Isolate* isolate = creator.GetIsolate();
  {
    v8::HandleScope handle_scope(isolate);
    {
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      CompileRun(
          "function f() { return (() => 'a'); }\n"
          "let g1 = f();\n"
          "let g2 = f();\n");
      ExpectString("g1()", "a");
      ExpectString("g2()", "a");
      creator.SetDefaultContext(context);
    }
  }
  return creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kKeep);
}

UNINITIALIZED_TEST(SnapshotCreatorDuplicateFunctions) {
  DisableAlwaysOpt();
  DisableEmbeddedBlobRefcounting();
  v8::StartupData blob = CreateCustomSnapshotWithDuplicateFunctions();
  ReadOnlyHeap::ClearSharedHeapForTest();

  // Deserialize with an incomplete list of external references.
  {
    v8::Isolate::CreateParams params;
    params.snapshot_blob = &blob;
    params.array_buffer_allocator = CcTest::array_buffer_allocator();
    // Test-appropriate equivalent of v8::Isolate::New.
    v8::Isolate* isolate = TestSerializer::NewIsolate(params);
    {
      v8::Isolate::Scope isolate_scope(isolate);
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      ExpectString("g1()", "a");
      ExpectString("g2()", "a");
    }
    isolate->Dispose();
  }
  delete[] blob.data;
  FreeCurrentEmbeddedBlob();
}

3039 3040 3041 3042 3043 3044
TEST(SnapshotCreatorNoExternalReferencesCustomFail1) {
  DisableAlwaysOpt();
  v8::StartupData blob = CreateSnapshotWithDefaultAndCustom();

  // Deserialize with an incomplete list of external references.
  {
3045
    ReadOnlyHeap::ClearSharedHeapForTest();
3046 3047 3048 3049 3050
    v8::Isolate::CreateParams params;
    params.snapshot_blob = &blob;
    params.array_buffer_allocator = CcTest::array_buffer_allocator();
    params.external_references = nullptr;
    // Test-appropriate equivalent of v8::Isolate::New.
3051
    v8::Isolate* isolate = TestSerializer::NewIsolate(params);
3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070
    {
      v8::Isolate::Scope isolate_scope(isolate);
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context =
          v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
      v8::Context::Scope context_scope(context);
      ExpectInt32("f()", 42);
    }
    isolate->Dispose();
  }
  delete[] blob.data;
}

TEST(SnapshotCreatorNoExternalReferencesCustomFail2) {
  DisableAlwaysOpt();
  v8::StartupData blob = CreateSnapshotWithDefaultAndCustom();

  // Deserialize with an incomplete list of external references.
  {
3071
    ReadOnlyHeap::ClearSharedHeapForTest();
3072 3073 3074 3075 3076
    v8::Isolate::CreateParams params;
    params.snapshot_blob = &blob;
    params.array_buffer_allocator = CcTest::array_buffer_allocator();
    params.external_references = nullptr;
    // Test-appropriate equivalent of v8::Isolate::New.
3077
    v8::Isolate* isolate = TestSerializer::NewIsolate(params);
3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090
    {
      v8::Isolate::Scope isolate_scope(isolate);
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context =
          v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
      v8::Context::Scope context_scope(context);
      ExpectInt32("o.x", 2017);
    }
    isolate->Dispose();
  }
  delete[] blob.data;
}

3091
UNINITIALIZED_TEST(SnapshotCreatorUnknownExternalReferences) {
3092
  DisableAlwaysOpt();
3093
  DisableEmbeddedBlobRefcounting();
3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107
  v8::SnapshotCreator creator;
  v8::Isolate* isolate = creator.GetIsolate();
  {
    v8::HandleScope handle_scope(isolate);
    v8::Local<v8::Context> context = v8::Context::New(isolate);
    v8::Context::Scope context_scope(context);

    v8::Local<v8::FunctionTemplate> callback =
        v8::FunctionTemplate::New(isolate, SerializedCallback);
    v8::Local<v8::Value> function =
        callback->GetFunction(context).ToLocalChecked();
    CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
    ExpectInt32("f()", 42);

3108
    creator.SetDefaultContext(context);
3109 3110 3111 3112 3113
  }
  v8::StartupData blob =
      creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);

  delete[] blob.data;
3114
  FreeCurrentEmbeddedBlob();
3115 3116
}

3117
UNINITIALIZED_TEST(SnapshotCreatorTemplates) {
3118
  DisableAlwaysOpt();
3119
  DisableEmbeddedBlobRefcounting();
3120
  v8::StartupData blob;
3121

3122
  {
3123
    InternalFieldData* a1 = new InternalFieldData{11};
3124 3125
    InternalFieldData* b1 = new InternalFieldData{20};
    InternalFieldData* c1 = new InternalFieldData{30};
3126

3127 3128 3129 3130 3131 3132 3133
    v8::SnapshotCreator creator(original_external_references);
    v8::Isolate* isolate = creator.GetIsolate();
    {
      v8::HandleScope handle_scope(isolate);
      v8::ExtensionConfiguration* no_extension = nullptr;
      v8::Local<v8::ObjectTemplate> global_template =
          v8::ObjectTemplate::New(isolate);
3134 3135
      v8::Local<v8::External> external =
          v8::External::New(isolate, &serialized_static_field);
3136
      v8::Local<v8::FunctionTemplate> callback =
3137
          v8::FunctionTemplate::New(isolate, SerializedCallback, external);
3138
      global_template->Set(v8_str("f"), callback);
3139 3140
      v8::Local<v8::Context> context =
          v8::Context::New(isolate, no_extension, global_template);
3141 3142
      creator.SetDefaultContext(context);
      context = v8::Context::New(isolate, no_extension, global_template);
3143 3144
      v8::Local<v8::ObjectTemplate> object_template =
          v8::ObjectTemplate::New(isolate);
3145
      object_template->SetInternalFieldCount(3);
3146

3147 3148
      v8::Context::Scope context_scope(context);
      ExpectInt32("f()", 42);
3149
      CHECK_EQ(315, serialized_static_field);
3150 3151 3152 3153 3154 3155 3156

      v8::Local<v8::Object> a =
          object_template->NewInstance(context).ToLocalChecked();
      v8::Local<v8::Object> b =
          object_template->NewInstance(context).ToLocalChecked();
      v8::Local<v8::Object> c =
          object_template->NewInstance(context).ToLocalChecked();
3157 3158 3159 3160
      v8::Local<v8::External> null_external =
          v8::External::New(isolate, nullptr);
      v8::Local<v8::External> field_external =
          v8::External::New(isolate, &serialized_static_field);
3161

3162
      a->SetInternalField(0, b);
3163 3164
      b->SetInternalField(0, c);

3165
      a->SetAlignedPointerInInternalField(1, a1);
3166 3167 3168 3169 3170 3171
      b->SetAlignedPointerInInternalField(1, b1);
      c->SetAlignedPointerInInternalField(1, c1);

      a->SetInternalField(2, null_external);
      b->SetInternalField(2, field_external);
      c->SetInternalField(2, v8_num(35));
3172 3173
      CHECK(context->Global()->Set(context, v8_str("a"), a).FromJust());

3174 3175 3176
      CHECK_EQ(0u,
               creator.AddContext(context, v8::SerializeInternalFieldsCallback(
                                               SerializeInternalFields,
3177
                                               reinterpret_cast<void*>(2000))));
3178 3179
      CHECK_EQ(0u, creator.AddTemplate(callback));
      CHECK_EQ(1u, creator.AddTemplate(global_template));
3180
    }
3181 3182
    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3183 3184

    delete a1;
3185 3186
    delete b1;
    delete c1;
3187 3188 3189
  }

  {
3190
    ReadOnlyHeap::ClearSharedHeapForTest();
3191 3192 3193 3194
    v8::Isolate::CreateParams params;
    params.snapshot_blob = &blob;
    params.array_buffer_allocator = CcTest::array_buffer_allocator();
    params.external_references = original_external_references;
3195
    // Test-appropriate equivalent of v8::Isolate::New.
3196
    v8::Isolate* isolate = TestSerializer::NewIsolate(params);
3197 3198 3199 3200 3201
    {
      v8::Isolate::Scope isolate_scope(isolate);
      {
        // Create a new context without a new object template.
        v8::HandleScope handle_scope(isolate);
3202
        v8::Local<v8::Context> context =
3203 3204 3205 3206
            v8::Context::FromSnapshot(
                isolate, 0,
                v8::DeserializeInternalFieldsCallback(
                    DeserializeInternalFields, reinterpret_cast<void*>(2017)))
3207
                .ToLocalChecked();
3208 3209
        v8::Context::Scope context_scope(context);
        ExpectInt32("f()", 42);
3210
        CHECK_EQ(316, serialized_static_field);
3211 3212 3213

        // Retrieve the snapshotted object template.
        v8::Local<v8::ObjectTemplate> obj_template =
3214
            v8::ObjectTemplate::FromSnapshot(isolate, 1).ToLocalChecked();
3215 3216 3217 3218 3219
        CHECK(!obj_template.IsEmpty());
        v8::Local<v8::Object> object =
            obj_template->NewInstance(context).ToLocalChecked();
        CHECK(context->Global()->Set(context, v8_str("o"), object).FromJust());
        ExpectInt32("o.f()", 42);
3220
        CHECK_EQ(317, serialized_static_field);
3221 3222 3223 3224 3225
        // Check that it instantiates to the same prototype.
        ExpectTrue("o.f.prototype === f.prototype");

        // Retrieve the snapshotted function template.
        v8::Local<v8::FunctionTemplate> fun_template =
3226
            v8::FunctionTemplate::FromSnapshot(isolate, 0).ToLocalChecked();
3227 3228 3229 3230 3231 3232 3233
        CHECK(!fun_template.IsEmpty());
        v8::Local<v8::Function> fun =
            fun_template->GetFunction(context).ToLocalChecked();
        CHECK(context->Global()->Set(context, v8_str("g"), fun).FromJust());
        ExpectInt32("g()", 42);
        // Check that it instantiates to the same prototype.
        ExpectTrue("g.prototype === f.prototype");
3234

3235
        // Retrieve embedder fields.
3236 3237 3238 3239 3240 3241 3242
        v8::Local<v8::Object> a = context->Global()
                                      ->Get(context, v8_str("a"))
                                      .ToLocalChecked()
                                      ->ToObject(context)
                                      .ToLocalChecked();
        v8::Local<v8::Object> b =
            a->GetInternalField(0)->ToObject(context).ToLocalChecked();
3243 3244 3245
        v8::Local<v8::Object> c =
            b->GetInternalField(0)->ToObject(context).ToLocalChecked();

3246 3247
        InternalFieldData* a1 = reinterpret_cast<InternalFieldData*>(
            a->GetAlignedPointerFromInternalField(1));
3248 3249
        v8::Local<v8::Value> a2 = a->GetInternalField(2);

3250 3251
        InternalFieldData* b1 = reinterpret_cast<InternalFieldData*>(
            b->GetAlignedPointerFromInternalField(1));
3252 3253
        v8::Local<v8::Value> b2 = b->GetInternalField(2);

3254 3255 3256
        v8::Local<v8::Value> c0 = c->GetInternalField(0);
        InternalFieldData* c1 = reinterpret_cast<InternalFieldData*>(
            c->GetAlignedPointerFromInternalField(1));
3257
        v8::Local<v8::Value> c2 = c->GetInternalField(2);
3258

3259 3260
        CHECK(c0->IsUndefined());

3261
        CHECK_EQ(11u, a1->data);
3262 3263 3264 3265 3266 3267
        CHECK_EQ(20u, b1->data);
        CHECK_EQ(30u, c1->data);

        CHECK(a2->IsExternal());
        CHECK_NULL(v8::Local<v8::External>::Cast(a2)->Value());
        CHECK(b2->IsExternal());
3268
        CHECK_EQ(static_cast<void*>(&serialized_static_field),
3269 3270
                 v8::Local<v8::External>::Cast(b2)->Value());
        CHECK(c2->IsInt32() && c2->Int32Value(context).FromJust() == 35);
3271

3272 3273 3274
        // Accessing out of bound returns empty MaybeHandle.
        CHECK(v8::ObjectTemplate::FromSnapshot(isolate, 2).IsEmpty());
        CHECK(v8::FunctionTemplate::FromSnapshot(isolate, 2).IsEmpty());
3275
        CHECK(v8::Context::FromSnapshot(isolate, 1).IsEmpty());
3276

3277 3278
        for (auto data : deserialized_data) delete data;
        deserialized_data.clear();
3279 3280 3281 3282 3283
      }
    }
    isolate->Dispose();
  }
  delete[] blob.data;
3284
  FreeCurrentEmbeddedBlob();
3285 3286
}

3287
UNINITIALIZED_TEST(SnapshotCreatorAddData) {
3288
  DisableAlwaysOpt();
3289
  DisableEmbeddedBlobRefcounting();
3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319
  v8::StartupData blob;

  {
    v8::SnapshotCreator creator;
    v8::Isolate* isolate = creator.GetIsolate();
    v8::Eternal<v8::Value> eternal_number;
    v8::Persistent<v8::Value> persistent_number_1;
    v8::Persistent<v8::Value> persistent_number_2;
    v8::Persistent<v8::Context> persistent_context;
    {
      v8::HandleScope handle_scope(isolate);

      eternal_number.Set(isolate, v8_num(2017));
      persistent_number_1.Reset(isolate, v8_num(2018));
      persistent_number_2.Reset(isolate, v8_num(2019));

      v8::Local<v8::Context> context = v8::Context::New(isolate);
      CHECK_EQ(0u, creator.AddData(context, persistent_number_2.Get(isolate)));
      creator.SetDefaultContext(context);
      context = v8::Context::New(isolate);
      persistent_context.Reset(isolate, context);

      v8::Context::Scope context_scope(context);

      v8::Local<v8::Object> object = CompileRun("({ p: 12 })").As<v8::Object>();

      v8::Local<v8::ObjectTemplate> object_template =
          v8::ObjectTemplate::New(isolate);
      object_template->SetInternalFieldCount(3);

3320 3321 3322 3323 3324 3325 3326 3327 3328 3329
      v8::Local<v8::Private> private_symbol =
          v8::Private::ForApi(isolate, v8_str("private_symbol"));

      v8::Local<v8::Signature> signature =
        v8::Signature::New(isolate, v8::FunctionTemplate::New(isolate));

      v8::Local<v8::AccessorSignature> accessor_signature =
           v8::AccessorSignature::New(isolate,
                                      v8::FunctionTemplate::New(isolate));

3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340
      CHECK_EQ(0u, creator.AddData(context, object));
      CHECK_EQ(1u, creator.AddData(context, v8_str("context-dependent")));
      CHECK_EQ(2u, creator.AddData(context, persistent_number_1.Get(isolate)));
      CHECK_EQ(3u, creator.AddData(context, object_template));
      CHECK_EQ(4u, creator.AddData(context, persistent_context.Get(isolate)));
      creator.AddContext(context);

      CHECK_EQ(0u, creator.AddData(v8_str("context-independent")));
      CHECK_EQ(1u, creator.AddData(eternal_number.Get(isolate)));
      CHECK_EQ(2u, creator.AddData(object_template));
      CHECK_EQ(3u, creator.AddData(v8::FunctionTemplate::New(isolate)));
3341 3342 3343
      CHECK_EQ(4u, creator.AddData(private_symbol));
      CHECK_EQ(5u, creator.AddData(signature));
      CHECK_EQ(6u, creator.AddData(accessor_signature));
3344 3345 3346 3347 3348 3349 3350
    }

    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
  }

  {
3351
    ReadOnlyHeap::ClearSharedHeapForTest();
3352 3353 3354 3355
    v8::Isolate::CreateParams params;
    params.snapshot_blob = &blob;
    params.array_buffer_allocator = CcTest::array_buffer_allocator();
    // Test-appropriate equivalent of v8::Isolate::New.
3356
    v8::Isolate* isolate = TestSerializer::NewIsolate(params);
3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414
    {
      v8::Isolate::Scope isolate_scope(isolate);
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context =
          v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();

      // Check serialized data on the context.
      v8::Local<v8::Object> object =
          context->GetDataFromSnapshotOnce<v8::Object>(0).ToLocalChecked();
      CHECK(context->GetDataFromSnapshotOnce<v8::Object>(0).IsEmpty());
      CHECK_EQ(12, object->Get(context, v8_str("p"))
                       .ToLocalChecked()
                       ->Int32Value(context)
                       .FromJust());

      v8::Local<v8::String> string =
          context->GetDataFromSnapshotOnce<v8::String>(1).ToLocalChecked();
      CHECK(context->GetDataFromSnapshotOnce<v8::String>(1).IsEmpty());
      CHECK(string->Equals(context, v8_str("context-dependent")).FromJust());

      v8::Local<v8::Number> number =
          context->GetDataFromSnapshotOnce<v8::Number>(2).ToLocalChecked();
      CHECK(context->GetDataFromSnapshotOnce<v8::Number>(2).IsEmpty());
      CHECK_EQ(2018, number->Int32Value(context).FromJust());

      v8::Local<v8::ObjectTemplate> templ =
          context->GetDataFromSnapshotOnce<v8::ObjectTemplate>(3)
              .ToLocalChecked();
      CHECK(context->GetDataFromSnapshotOnce<v8::ObjectTemplate>(3).IsEmpty());
      CHECK_EQ(3, templ->InternalFieldCount());

      v8::Local<v8::Context> serialized_context =
          context->GetDataFromSnapshotOnce<v8::Context>(4).ToLocalChecked();
      CHECK(context->GetDataFromSnapshotOnce<v8::Context>(4).IsEmpty());
      CHECK_EQ(*v8::Utils::OpenHandle(*serialized_context),
               *v8::Utils::OpenHandle(*context));

      CHECK(context->GetDataFromSnapshotOnce<v8::Value>(5).IsEmpty());

      // Check serialized data on the isolate.
      string = isolate->GetDataFromSnapshotOnce<v8::String>(0).ToLocalChecked();
      CHECK(context->GetDataFromSnapshotOnce<v8::String>(0).IsEmpty());
      CHECK(string->Equals(context, v8_str("context-independent")).FromJust());

      number = isolate->GetDataFromSnapshotOnce<v8::Number>(1).ToLocalChecked();
      CHECK(isolate->GetDataFromSnapshotOnce<v8::Number>(1).IsEmpty());
      CHECK_EQ(2017, number->Int32Value(context).FromJust());

      templ = isolate->GetDataFromSnapshotOnce<v8::ObjectTemplate>(2)
                  .ToLocalChecked();
      CHECK(isolate->GetDataFromSnapshotOnce<v8::ObjectTemplate>(2).IsEmpty());
      CHECK_EQ(3, templ->InternalFieldCount());

      isolate->GetDataFromSnapshotOnce<v8::FunctionTemplate>(3)
          .ToLocalChecked();
      CHECK(
          isolate->GetDataFromSnapshotOnce<v8::FunctionTemplate>(3).IsEmpty());

3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427
      isolate->GetDataFromSnapshotOnce<v8::Private>(4).ToLocalChecked();
      CHECK(
          isolate->GetDataFromSnapshotOnce<v8::Private>(4).IsEmpty());

      isolate->GetDataFromSnapshotOnce<v8::Signature>(5).ToLocalChecked();
      CHECK(isolate->GetDataFromSnapshotOnce<v8::Signature>(5).IsEmpty());

      isolate->GetDataFromSnapshotOnce<v8::AccessorSignature>(6)
          .ToLocalChecked();
      CHECK(
          isolate->GetDataFromSnapshotOnce<v8::AccessorSignature>(6).IsEmpty());

      CHECK(isolate->GetDataFromSnapshotOnce<v8::Value>(7).IsEmpty());
3428 3429 3430 3431
    }
    isolate->Dispose();
  }
  {
3432
    ReadOnlyHeap::ClearSharedHeapForTest();
3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458
    SnapshotCreator creator(nullptr, &blob);
    v8::Isolate* isolate = creator.GetIsolate();
    {
      // Adding data to a snapshot replaces the list of existing data.
      v8::HandleScope hscope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      creator.SetDefaultContext(context);
      context = v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
      v8::Local<v8::String> string =
          context->GetDataFromSnapshotOnce<v8::String>(1).ToLocalChecked();
      CHECK(context->GetDataFromSnapshotOnce<v8::String>(1).IsEmpty());
      CHECK(string->Equals(context, v8_str("context-dependent")).FromJust());
      v8::Local<v8::Number> number =
          isolate->GetDataFromSnapshotOnce<v8::Number>(1).ToLocalChecked();
      CHECK(isolate->GetDataFromSnapshotOnce<v8::Number>(1).IsEmpty());
      CHECK_EQ(2017, number->Int32Value(context).FromJust());

      CHECK_EQ(0u, creator.AddData(context, v8_num(2016)));
      CHECK_EQ(0u, creator.AddContext(context));
      CHECK_EQ(0u, creator.AddData(v8_str("stuff")));
    }
    delete[] blob.data;
    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
  }
  {
3459
    ReadOnlyHeap::ClearSharedHeapForTest();
3460 3461 3462 3463
    v8::Isolate::CreateParams params;
    params.snapshot_blob = &blob;
    params.array_buffer_allocator = CcTest::array_buffer_allocator();
    // Test-appropriate equivalent of v8::Isolate::New.
3464
    v8::Isolate* isolate = TestSerializer::NewIsolate(params);
3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488
    {
      v8::Isolate::Scope isolate_scope(isolate);
      v8::HandleScope handle_scope(isolate);

      // Context where we did not re-add data no longer has data.
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      CHECK(context->GetDataFromSnapshotOnce<v8::Object>(0).IsEmpty());

      // Context where we re-added data has completely new ones.
      context = v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
      v8::Local<v8::Value> value =
          context->GetDataFromSnapshotOnce<v8::Value>(0).ToLocalChecked();
      CHECK_EQ(2016, value->Int32Value(context).FromJust());
      CHECK(context->GetDataFromSnapshotOnce<v8::Value>(1).IsEmpty());

      // Ditto for the isolate.
      v8::Local<v8::String> string =
          isolate->GetDataFromSnapshotOnce<v8::String>(0).ToLocalChecked();
      CHECK(string->Equals(context, v8_str("stuff")).FromJust());
      CHECK(context->GetDataFromSnapshotOnce<v8::String>(1).IsEmpty());
    }
    isolate->Dispose();
  }
  delete[] blob.data;
3489
  FreeCurrentEmbeddedBlob();
3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516
}

TEST(SnapshotCreatorUnknownHandles) {
  DisableAlwaysOpt();
  v8::StartupData blob;

  {
    v8::SnapshotCreator creator;
    v8::Isolate* isolate = creator.GetIsolate();
    v8::Eternal<v8::Value> eternal_number;
    v8::Persistent<v8::Value> persistent_number;
    {
      v8::HandleScope handle_scope(isolate);

      eternal_number.Set(isolate, v8_num(2017));
      persistent_number.Reset(isolate, v8_num(2018));

      v8::Local<v8::Context> context = v8::Context::New(isolate);
      creator.SetDefaultContext(context);
    }

    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
  }
  delete[] blob.data;
}

3517
UNINITIALIZED_TEST(SnapshotCreatorIncludeGlobalProxy) {
3518
  DisableAlwaysOpt();
3519
  DisableEmbeddedBlobRefcounting();
3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538
  v8::StartupData blob;

  {
    v8::SnapshotCreator creator(original_external_references);
    v8::Isolate* isolate = creator.GetIsolate();
    {
      // Set default context. This context implicitly does *not* serialize
      // the global proxy, and upon deserialization one has to be created
      // in the bootstrapper from the global object template.
      // Side effects from extensions are persisted though.
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::ObjectTemplate> global_template =
          v8::ObjectTemplate::New(isolate);
      v8::Local<v8::FunctionTemplate> callback =
          v8::FunctionTemplate::New(isolate, SerializedCallback);
      global_template->Set(v8_str("f"), callback);
      global_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
          NamedPropertyGetterForSerialization));
      v8::Local<v8::Context> context =
3539
          v8::Context::New(isolate, nullptr, global_template);
3540
      v8::Context::Scope context_scope(context);
3541 3542 3543 3544
      CompileRun(
          "function h() { return 13; };"
          "function i() { return 14; };"
          "var o = { p: 7 };");
3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560
      ExpectInt32("f()", 42);
      ExpectInt32("h()", 13);
      ExpectInt32("o.p", 7);
      ExpectInt32("x", 2016);
      creator.SetDefaultContext(context);
    }
    {
      // Add additional context. This context implicitly *does* serialize
      // the global proxy, and upon deserialization one has to be created
      // in the bootstrapper from the global object template.
      // Side effects from extensions are persisted.
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::ObjectTemplate> global_template =
          v8::ObjectTemplate::New(isolate);
      v8::Local<v8::FunctionTemplate> callback =
          v8::FunctionTemplate::New(isolate, SerializedCallback);
3561
      global_template->SetInternalFieldCount(3);
3562 3563 3564 3565
      global_template->Set(v8_str("f"), callback);
      global_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
          NamedPropertyGetterForSerialization));
      global_template->SetAccessor(v8_str("y"), AccessorForSerialization);
3566 3567 3568 3569 3570 3571
      v8::Local<v8::Private> priv =
          v8::Private::ForApi(isolate, v8_str("cached"));
      global_template->SetAccessorProperty(
          v8_str("cached"),
          v8::FunctionTemplate::NewWithCache(isolate, SerializedCallback, priv,
                                             v8::Local<v8::Value>()));
3572
      v8::Local<v8::Context> context =
3573
          v8::Context::New(isolate, nullptr, global_template);
3574
      v8::Context::Scope context_scope(context);
3575 3576 3577 3578 3579 3580 3581 3582 3583 3584

      CHECK(context->Global()
                ->SetPrivate(context, priv, v8_str("cached string"))
                .FromJust());
      v8::Local<v8::Private> hidden =
          v8::Private::ForApi(isolate, v8_str("hidden"));
      CHECK(context->Global()
                ->SetPrivate(context, hidden, v8_str("hidden string"))
                .FromJust());

3585 3586 3587
      ExpectInt32("f()", 42);
      ExpectInt32("x", 2016);
      ExpectInt32("y", 2017);
3588 3589 3590 3591 3592 3593
      CHECK(v8_str("hidden string")
                ->Equals(context, context->Global()
                                      ->GetPrivate(context, hidden)
                                      .ToLocalChecked())
                .FromJust());

3594 3595 3596 3597
      CHECK_EQ(0u,
               creator.AddContext(context, v8::SerializeInternalFieldsCallback(
                                               SerializeInternalFields,
                                               reinterpret_cast<void*>(2016))));
3598
    }
3599 3600
    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3601 3602 3603
  }

  {
3604
    ReadOnlyHeap::ClearSharedHeapForTest();
3605 3606 3607 3608
    v8::Isolate::CreateParams params;
    params.snapshot_blob = &blob;
    params.array_buffer_allocator = CcTest::array_buffer_allocator();
    params.external_references = original_external_references;
3609
    // Test-appropriate equivalent of v8::Isolate::New.
3610
    v8::Isolate* isolate = TestSerializer::NewIsolate(params);
3611 3612
    {
      v8::Isolate::Scope isolate_scope(isolate);
3613 3614
      // We can introduce new extensions, which could override functions already
      // in the snapshot.
3615
      auto extension =
3616 3617 3618 3619 3620 3621 3622
          std::make_unique<v8::Extension>("new extension",
                                          "function i() { return 24; }"
                                          "function j() { return 25; }"
                                          "let a = 26;"
                                          "try {"
                                          "  if (o.p == 7) o.p++;"
                                          "} catch {}");
3623
      extension->set_auto_enable(true);
3624
      v8::RegisterExtension(std::move(extension));
3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636
      {
        // Create a new context from default context snapshot. This will
        // create a new global object from a new global object template
        // without the interceptor.
        v8::HandleScope handle_scope(isolate);
        v8::Local<v8::Context> context = v8::Context::New(isolate);
        v8::Context::Scope context_scope(context);
        ExpectInt32("f()", 42);
        ExpectInt32("h()", 13);
        ExpectInt32("i()", 24);
        ExpectInt32("j()", 25);
        ExpectInt32("o.p", 8);
3637
        ExpectInt32("a", 26);
3638 3639 3640 3641 3642 3643 3644 3645 3646
        v8::TryCatch try_catch(isolate);
        CHECK(CompileRun("x").IsEmpty());
        CHECK(try_catch.HasCaught());
      }
      {
        // Create a new context from first additional context snapshot. This
        // will use the global object from the snapshot, including interceptor.
        v8::HandleScope handle_scope(isolate);
        v8::Local<v8::Context> context =
3647 3648 3649 3650
            v8::Context::FromSnapshot(
                isolate, 0,
                v8::DeserializeInternalFieldsCallback(
                    DeserializeInternalFields, reinterpret_cast<void*>(2017)))
3651
                .ToLocalChecked();
3652

3653 3654 3655 3656 3657 3658
        {
          v8::Context::Scope context_scope(context);
          ExpectInt32("f()", 42);
          ExpectInt32("i()", 24);
          ExpectInt32("j()", 25);
          ExpectInt32("x", 2016);
3659 3660 3661 3662 3663 3664 3665 3666
          v8::Local<v8::Private> hidden =
              v8::Private::ForApi(isolate, v8_str("hidden"));
          CHECK(v8_str("hidden string")
                    ->Equals(context, context->Global()
                                          ->GetPrivate(context, hidden)
                                          .ToLocalChecked())
                    .FromJust());
          ExpectString("cached", "cached string");
3667 3668 3669
        }

        v8::Local<v8::Object> global = context->Global();
3670
        CHECK_EQ(3, global->InternalFieldCount());
3671 3672 3673 3674 3675
        context->DetachGlobal();

        // New context, but reuse global proxy.
        v8::ExtensionConfiguration* no_extensions = nullptr;
        v8::Local<v8::Context> context2 =
3676 3677 3678 3679 3680
            v8::Context::FromSnapshot(
                isolate, 0,
                v8::DeserializeInternalFieldsCallback(
                    DeserializeInternalFields, reinterpret_cast<void*>(2017)),
                no_extensions, global)
3681 3682 3683 3684 3685 3686 3687
                .ToLocalChecked();
        {
          v8::Context::Scope context_scope(context2);
          ExpectInt32("f()", 42);
          ExpectInt32("i()", 24);
          ExpectInt32("j()", 25);
          ExpectInt32("x", 2016);
3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702
          v8::Local<v8::Private> hidden =
              v8::Private::ForApi(isolate, v8_str("hidden"));
          CHECK(v8_str("hidden string")
                    ->Equals(context2, context2->Global()
                                           ->GetPrivate(context2, hidden)
                                           .ToLocalChecked())
                    .FromJust());

          // Set cached accessor property again.
          v8::Local<v8::Private> priv =
              v8::Private::ForApi(isolate, v8_str("cached"));
          CHECK(context2->Global()
                    ->SetPrivate(context2, priv, v8_str("cached string 1"))
                    .FromJust());
          ExpectString("cached", "cached string 1");
3703 3704 3705
        }

        CHECK(context2->Global()->Equals(context2, global).FromJust());
3706 3707 3708 3709 3710
      }
    }
    isolate->Dispose();
  }
  delete[] blob.data;
3711
  FreeCurrentEmbeddedBlob();
3712 3713
}

3714
UNINITIALIZED_TEST(ReinitializeHashSeedNotRehashable) {
3715 3716 3717 3718
  DisableAlwaysOpt();
  i::FLAG_rehash_snapshot = true;
  i::FLAG_hash_seed = 42;
  i::FLAG_allow_natives_syntax = true;
3719
  DisableEmbeddedBlobRefcounting();
3720 3721 3722 3723 3724 3725 3726 3727
  v8::StartupData blob;
  {
    v8::SnapshotCreator creator;
    v8::Isolate* isolate = creator.GetIsolate();
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
3728
      // Create an object with an ordered hash table.
3729
      CompileRun(
3730 3731 3732 3733
          "var m = new Map();"
          "m.set('a', 1);"
          "m.set('b', 2);");
      ExpectInt32("m.get('b')", 2);
3734 3735 3736 3737
      creator.SetDefaultContext(context);
    }
    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3738
    CHECK(!blob.CanBeRehashed());
3739 3740
  }

3741
  ReadOnlyHeap::ClearSharedHeapForTest();
3742 3743 3744 3745 3746 3747 3748
  i::FLAG_hash_seed = 1337;
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  create_params.snapshot_blob = &blob;
  v8::Isolate* isolate = v8::Isolate::New(create_params);
  {
    // Check that no rehashing has been performed.
Yang Guo's avatar
Yang Guo committed
3749
    CHECK_EQ(static_cast<uint64_t>(42),
3750
             HashSeed(reinterpret_cast<i::Isolate*>(isolate)));
3751 3752 3753 3754 3755
    v8::Isolate::Scope isolate_scope(isolate);
    v8::HandleScope handle_scope(isolate);
    v8::Local<v8::Context> context = v8::Context::New(isolate);
    CHECK(!context.IsEmpty());
    v8::Context::Scope context_scope(context);
3756 3757 3758 3759
    ExpectInt32("m.get('b')", 2);
  }
  isolate->Dispose();
  delete[] blob.data;
3760
  FreeCurrentEmbeddedBlob();
3761 3762 3763 3764 3765 3766 3767
}

UNINITIALIZED_TEST(ReinitializeHashSeedRehashable) {
  DisableAlwaysOpt();
  i::FLAG_rehash_snapshot = true;
  i::FLAG_hash_seed = 42;
  i::FLAG_allow_natives_syntax = true;
3768
  DisableEmbeddedBlobRefcounting();
3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789
  v8::StartupData blob;
  {
    v8::SnapshotCreator creator;
    v8::Isolate* isolate = creator.GetIsolate();
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      // Create dictionary mode object.
      CompileRun(
          "var a = new Array(10000);"
          "%NormalizeElements(a);"
          "a[133] = 1;"
          "a[177] = 2;"
          "a[971] = 3;"
          "a[7997] = 4;"
          "a[2111] = 5;"
          "var o = {};"
          "%OptimizeObjectForAddingMultipleProperties(o, 3);"
          "o.a = 1;"
          "o.b = 2;"
Yang Guo's avatar
Yang Guo committed
3790 3791 3792
          "o.c = 3;"
          "var p = { foo: 1 };"  // Test rehashing of transition arrays.
          "p = JSON.parse('{\"foo\": {\"x\": 1}}');");
3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804
      i::Handle<i::Object> i_a = v8::Utils::OpenHandle(*CompileRun("a"));
      i::Handle<i::Object> i_o = v8::Utils::OpenHandle(*CompileRun("o"));
      CHECK(i_a->IsJSArray());
      CHECK(i_a->IsJSObject());
      CHECK(!i::Handle<i::JSArray>::cast(i_a)->HasFastElements());
      CHECK(!i::Handle<i::JSObject>::cast(i_o)->HasFastProperties());
      ExpectInt32("a[2111]", 5);
      ExpectInt32("o.c", 3);
      creator.SetDefaultContext(context);
    }
    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3805
    CHECK(blob.CanBeRehashed());
3806 3807
  }

3808
  ReadOnlyHeap::ClearSharedHeapForTest();
3809 3810 3811 3812 3813 3814 3815
  i::FLAG_hash_seed = 1337;
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  create_params.snapshot_blob = &blob;
  v8::Isolate* isolate = v8::Isolate::New(create_params);
  {
    // Check that rehashing has been performed.
Yang Guo's avatar
Yang Guo committed
3816
    CHECK_EQ(static_cast<uint64_t>(1337),
3817
             HashSeed(reinterpret_cast<i::Isolate*>(isolate)));
3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830
    v8::Isolate::Scope isolate_scope(isolate);
    v8::HandleScope handle_scope(isolate);
    v8::Local<v8::Context> context = v8::Context::New(isolate);
    CHECK(!context.IsEmpty());
    v8::Context::Scope context_scope(context);
    i::Handle<i::Object> i_a = v8::Utils::OpenHandle(*CompileRun("a"));
    i::Handle<i::Object> i_o = v8::Utils::OpenHandle(*CompileRun("o"));
    CHECK(i_a->IsJSArray());
    CHECK(i_a->IsJSObject());
    CHECK(!i::Handle<i::JSArray>::cast(i_a)->HasFastElements());
    CHECK(!i::Handle<i::JSObject>::cast(i_o)->HasFastProperties());
    ExpectInt32("a[2111]", 5);
    ExpectInt32("o.c", 3);
3831 3832 3833
  }
  isolate->Dispose();
  delete[] blob.data;
3834
  FreeCurrentEmbeddedBlob();
3835 3836
}

3837
void CheckSFIsAreWeak(WeakFixedArray sfis, Isolate* isolate) {
3838
  CHECK_GT(sfis.length(), 0);
3839
  int no_of_weak = 0;
3840 3841
  for (int i = 0; i < sfis.length(); ++i) {
    MaybeObject maybe_object = sfis.Get(i);
3842
    HeapObject heap_object;
3843 3844
    CHECK(maybe_object->IsWeakOrCleared() ||
          (maybe_object->GetHeapObjectIfStrong(&heap_object) &&
3845
           heap_object.IsUndefined(isolate)));
3846
    if (maybe_object->IsWeak()) {
3847 3848 3849 3850 3851 3852
      ++no_of_weak;
    }
  }
  CHECK_GT(no_of_weak, 0);
}

3853
UNINITIALIZED_TEST(WeakArraySerializationInSnapshot) {
3854 3855 3856
  const char* code = "var my_func = function() { }";

  DisableAlwaysOpt();
3857
  DisableEmbeddedBlobRefcounting();
3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876
  i::FLAG_allow_natives_syntax = true;
  v8::StartupData blob;
  {
    v8::SnapshotCreator creator;
    v8::Isolate* isolate = creator.GetIsolate();
    {
      v8::HandleScope handle_scope(isolate);
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);

      CompileRun(code);
      creator.SetDefaultContext(
          context, v8::SerializeInternalFieldsCallback(
                       SerializeInternalFields, reinterpret_cast<void*>(2016)));
    }
    blob =
        creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
  }

3877
  ReadOnlyHeap::ClearSharedHeapForTest();
3878 3879 3880
  v8::Isolate::CreateParams create_params;
  create_params.snapshot_blob = &blob;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
3881
  v8::Isolate* isolate = TestSerializer::NewIsolate(create_params);
3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897
  {
    v8::Isolate::Scope i_scope(isolate);
    v8::HandleScope h_scope(isolate);
    v8::Local<v8::Context> context = v8::Context::New(
        isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
        v8::MaybeLocal<v8::Value>(),
        v8::DeserializeInternalFieldsCallback(DeserializeInternalFields,
                                              reinterpret_cast<void*>(2017)));
    v8::Context::Scope c_scope(context);

    v8::Local<v8::Value> x = CompileRun("my_func");
    CHECK(x->IsFunction());
    Handle<JSFunction> function =
        Handle<JSFunction>::cast(v8::Utils::OpenHandle(*x));

    // Verify that the pointers in shared_function_infos are weak.
3898
    WeakFixedArray sfis =
3899
        Script::cast(function->shared().script()).shared_function_infos();
3900
    CheckSFIsAreWeak(sfis, reinterpret_cast<i::Isolate*>(isolate));
3901 3902 3903
  }
  isolate->Dispose();
  delete[] blob.data;
3904
  FreeCurrentEmbeddedBlob();
3905 3906 3907 3908 3909
}

TEST(WeakArraySerializationInCodeCache) {
  LocalContext context;
  Isolate* isolate = CcTest::i_isolate();
3910
  isolate->compilation_cache()->DisableScriptAndEval();
3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925

  v8::HandleScope scope(CcTest::isolate());

  const char* source = "function foo() { }";

  Handle<String> src = isolate->factory()
                           ->NewStringFromUtf8(CStrVector(source))
                           .ToHandleChecked();
  ScriptData* cache = nullptr;

  CompileScriptAndProduceCache(isolate, src, src, &cache,
                               v8::ScriptCompiler::kNoCompileOptions);

  DisallowCompilation no_compile_expected(isolate);
  Handle<SharedFunctionInfo> copy = CompileScript(
3926
      isolate, src, src, cache, v8::ScriptCompiler::kConsumeCodeCache);
3927 3928

  // Verify that the pointers in shared_function_infos are weak.
3929
  WeakFixedArray sfis = Script::cast(copy->script()).shared_function_infos();
3930 3931 3932 3933 3934
  CheckSFIsAreWeak(sfis, isolate);

  delete cache;
}

3935 3936 3937 3938
TEST(CachedCompileFunctionInContext) {
  DisableAlwaysOpt();
  LocalContext env;
  Isolate* isolate = CcTest::i_isolate();
3939 3940
  isolate->compilation_cache()
      ->DisableScriptAndEval();  // Disable same-isolate code cache.
3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953

  v8::HandleScope scope(CcTest::isolate());

  v8::Local<v8::String> source = v8_str("return x*x;");
  v8::Local<v8::String> arg_str = v8_str("x");
  ScriptCompiler::CachedData* cache;
  {
    v8::ScriptCompiler::Source script_source(source);
    v8::Local<v8::Function> fun =
        v8::ScriptCompiler::CompileFunctionInContext(
            env.local(), &script_source, 1, &arg_str, 0, nullptr,
            v8::ScriptCompiler::kEagerCompile)
            .ToLocalChecked();
3954
    cache = v8::ScriptCompiler::CreateCodeCacheForFunction(fun);
3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972
  }

  {
    DisallowCompilation no_compile_expected(isolate);
    v8::ScriptCompiler::Source script_source(source, cache);
    v8::Local<v8::Function> fun =
        v8::ScriptCompiler::CompileFunctionInContext(
            env.local(), &script_source, 1, &arg_str, 0, nullptr,
            v8::ScriptCompiler::kConsumeCodeCache)
            .ToLocalChecked();
    v8::Local<v8::Value> arg = v8_num(3);
    v8::Local<v8::Value> result =
        fun->Call(env.local(), v8::Undefined(CcTest::isolate()), 1, &arg)
            .ToLocalChecked();
    CHECK_EQ(9, result->Int32Value(env.local()).FromJust());
  }
}

3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994
UNINITIALIZED_TEST(SnapshotCreatorAnonClassWithKeep) {
  DisableAlwaysOpt();
  v8::SnapshotCreator creator;
  v8::Isolate* isolate = creator.GetIsolate();
  {
    v8::HandleScope handle_scope(isolate);
    {
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      CompileRun(
          "function Foo() { return class {}; } \n"
          "class Bar extends Foo() {}\n"
          "Foo()\n");
      creator.SetDefaultContext(context);
    }
  }
  v8::StartupData blob =
      creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kKeep);

  delete[] blob.data;
}

3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042
class DisableLazySourcePositionScope {
 public:
  DisableLazySourcePositionScope()
      : backup_value_(FLAG_enable_lazy_source_positions) {
    FLAG_enable_lazy_source_positions = false;
  }
  ~DisableLazySourcePositionScope() {
    FLAG_enable_lazy_source_positions = backup_value_;
  }

 private:
  bool backup_value_;
};

UNINITIALIZED_TEST(NoStackFrameCacheSerialization) {
  // Checks that exceptions caught are not cached in the
  // stack frame cache during serialization. The individual frames
  // can point to JSFunction objects, which need to be stored in a
  // context snapshot, *not* isolate snapshot.
  DisableAlwaysOpt();
  DisableLazySourcePositionScope lazy_scope;

  v8::SnapshotCreator creator;
  v8::Isolate* isolate = creator.GetIsolate();
  isolate->SetCaptureStackTraceForUncaughtExceptions(true);
  {
    v8::HandleScope handle_scope(isolate);
    {
      v8::Local<v8::Context> context = v8::Context::New(isolate);
      v8::Context::Scope context_scope(context);
      v8::TryCatch try_catch(isolate);
      CompileRun(R"(
        function foo() { throw new Error('bar'); }
        function bar() {
          foo();
        }
        bar();
      )");

      creator.SetDefaultContext(context);
    }
  }
  v8::StartupData blob =
      creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kKeep);

  delete[] blob.data;
}

4043 4044
}  // namespace internal
}  // namespace v8