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