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