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