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