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/heap/spaces.h"
41 : #include "src/interpreter/interpreter.h"
42 : #include "src/macro-assembler-inl.h"
43 : #include "src/objects-inl.h"
44 : #include "src/objects/js-array-buffer-inl.h"
45 : #include "src/objects/js-array-inl.h"
46 : #include "src/objects/js-regexp-inl.h"
47 : #include "src/runtime/runtime.h"
48 : #include "src/snapshot/code-serializer.h"
49 : #include "src/snapshot/natives.h"
50 : #include "src/snapshot/partial-deserializer.h"
51 : #include "src/snapshot/partial-serializer.h"
52 : #include "src/snapshot/read-only-serializer.h"
53 : #include "src/snapshot/snapshot.h"
54 : #include "src/snapshot/startup-deserializer.h"
55 : #include "src/snapshot/startup-serializer.h"
56 : #include "test/cctest/cctest.h"
57 : #include "test/cctest/heap/heap-utils.h"
58 : #include "test/cctest/setup-isolate-for-tests.h"
59 :
60 : namespace v8 {
61 : namespace internal {
62 :
63 : enum CodeCacheType { kLazy, kEager, kAfterExecute };
64 :
65 0 : void DisableAlwaysOpt() {
66 : // Isolates prepared for serialization do not optimize. The only exception is
67 : // with the flag --always-opt.
68 220 : FLAG_always_opt = false;
69 0 : }
70 :
71 : // A convenience struct to simplify management of the blobs required to
72 : // deserialize an isolate.
73 : struct StartupBlobs {
74 : Vector<const byte> startup;
75 : Vector<const byte> read_only;
76 :
77 65 : void Dispose() {
78 : startup.Dispose();
79 : read_only.Dispose();
80 65 : }
81 : };
82 :
83 : // TestSerializer is used for testing isolate serialization.
84 : class TestSerializer {
85 : public:
86 55 : static v8::Isolate* NewIsolateInitialized() {
87 : const bool kEnableSerializer = true;
88 : const bool kGenerateHeap = true;
89 55 : DisableEmbeddedBlobRefcounting();
90 55 : v8::Isolate* v8_isolate = NewIsolate(kEnableSerializer, kGenerateHeap);
91 : v8::Isolate::Scope isolate_scope(v8_isolate);
92 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
93 55 : isolate->Init(nullptr);
94 55 : isolate->heap()->read_only_space()->ClearStringPaddingIfNeeded();
95 55 : return v8_isolate;
96 : }
97 :
98 55 : static v8::Isolate* NewIsolateFromBlob(StartupBlobs& blobs) {
99 : SnapshotData startup_snapshot(blobs.startup);
100 : SnapshotData read_only_snapshot(blobs.read_only);
101 : StartupDeserializer deserializer(&startup_snapshot, &read_only_snapshot);
102 : const bool kEnableSerializer = false;
103 : const bool kGenerateHeap = false;
104 55 : v8::Isolate* v8_isolate = NewIsolate(kEnableSerializer, kGenerateHeap);
105 : v8::Isolate::Scope isolate_scope(v8_isolate);
106 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
107 55 : isolate->Init(&deserializer);
108 55 : return v8_isolate;
109 : }
110 :
111 : // Wraps v8::Isolate::New, but with a test isolate under the hood.
112 : // Allows flexibility to bootstrap with or without snapshot even when
113 : // the production Isolate class has one or the other behavior baked in.
114 150 : static v8::Isolate* NewIsolate(const v8::Isolate::CreateParams& params) {
115 : const bool kEnableSerializer = false;
116 150 : const bool kGenerateHeap = params.snapshot_blob == nullptr;
117 150 : v8::Isolate* v8_isolate = NewIsolate(kEnableSerializer, kGenerateHeap);
118 150 : v8::Isolate::Initialize(v8_isolate, params);
119 150 : return v8_isolate;
120 : }
121 :
122 : private:
123 : // Creates an Isolate instance configured for testing.
124 260 : static v8::Isolate* NewIsolate(bool with_serializer, bool generate_heap) {
125 260 : i::Isolate* isolate = i::Isolate::New();
126 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
127 :
128 260 : if (with_serializer) isolate->enable_serializer();
129 : isolate->set_array_buffer_allocator(CcTest::array_buffer_allocator());
130 520 : isolate->setup_delegate_ = new SetupIsolateDelegateForTests(generate_heap);
131 :
132 260 : return v8_isolate;
133 : }
134 : };
135 :
136 280 : static Vector<const byte> WritePayload(const Vector<const byte>& payload) {
137 : int length = payload.length();
138 140 : byte* blob = NewArray<byte>(length);
139 : memcpy(blob, payload.begin(), length);
140 140 : return Vector<const byte>(const_cast<const byte*>(blob), length);
141 : }
142 :
143 : namespace {
144 :
145 70 : bool RunExtraCode(v8::Isolate* isolate, v8::Local<v8::Context> context,
146 : const char* utf8_source, const char* name) {
147 : v8::Context::Scope context_scope(context);
148 140 : v8::TryCatch try_catch(isolate);
149 : v8::Local<v8::String> source_string;
150 70 : if (!v8::String::NewFromUtf8(isolate, utf8_source, v8::NewStringType::kNormal)
151 70 : .ToLocal(&source_string)) {
152 : return false;
153 : }
154 : v8::Local<v8::String> resource_name =
155 : v8::String::NewFromUtf8(isolate, name, v8::NewStringType::kNormal)
156 70 : .ToLocalChecked();
157 : v8::ScriptOrigin origin(resource_name);
158 : v8::ScriptCompiler::Source source(source_string, origin);
159 : v8::Local<v8::Script> script;
160 140 : if (!v8::ScriptCompiler::Compile(context, &source).ToLocal(&script))
161 : return false;
162 140 : if (script->Run(context).IsEmpty()) return false;
163 70 : CHECK(!try_catch.HasCaught());
164 : return true;
165 : }
166 :
167 70 : v8::StartupData CreateSnapshotDataBlob(
168 : v8::SnapshotCreator::FunctionCodeHandling function_code_handling,
169 : const char* embedded_source) {
170 : // Create a new isolate and a new context from scratch, optionally run
171 : // a script to embed, and serialize to create a snapshot blob.
172 70 : DisableEmbeddedBlobRefcounting();
173 : v8::StartupData result = {nullptr, 0};
174 : {
175 70 : v8::SnapshotCreator snapshot_creator;
176 70 : v8::Isolate* isolate = snapshot_creator.GetIsolate();
177 : {
178 70 : v8::HandleScope scope(isolate);
179 70 : v8::Local<v8::Context> context = v8::Context::New(isolate);
180 130 : if (embedded_source != nullptr &&
181 60 : !RunExtraCode(isolate, context, embedded_source, "<embedded>")) {
182 0 : return result;
183 : }
184 70 : snapshot_creator.SetDefaultContext(context);
185 : }
186 70 : result = snapshot_creator.CreateBlob(function_code_handling);
187 : }
188 70 : return result;
189 : }
190 :
191 : v8::StartupData CreateSnapshotDataBlob(const char* embedded_source = nullptr) {
192 : return CreateSnapshotDataBlob(
193 60 : v8::SnapshotCreator::FunctionCodeHandling::kClear, embedded_source);
194 : }
195 :
196 10 : v8::StartupData WarmUpSnapshotDataBlob(v8::StartupData cold_snapshot_blob,
197 : const char* warmup_source) {
198 10 : CHECK(cold_snapshot_blob.raw_size > 0 && cold_snapshot_blob.data != nullptr);
199 10 : CHECK_NOT_NULL(warmup_source);
200 : // Use following steps to create a warmed up snapshot blob from a cold one:
201 : // - Create a new isolate from the cold snapshot.
202 : // - Create a new context to run the warmup script. This will trigger
203 : // compilation of executed functions.
204 : // - Create a new context. This context will be unpolluted.
205 : // - Serialize the isolate and the second context into a new snapshot blob.
206 : v8::StartupData result = {nullptr, 0};
207 : {
208 10 : v8::SnapshotCreator snapshot_creator(nullptr, &cold_snapshot_blob);
209 10 : v8::Isolate* isolate = snapshot_creator.GetIsolate();
210 : {
211 10 : v8::HandleScope scope(isolate);
212 10 : v8::Local<v8::Context> context = v8::Context::New(isolate);
213 10 : if (!RunExtraCode(isolate, context, warmup_source, "<warm-up>")) {
214 0 : return result;
215 10 : }
216 : }
217 : {
218 10 : v8::HandleScope handle_scope(isolate);
219 10 : isolate->ContextDisposedNotification(false);
220 10 : v8::Local<v8::Context> context = v8::Context::New(isolate);
221 10 : snapshot_creator.SetDefaultContext(context);
222 : }
223 : result = snapshot_creator.CreateBlob(
224 10 : v8::SnapshotCreator::FunctionCodeHandling::kKeep);
225 : }
226 10 : return result;
227 : }
228 :
229 : } // namespace
230 :
231 55 : static StartupBlobs Serialize(v8::Isolate* isolate) {
232 : // We have to create one context. One reason for this is so that the builtins
233 : // can be loaded from self hosted JS builtins and their addresses can be
234 : // processed. This will clear the pending fixups array, which would otherwise
235 : // contain GC roots that would confuse the serialization/deserialization
236 : // process.
237 : v8::Isolate::Scope isolate_scope(isolate);
238 : {
239 55 : v8::HandleScope scope(isolate);
240 55 : v8::Context::New(isolate);
241 : }
242 :
243 : Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
244 : internal_isolate->heap()->CollectAllAvailableGarbage(
245 55 : i::GarbageCollectionReason::kTesting);
246 :
247 110 : ReadOnlySerializer read_only_serializer(internal_isolate);
248 55 : read_only_serializer.SerializeReadOnlyRoots();
249 :
250 110 : StartupSerializer ser(internal_isolate, &read_only_serializer);
251 55 : ser.SerializeStrongReferences();
252 :
253 55 : ser.SerializeWeakReferencesAndDeferred();
254 55 : read_only_serializer.FinalizeSerialization();
255 55 : SnapshotData startup_snapshot(&ser);
256 55 : SnapshotData read_only_snapshot(&read_only_serializer);
257 165 : return {WritePayload(startup_snapshot.RawData()),
258 165 : WritePayload(read_only_snapshot.RawData())};
259 : }
260 :
261 :
262 50 : Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head,
263 : Vector<const uint8_t> body,
264 : Vector<const uint8_t> tail, int repeats) {
265 100 : int source_length = head.length() + body.length() * repeats + tail.length();
266 50 : uint8_t* source = NewArray<uint8_t>(static_cast<size_t>(source_length));
267 50 : CopyChars(source, head.start(), head.length());
268 23159990 : for (int i = 0; i < repeats; i++) {
269 23159990 : CopyChars(source + head.length() + i * body.length(), body.start(),
270 46319980 : body.length());
271 : }
272 50 : CopyChars(source + head.length() + repeats * body.length(), tail.start(),
273 100 : tail.length());
274 : return Vector<const uint8_t>(const_cast<const uint8_t*>(source),
275 50 : source_length);
276 : }
277 :
278 :
279 45 : static v8::Isolate* Deserialize(StartupBlobs& blobs) {
280 45 : v8::Isolate* isolate = TestSerializer::NewIsolateFromBlob(blobs);
281 45 : CHECK(isolate);
282 45 : return isolate;
283 : }
284 :
285 :
286 40 : static void SanityCheck(v8::Isolate* v8_isolate) {
287 : Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
288 40 : v8::HandleScope scope(v8_isolate);
289 : #ifdef VERIFY_HEAP
290 : isolate->heap()->Verify();
291 : #endif
292 120 : CHECK(isolate->global_object()->IsJSObject());
293 120 : CHECK(isolate->native_context()->IsContext());
294 40 : isolate->factory()->InternalizeOneByteString(StaticCharVector("Empty"));
295 40 : }
296 :
297 30 : void TestStartupSerializerOnceImpl() {
298 30 : v8::Isolate* isolate = TestSerializer::NewIsolateInitialized();
299 30 : StartupBlobs blobs = Serialize(isolate);
300 30 : isolate->Dispose();
301 30 : isolate = Deserialize(blobs);
302 : {
303 30 : v8::HandleScope handle_scope(isolate);
304 : v8::Isolate::Scope isolate_scope(isolate);
305 :
306 30 : v8::Local<v8::Context> env = v8::Context::New(isolate);
307 30 : env->Enter();
308 :
309 60 : SanityCheck(isolate);
310 : }
311 30 : isolate->Dispose();
312 30 : blobs.Dispose();
313 30 : FreeCurrentEmbeddedBlob();
314 30 : }
315 :
316 28342 : UNINITIALIZED_TEST(StartupSerializerOnce) {
317 : DisableAlwaysOpt();
318 5 : TestStartupSerializerOnceImpl();
319 5 : }
320 :
321 28342 : UNINITIALIZED_TEST(StartupSerializerOnce1) {
322 : DisableAlwaysOpt();
323 5 : FLAG_serialization_chunk_size = 1;
324 5 : TestStartupSerializerOnceImpl();
325 5 : }
326 :
327 28342 : UNINITIALIZED_TEST(StartupSerializerOnce32) {
328 : DisableAlwaysOpt();
329 5 : FLAG_serialization_chunk_size = 32;
330 5 : TestStartupSerializerOnceImpl();
331 5 : }
332 :
333 28342 : UNINITIALIZED_TEST(StartupSerializerOnce1K) {
334 : DisableAlwaysOpt();
335 5 : FLAG_serialization_chunk_size = 1 * KB;
336 5 : TestStartupSerializerOnceImpl();
337 5 : }
338 :
339 28342 : UNINITIALIZED_TEST(StartupSerializerOnce4K) {
340 : DisableAlwaysOpt();
341 5 : FLAG_serialization_chunk_size = 4 * KB;
342 5 : TestStartupSerializerOnceImpl();
343 5 : }
344 :
345 28342 : UNINITIALIZED_TEST(StartupSerializerOnce32K) {
346 : DisableAlwaysOpt();
347 5 : FLAG_serialization_chunk_size = 32 * KB;
348 5 : TestStartupSerializerOnceImpl();
349 5 : }
350 :
351 28342 : UNINITIALIZED_TEST(StartupSerializerRootMapDependencies) {
352 : DisableAlwaysOpt();
353 5 : v8::SnapshotCreator snapshot_creator;
354 5 : v8::Isolate* isolate = snapshot_creator.GetIsolate();
355 : {
356 : v8::Isolate::Scope isolate_scope(isolate);
357 10 : v8::HandleScope handle_scope(isolate);
358 : Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
359 : // Here is interesting retaining path:
360 : // - FreeSpaceMap
361 : // - Map for Map types itself
362 : // - NullValue
363 : // - Internalized one byte string
364 : // - Map for Internalized one byte string
365 : // - TheHoleValue
366 : // - HeapNumber
367 : // HeapNumber objects require kDoubleUnaligned on 32-bit
368 : // platforms. So, without special measures we're risking to serialize
369 : // object, requiring alignment before FreeSpaceMap is fully serialized.
370 : v8::internal::Handle<Map> map(
371 : ReadOnlyRoots(internal_isolate).one_byte_internalized_string_map(),
372 : internal_isolate);
373 : // Need to avoid DCHECKs inside SnapshotCreator.
374 5 : snapshot_creator.SetDefaultContext(v8::Context::New(isolate));
375 : }
376 :
377 : v8::StartupData startup_data = snapshot_creator.CreateBlob(
378 5 : v8::SnapshotCreator::FunctionCodeHandling::kKeep);
379 :
380 : v8::Isolate::CreateParams params;
381 5 : params.snapshot_blob = &startup_data;
382 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
383 5 : isolate = v8::Isolate::New(params);
384 :
385 : {
386 5 : v8::HandleScope handle_scope(isolate);
387 : v8::Isolate::Scope isolate_scope(isolate);
388 :
389 5 : v8::Local<v8::Context> env = v8::Context::New(isolate);
390 5 : env->Enter();
391 :
392 10 : SanityCheck(isolate);
393 : }
394 5 : isolate->Dispose();
395 5 : delete[] startup_data.data;
396 5 : }
397 :
398 28342 : UNINITIALIZED_TEST(StartupSerializerTwice) {
399 : DisableAlwaysOpt();
400 5 : v8::Isolate* isolate = TestSerializer::NewIsolateInitialized();
401 5 : StartupBlobs blobs1 = Serialize(isolate);
402 5 : StartupBlobs blobs2 = Serialize(isolate);
403 5 : isolate->Dispose();
404 5 : blobs1.Dispose();
405 5 : isolate = Deserialize(blobs2);
406 : {
407 : v8::Isolate::Scope isolate_scope(isolate);
408 10 : v8::HandleScope handle_scope(isolate);
409 :
410 5 : v8::Local<v8::Context> env = v8::Context::New(isolate);
411 5 : env->Enter();
412 :
413 5 : SanityCheck(isolate);
414 : }
415 5 : isolate->Dispose();
416 5 : blobs2.Dispose();
417 5 : FreeCurrentEmbeddedBlob();
418 5 : }
419 :
420 28342 : UNINITIALIZED_TEST(StartupSerializerOnceRunScript) {
421 : DisableAlwaysOpt();
422 5 : v8::Isolate* isolate = TestSerializer::NewIsolateInitialized();
423 5 : StartupBlobs blobs = Serialize(isolate);
424 5 : isolate->Dispose();
425 5 : isolate = Deserialize(blobs);
426 : {
427 : v8::Isolate::Scope isolate_scope(isolate);
428 10 : v8::HandleScope handle_scope(isolate);
429 :
430 :
431 5 : v8::Local<v8::Context> env = v8::Context::New(isolate);
432 5 : env->Enter();
433 :
434 : const char* c_source = "\"1234\".length";
435 : v8::Local<v8::Script> script = v8_compile(c_source);
436 5 : v8::Maybe<int32_t> result = script->Run(isolate->GetCurrentContext())
437 5 : .ToLocalChecked()
438 10 : ->Int32Value(isolate->GetCurrentContext());
439 5 : CHECK_EQ(4, result.FromJust());
440 : }
441 5 : isolate->Dispose();
442 5 : blobs.Dispose();
443 5 : FreeCurrentEmbeddedBlob();
444 5 : }
445 :
446 28342 : UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) {
447 : DisableAlwaysOpt();
448 5 : v8::Isolate* isolate = TestSerializer::NewIsolateInitialized();
449 5 : StartupBlobs blobs1 = Serialize(isolate);
450 5 : StartupBlobs blobs2 = Serialize(isolate);
451 5 : isolate->Dispose();
452 5 : blobs1.Dispose();
453 5 : isolate = Deserialize(blobs2);
454 : {
455 : v8::Isolate::Scope isolate_scope(isolate);
456 10 : v8::HandleScope handle_scope(isolate);
457 :
458 5 : v8::Local<v8::Context> env = v8::Context::New(isolate);
459 5 : env->Enter();
460 :
461 : const char* c_source = "\"1234\".length";
462 : v8::Local<v8::Script> script = v8_compile(c_source);
463 5 : v8::Maybe<int32_t> result = script->Run(isolate->GetCurrentContext())
464 5 : .ToLocalChecked()
465 10 : ->Int32Value(isolate->GetCurrentContext());
466 5 : CHECK_EQ(4, result.FromJust());
467 : }
468 5 : isolate->Dispose();
469 5 : blobs2.Dispose();
470 5 : FreeCurrentEmbeddedBlob();
471 5 : }
472 :
473 5 : static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
474 : Vector<const byte>* read_only_blob_out,
475 : Vector<const byte>* partial_blob_out) {
476 5 : v8::Isolate* v8_isolate = TestSerializer::NewIsolateInitialized();
477 : Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
478 5 : Heap* heap = isolate->heap();
479 : {
480 : v8::Isolate::Scope isolate_scope(v8_isolate);
481 :
482 : v8::Persistent<v8::Context> env;
483 : {
484 : HandleScope scope(isolate);
485 10 : env.Reset(v8_isolate, v8::Context::New(v8_isolate));
486 : }
487 5 : CHECK(!env.IsEmpty());
488 : {
489 5 : v8::HandleScope handle_scope(v8_isolate);
490 5 : v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
491 : }
492 :
493 : // If we don't do this then we end up with a stray root pointing at the
494 : // context even after we have disposed of env.
495 5 : heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
496 :
497 : {
498 5 : v8::HandleScope handle_scope(v8_isolate);
499 5 : v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
500 : }
501 :
502 5 : i::Context raw_context = i::Context::cast(*v8::Utils::OpenPersistent(env));
503 :
504 : env.Reset();
505 :
506 : SnapshotByteSink read_only_sink;
507 10 : ReadOnlySerializer read_only_serializer(isolate);
508 5 : read_only_serializer.SerializeReadOnlyRoots();
509 :
510 : SnapshotByteSink startup_sink;
511 10 : StartupSerializer startup_serializer(isolate, &read_only_serializer);
512 5 : startup_serializer.SerializeStrongReferences();
513 :
514 : SnapshotByteSink partial_sink;
515 : PartialSerializer partial_serializer(isolate, &startup_serializer,
516 10 : v8::SerializeInternalFieldsCallback());
517 5 : partial_serializer.Serialize(&raw_context, false);
518 :
519 5 : startup_serializer.SerializeWeakReferencesAndDeferred();
520 :
521 5 : read_only_serializer.FinalizeSerialization();
522 :
523 5 : SnapshotData read_only_snapshot(&read_only_serializer);
524 5 : SnapshotData startup_snapshot(&startup_serializer);
525 5 : SnapshotData partial_snapshot(&partial_serializer);
526 :
527 10 : *partial_blob_out = WritePayload(partial_snapshot.RawData());
528 10 : *startup_blob_out = WritePayload(startup_snapshot.RawData());
529 10 : *read_only_blob_out = WritePayload(read_only_snapshot.RawData());
530 : }
531 5 : v8_isolate->Dispose();
532 5 : }
533 :
534 28342 : UNINITIALIZED_TEST(PartialSerializerContext) {
535 : DisableAlwaysOpt();
536 5 : Vector<const byte> startup_blob;
537 5 : Vector<const byte> read_only_blob;
538 5 : Vector<const byte> partial_blob;
539 5 : PartiallySerializeContext(&startup_blob, &read_only_blob, &partial_blob);
540 :
541 5 : StartupBlobs blobs = {startup_blob, read_only_blob};
542 5 : v8::Isolate* v8_isolate = TestSerializer::NewIsolateFromBlob(blobs);
543 5 : CHECK(v8_isolate);
544 : {
545 : v8::Isolate::Scope isolate_scope(v8_isolate);
546 :
547 : Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
548 : HandleScope handle_scope(isolate);
549 : Handle<Object> root;
550 : Handle<JSGlobalProxy> global_proxy =
551 : isolate->factory()->NewUninitializedJSGlobalProxy(
552 5 : JSGlobalProxy::SizeWithEmbedderFields(0));
553 : {
554 : SnapshotData snapshot_data(partial_blob);
555 : root = PartialDeserializer::DeserializeContext(
556 : isolate, &snapshot_data, false, global_proxy,
557 5 : v8::DeserializeInternalFieldsCallback())
558 10 : .ToHandleChecked();
559 10 : CHECK(root->IsContext());
560 15 : CHECK(Handle<Context>::cast(root)->global_proxy() == *global_proxy);
561 : }
562 :
563 : Handle<Object> root2;
564 : {
565 : SnapshotData snapshot_data(partial_blob);
566 : root2 = PartialDeserializer::DeserializeContext(
567 : isolate, &snapshot_data, false, global_proxy,
568 5 : v8::DeserializeInternalFieldsCallback())
569 10 : .ToHandleChecked();
570 10 : CHECK(root2->IsContext());
571 5 : CHECK(!root.is_identical_to(root2));
572 : }
573 : partial_blob.Dispose();
574 : }
575 5 : v8_isolate->Dispose();
576 5 : blobs.Dispose();
577 5 : FreeCurrentEmbeddedBlob();
578 5 : }
579 :
580 5 : static void PartiallySerializeCustomContext(
581 : Vector<const byte>* startup_blob_out,
582 : Vector<const byte>* read_only_blob_out,
583 : Vector<const byte>* partial_blob_out) {
584 5 : v8::Isolate* v8_isolate = TestSerializer::NewIsolateInitialized();
585 : Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
586 : {
587 : v8::Isolate::Scope isolate_scope(v8_isolate);
588 :
589 : v8::Persistent<v8::Context> env;
590 : {
591 : HandleScope scope(isolate);
592 10 : env.Reset(v8_isolate, v8::Context::New(v8_isolate));
593 : }
594 5 : CHECK(!env.IsEmpty());
595 : {
596 5 : v8::HandleScope handle_scope(v8_isolate);
597 5 : v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
598 : // After execution, e's function context refers to the global object.
599 : CompileRun(
600 : "var e;"
601 : "(function() {"
602 : " e = function(s) { return eval (s); }"
603 : "})();"
604 : "var o = this;"
605 : "var r = Math.random();"
606 : "var c = Math.sin(0) + Math.cos(0);"
607 : "var f = (function(a, b) { return a + b; }).bind(1, 2, 3);"
608 : "var s = parseInt('12345');"
609 : "var p = 0;"
610 : "(async ()=>{ p = await 42; })();");
611 :
612 : Vector<const uint8_t> source = ConstructSource(
613 : StaticCharVector("function g() { return [,"), StaticCharVector("1,"),
614 5 : StaticCharVector("];} a = g(); b = g(); b.push(1);"), 100000);
615 : v8::MaybeLocal<v8::String> source_str = v8::String::NewFromOneByte(
616 : v8_isolate, source.start(), v8::NewStringType::kNormal,
617 5 : source.length());
618 5 : CompileRun(source_str.ToLocalChecked());
619 5 : source.Dispose();
620 : }
621 : // If we don't do this then we end up with a stray root pointing at the
622 : // context even after we have disposed of env.
623 : isolate->heap()->CollectAllAvailableGarbage(
624 5 : i::GarbageCollectionReason::kTesting);
625 :
626 : {
627 5 : v8::HandleScope handle_scope(v8_isolate);
628 5 : v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
629 : }
630 :
631 5 : i::Context raw_context = i::Context::cast(*v8::Utils::OpenPersistent(env));
632 :
633 : env.Reset();
634 :
635 : SnapshotByteSink read_only_sink;
636 10 : ReadOnlySerializer read_only_serializer(isolate);
637 5 : read_only_serializer.SerializeReadOnlyRoots();
638 :
639 : SnapshotByteSink startup_sink;
640 10 : StartupSerializer startup_serializer(isolate, &read_only_serializer);
641 5 : startup_serializer.SerializeStrongReferences();
642 :
643 : SnapshotByteSink partial_sink;
644 : PartialSerializer partial_serializer(isolate, &startup_serializer,
645 10 : v8::SerializeInternalFieldsCallback());
646 5 : partial_serializer.Serialize(&raw_context, false);
647 :
648 5 : startup_serializer.SerializeWeakReferencesAndDeferred();
649 :
650 5 : read_only_serializer.FinalizeSerialization();
651 :
652 5 : SnapshotData read_only_snapshot(&read_only_serializer);
653 5 : SnapshotData startup_snapshot(&startup_serializer);
654 5 : SnapshotData partial_snapshot(&partial_serializer);
655 :
656 10 : *partial_blob_out = WritePayload(partial_snapshot.RawData());
657 10 : *startup_blob_out = WritePayload(startup_snapshot.RawData());
658 10 : *read_only_blob_out = WritePayload(read_only_snapshot.RawData());
659 : }
660 5 : v8_isolate->Dispose();
661 5 : }
662 :
663 28342 : UNINITIALIZED_TEST(PartialSerializerCustomContext) {
664 : DisableAlwaysOpt();
665 5 : Vector<const byte> startup_blob;
666 5 : Vector<const byte> read_only_blob;
667 5 : Vector<const byte> partial_blob;
668 : PartiallySerializeCustomContext(&startup_blob, &read_only_blob,
669 5 : &partial_blob);
670 :
671 5 : StartupBlobs blobs = {startup_blob, read_only_blob};
672 5 : v8::Isolate* v8_isolate = TestSerializer::NewIsolateFromBlob(blobs);
673 5 : CHECK(v8_isolate);
674 : {
675 : v8::Isolate::Scope isolate_scope(v8_isolate);
676 :
677 : Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
678 : HandleScope handle_scope(isolate);
679 : Handle<Object> root;
680 : Handle<JSGlobalProxy> global_proxy =
681 : isolate->factory()->NewUninitializedJSGlobalProxy(
682 5 : JSGlobalProxy::SizeWithEmbedderFields(0));
683 : {
684 : SnapshotData snapshot_data(partial_blob);
685 : root = PartialDeserializer::DeserializeContext(
686 : isolate, &snapshot_data, false, global_proxy,
687 5 : v8::DeserializeInternalFieldsCallback())
688 10 : .ToHandleChecked();
689 10 : CHECK(root->IsContext());
690 5 : Handle<Context> context = Handle<Context>::cast(root);
691 :
692 : // Add context to the weak native context list
693 : context->set(Context::NEXT_CONTEXT_LINK,
694 : isolate->heap()->native_contexts_list(),
695 10 : UPDATE_WEAK_WRITE_BARRIER);
696 : isolate->heap()->set_native_contexts_list(*context);
697 :
698 10 : CHECK(context->global_proxy() == *global_proxy);
699 5 : Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o");
700 10 : Handle<JSObject> global_object(context->global_object(), isolate);
701 5 : Handle<Object> property = JSReceiver::GetDataProperty(global_object, o);
702 5 : CHECK(property.is_identical_to(global_proxy));
703 :
704 : v8::Local<v8::Context> v8_context = v8::Utils::ToLocal(context);
705 : v8::Context::Scope context_scope(v8_context);
706 : double r = CompileRun("r")
707 5 : ->ToNumber(v8_isolate->GetCurrentContext())
708 5 : .ToLocalChecked()
709 5 : ->Value();
710 5 : CHECK(0.0 <= r && r < 1.0);
711 : // Math.random still works.
712 : double random = CompileRun("Math.random()")
713 5 : ->ToNumber(v8_isolate->GetCurrentContext())
714 5 : .ToLocalChecked()
715 5 : ->Value();
716 5 : CHECK(0.0 <= random && random < 1.0);
717 : double c = CompileRun("c")
718 5 : ->ToNumber(v8_isolate->GetCurrentContext())
719 5 : .ToLocalChecked()
720 5 : ->Value();
721 5 : CHECK_EQ(1, c);
722 : int f = CompileRun("f()")
723 5 : ->ToNumber(v8_isolate->GetCurrentContext())
724 5 : .ToLocalChecked()
725 5 : ->Int32Value(v8_isolate->GetCurrentContext())
726 10 : .FromJust();
727 5 : CHECK_EQ(5, f);
728 : f = CompileRun("e('f()')")
729 5 : ->ToNumber(v8_isolate->GetCurrentContext())
730 5 : .ToLocalChecked()
731 5 : ->Int32Value(v8_isolate->GetCurrentContext())
732 10 : .FromJust();
733 5 : CHECK_EQ(5, f);
734 : v8::Local<v8::String> s = CompileRun("s")
735 5 : ->ToString(v8_isolate->GetCurrentContext())
736 5 : .ToLocalChecked();
737 15 : CHECK(s->Equals(v8_isolate->GetCurrentContext(), v8_str("12345"))
738 : .FromJust());
739 : v8::Local<v8::String> p = CompileRun("p")
740 5 : ->ToString(v8_isolate->GetCurrentContext())
741 5 : .ToLocalChecked();
742 15 : CHECK(
743 : p->Equals(v8_isolate->GetCurrentContext(), v8_str("42")).FromJust());
744 : int a = CompileRun("a.length")
745 5 : ->ToNumber(v8_isolate->GetCurrentContext())
746 5 : .ToLocalChecked()
747 5 : ->Int32Value(v8_isolate->GetCurrentContext())
748 10 : .FromJust();
749 5 : CHECK_EQ(100001, a);
750 : int b = CompileRun("b.length")
751 5 : ->ToNumber(v8_isolate->GetCurrentContext())
752 5 : .ToLocalChecked()
753 5 : ->Int32Value(v8_isolate->GetCurrentContext())
754 10 : .FromJust();
755 5 : CHECK_EQ(100002, b);
756 : }
757 : partial_blob.Dispose();
758 : }
759 5 : v8_isolate->Dispose();
760 5 : blobs.Dispose();
761 5 : FreeCurrentEmbeddedBlob();
762 5 : }
763 :
764 28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlob1) {
765 : DisableAlwaysOpt();
766 : const char* source1 = "function f() { return 42; }";
767 :
768 5 : v8::StartupData data1 = CreateSnapshotDataBlob(source1);
769 :
770 : v8::Isolate::CreateParams params1;
771 5 : params1.snapshot_blob = &data1;
772 5 : params1.array_buffer_allocator = CcTest::array_buffer_allocator();
773 :
774 : // Test-appropriate equivalent of v8::Isolate::New.
775 5 : v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
776 : {
777 : v8::Isolate::Scope i_scope(isolate1);
778 10 : v8::HandleScope h_scope(isolate1);
779 5 : v8::Local<v8::Context> context = v8::Context::New(isolate1);
780 : v8::Context::Scope c_scope(context);
781 : v8::Maybe<int32_t> result =
782 10 : CompileRun("f()")->Int32Value(isolate1->GetCurrentContext());
783 5 : CHECK_EQ(42, result.FromJust());
784 5 : CHECK(CompileRun("this.g")->IsUndefined());
785 : }
786 5 : isolate1->Dispose();
787 5 : delete[] data1.data; // We can dispose of the snapshot blob now.
788 5 : FreeCurrentEmbeddedBlob();
789 5 : }
790 :
791 0 : static void UnreachableCallback(const FunctionCallbackInfo<Value>& args) {
792 0 : UNREACHABLE();
793 : }
794 :
795 28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobOverwriteGlobal) {
796 : DisableAlwaysOpt();
797 : const char* source1 = "function f() { return 42; }";
798 :
799 5 : v8::StartupData data1 = CreateSnapshotDataBlob(source1);
800 :
801 : v8::Isolate::CreateParams params1;
802 5 : params1.snapshot_blob = &data1;
803 5 : params1.array_buffer_allocator = CcTest::array_buffer_allocator();
804 :
805 : // Test that the snapshot overwrites the object template when there are
806 : // duplicate global properties.
807 5 : v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
808 : {
809 : v8::Isolate::Scope i_scope(isolate1);
810 10 : v8::HandleScope h_scope(isolate1);
811 : v8::Local<v8::ObjectTemplate> global_template =
812 5 : v8::ObjectTemplate::New(isolate1);
813 : global_template->Set(
814 15 : v8_str("f"), v8::FunctionTemplate::New(isolate1, UnreachableCallback));
815 : v8::Local<v8::Context> context =
816 5 : v8::Context::New(isolate1, nullptr, global_template);
817 : v8::Context::Scope c_scope(context);
818 : v8::Maybe<int32_t> result =
819 10 : CompileRun("f()")->Int32Value(isolate1->GetCurrentContext());
820 5 : CHECK_EQ(42, result.FromJust());
821 : }
822 5 : isolate1->Dispose();
823 5 : delete[] data1.data; // We can dispose of the snapshot blob now.
824 5 : FreeCurrentEmbeddedBlob();
825 5 : }
826 :
827 28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobStringNotInternalized) {
828 : DisableAlwaysOpt();
829 : const char* source1 =
830 : R"javascript(
831 : // String would be internalized if it came from a literal so create "A"
832 : // via a function call.
833 : var global = String.fromCharCode(65);
834 : function f() { return global; }
835 : )javascript";
836 :
837 5 : v8::StartupData data1 = CreateSnapshotDataBlob(source1);
838 :
839 : v8::Isolate::CreateParams params1;
840 5 : params1.snapshot_blob = &data1;
841 5 : params1.array_buffer_allocator = CcTest::array_buffer_allocator();
842 :
843 : // Test-appropriate equivalent of v8::Isolate::New.
844 5 : v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
845 : {
846 : v8::Isolate::Scope i_scope(isolate1);
847 10 : v8::HandleScope h_scope(isolate1);
848 5 : v8::Local<v8::Context> context = v8::Context::New(isolate1);
849 : v8::Context::Scope c_scope(context);
850 : v8::Local<v8::Value> result = CompileRun("f()").As<v8::Value>();
851 5 : CHECK(result->IsString());
852 5 : i::String str = *v8::Utils::OpenHandle(*result.As<v8::String>());
853 20 : CHECK_EQ(std::string(str->ToCString().get()), "A");
854 5 : CHECK(!str.IsInternalizedString());
855 10 : CHECK(
856 : !reinterpret_cast<i::Isolate*>(isolate1)->heap()->InReadOnlySpace(str));
857 : }
858 5 : isolate1->Dispose();
859 5 : delete[] data1.data; // We can dispose of the snapshot blob now.
860 5 : FreeCurrentEmbeddedBlob();
861 5 : }
862 :
863 : #ifndef V8_INTERPRETED_REGEXP
864 : namespace {
865 :
866 10 : void TestCustomSnapshotDataBlobWithIrregexpCode(
867 : v8::SnapshotCreator::FunctionCodeHandling function_code_handling) {
868 : DisableAlwaysOpt();
869 : const char* source =
870 : "var re1 = /\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\//;\n"
871 : "function f() { return '/* a comment */'.search(re1); }\n"
872 : "function g() { return 'not a comment'.search(re1); }\n"
873 : "function h() { return '// this is a comment'.search(re1); }\n"
874 : "var re2 = /a/;\n"
875 : "function i() { return '/* a comment */'.search(re2); }\n"
876 : "f(); f(); g(); g(); h(); h(); i(); i();\n";
877 :
878 : v8::StartupData data1 =
879 10 : CreateSnapshotDataBlob(function_code_handling, source);
880 :
881 : v8::Isolate::CreateParams params1;
882 10 : params1.snapshot_blob = &data1;
883 10 : params1.array_buffer_allocator = CcTest::array_buffer_allocator();
884 :
885 : // Test-appropriate equivalent of v8::Isolate::New.
886 10 : v8::Isolate* isolate1 = TestSerializer::NewIsolate(params1);
887 : {
888 : v8::Isolate::Scope i_scope(isolate1);
889 20 : v8::HandleScope h_scope(isolate1);
890 10 : v8::Local<v8::Context> context = v8::Context::New(isolate1);
891 : v8::Context::Scope c_scope(context);
892 : {
893 : // Check that compiled irregexp code has not been flushed prior to
894 : // serialization.
895 : i::Handle<i::JSRegExp> re =
896 : Utils::OpenHandle(*CompileRun("re1").As<v8::RegExp>());
897 20 : CHECK_EQ(re->HasCompiledCode(),
898 : function_code_handling ==
899 : v8::SnapshotCreator::FunctionCodeHandling::kKeep);
900 : }
901 : {
902 : v8::Maybe<int32_t> result =
903 20 : CompileRun("f()")->Int32Value(isolate1->GetCurrentContext());
904 10 : CHECK_EQ(0, result.FromJust());
905 : }
906 : {
907 : v8::Maybe<int32_t> result =
908 20 : CompileRun("g()")->Int32Value(isolate1->GetCurrentContext());
909 10 : CHECK_EQ(-1, result.FromJust());
910 : }
911 : {
912 : v8::Maybe<int32_t> result =
913 20 : CompileRun("h()")->Int32Value(isolate1->GetCurrentContext());
914 10 : CHECK_EQ(-1, result.FromJust());
915 : }
916 : {
917 : // Check that ATOM regexp remains valid.
918 : i::Handle<i::JSRegExp> re =
919 : Utils::OpenHandle(*CompileRun("re2").As<v8::RegExp>());
920 10 : CHECK_EQ(re->TypeTag(), JSRegExp::ATOM);
921 10 : CHECK(!re->HasCompiledCode());
922 : }
923 : }
924 10 : isolate1->Dispose();
925 10 : delete[] data1.data; // We can dispose of the snapshot blob now.
926 10 : FreeCurrentEmbeddedBlob();
927 10 : }
928 :
929 : } // namespace
930 :
931 28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCodeKeepCode) {
932 : TestCustomSnapshotDataBlobWithIrregexpCode(
933 5 : v8::SnapshotCreator::FunctionCodeHandling::kKeep);
934 5 : }
935 :
936 28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCodeClearCode) {
937 : TestCustomSnapshotDataBlobWithIrregexpCode(
938 5 : v8::SnapshotCreator::FunctionCodeHandling::kClear);
939 5 : }
940 : #endif // V8_INTERPRETED_REGEXP
941 :
942 28342 : 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 28337 : 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 28342 : 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 28342 : 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 28342 : 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 28342 : 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 28342 : 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 30 : return i::handle(i::JSArrayBuffer::cast(view->buffer()), view->GetIsolate());
1190 : }
1191 :
1192 28342 : 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 28342 : 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 28342 : 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 28342 : UNINITIALIZED_TEST(CustomSnapshotDataBlobWithLocker) {
1341 : DisableAlwaysOpt();
1342 : v8::Isolate::CreateParams create_params;
1343 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
1344 5 : DisableEmbeddedBlobRefcounting();
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 28342 : 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 28342 : 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 28342 : 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 28342 : 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 28342 : TEST(TestThatAlwaysSucceeds) {
1530 5 : }
1531 :
1532 :
1533 28337 : 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 832238 : for (HeapObject obj = iterator.next(); !obj.is_null();
1545 : obj = iterator.next()) {
1546 506748 : 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 75 : 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 28342 : TEST(CodeSerializerOnePlusOne) { TestCodeSerializerOnePlusOneImpl(); }
1629 :
1630 28342 : 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 28342 : TEST(CodeSerializerOnePlusOne1) {
1638 5 : FLAG_serialization_chunk_size = 1;
1639 5 : TestCodeSerializerOnePlusOneImpl();
1640 5 : }
1641 :
1642 28342 : TEST(CodeSerializerOnePlusOne32) {
1643 5 : FLAG_serialization_chunk_size = 32;
1644 5 : TestCodeSerializerOnePlusOneImpl();
1645 5 : }
1646 :
1647 28342 : TEST(CodeSerializerOnePlusOne4K) {
1648 5 : FLAG_serialization_chunk_size = 4 * KB;
1649 5 : TestCodeSerializerOnePlusOneImpl();
1650 5 : }
1651 :
1652 28342 : 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 28342 : 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 15 : 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 28342 : 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 28342 : 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_black_allocation = true;
1798 5 : FLAG_manual_evacuation_candidates_selection = true;
1799 :
1800 10 : LocalContext context;
1801 5 : Isolate* isolate = CcTest::i_isolate();
1802 15 : Heap* heap = isolate->heap();
1803 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
1804 :
1805 10 : v8::HandleScope scope(CcTest::isolate());
1806 :
1807 : Vector<const uint8_t> source = ConstructSource(
1808 : StaticCharVector("var j=1; if (j == 0) {"),
1809 : StaticCharVector("for (var i = 0; i < Object.prototype; i++);"),
1810 5 : StaticCharVector("} j=7; var s = 'happy_hippo'; j"), 20000);
1811 : Handle<String> source_str =
1812 10 : isolate->factory()->NewStringFromOneByte(source).ToHandleChecked();
1813 :
1814 : // Create a string on an evacuation candidate in old space.
1815 : Handle<String> moving_object;
1816 : Page* ec_page;
1817 : {
1818 : AlwaysAllocateScope always_allocate(isolate);
1819 5 : heap::SimulateFullSpace(heap->old_space());
1820 : moving_object = isolate->factory()->InternalizeString(
1821 5 : isolate->factory()->NewStringFromAsciiChecked("happy_hippo"));
1822 : ec_page = Page::FromHeapObject(*moving_object);
1823 : }
1824 :
1825 10 : Handle<JSObject> global(isolate->context()->global_object(), isolate);
1826 5 : ScriptData* cache = nullptr;
1827 :
1828 : Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
1829 : isolate, source_str, Handle<String>(), &cache,
1830 5 : v8::ScriptCompiler::kNoCompileOptions);
1831 :
1832 5 : CHECK(heap->InSpace(orig->abstract_code(), LO_SPACE));
1833 :
1834 : // Pretend that incremental marking is on when deserialization begins.
1835 5 : heap::ForceEvacuationCandidate(ec_page);
1836 5 : heap::SimulateIncrementalMarking(heap, false);
1837 : IncrementalMarking* marking = heap->incremental_marking();
1838 : marking->StartBlackAllocationForTesting();
1839 5 : CHECK(marking->IsCompacting());
1840 5 : CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*moving_object));
1841 :
1842 : Handle<SharedFunctionInfo> copy;
1843 : {
1844 : DisallowCompilation no_compile_expected(isolate);
1845 : copy = CompileScript(isolate, source_str, Handle<String>(), cache,
1846 10 : v8::ScriptCompiler::kConsumeCodeCache);
1847 : }
1848 15 : CHECK_NE(*orig, *copy);
1849 :
1850 : // We should have missed a write barrier. Complete incremental marking
1851 : // to flush out the bug.
1852 5 : heap::SimulateIncrementalMarking(heap, true);
1853 5 : CcTest::CollectAllGarbage();
1854 :
1855 : Handle<JSFunction> copy_fun =
1856 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
1857 10 : copy, isolate->native_context());
1858 :
1859 : Handle<Object> copy_result =
1860 10 : Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1861 :
1862 : int result_int;
1863 5 : CHECK(copy_result->ToInt32(&result_int));
1864 5 : CHECK_EQ(7, result_int);
1865 :
1866 10 : delete cache;
1867 : source.Dispose();
1868 : }
1869 28342 : TEST(CodeSerializerLargeStrings) {
1870 5 : LocalContext context;
1871 5 : Isolate* isolate = CcTest::i_isolate();
1872 : Factory* f = isolate->factory();
1873 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
1874 :
1875 10 : v8::HandleScope scope(CcTest::isolate());
1876 :
1877 : Vector<const uint8_t> source_s = ConstructSource(
1878 : StaticCharVector("var s = \""), StaticCharVector("abcdef"),
1879 5 : StaticCharVector("\";"), 1000000);
1880 : Vector<const uint8_t> source_t = ConstructSource(
1881 : StaticCharVector("var t = \""), StaticCharVector("uvwxyz"),
1882 5 : StaticCharVector("\"; s + t"), 999999);
1883 : Handle<String> source_str =
1884 : f->NewConsString(f->NewStringFromOneByte(source_s).ToHandleChecked(),
1885 15 : f->NewStringFromOneByte(source_t).ToHandleChecked())
1886 10 : .ToHandleChecked();
1887 :
1888 10 : Handle<JSObject> global(isolate->context()->global_object(), isolate);
1889 5 : ScriptData* cache = nullptr;
1890 :
1891 : Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
1892 : isolate, source_str, Handle<String>(), &cache,
1893 5 : v8::ScriptCompiler::kNoCompileOptions);
1894 :
1895 : Handle<SharedFunctionInfo> copy;
1896 : {
1897 : DisallowCompilation no_compile_expected(isolate);
1898 : copy = CompileScript(isolate, source_str, Handle<String>(), cache,
1899 15 : v8::ScriptCompiler::kConsumeCodeCache);
1900 : }
1901 15 : CHECK_NE(*orig, *copy);
1902 :
1903 : Handle<JSFunction> copy_fun =
1904 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
1905 10 : copy, isolate->native_context());
1906 :
1907 : Handle<Object> copy_result =
1908 10 : Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1909 :
1910 10 : CHECK_EQ(6 * 1999999, Handle<String>::cast(copy_result)->length());
1911 : Handle<Object> property = JSReceiver::GetDataProperty(
1912 15 : isolate->global_object(), f->NewStringFromAsciiChecked("s"));
1913 5 : CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
1914 : property = JSReceiver::GetDataProperty(isolate->global_object(),
1915 15 : f->NewStringFromAsciiChecked("t"));
1916 5 : CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
1917 : // Make sure we do not serialize too much, e.g. include the source string.
1918 10 : CHECK_LT(cache->length(), 13000000);
1919 :
1920 10 : delete cache;
1921 : source_s.Dispose();
1922 5 : source_t.Dispose();
1923 5 : }
1924 :
1925 28342 : TEST(CodeSerializerThreeBigStrings) {
1926 5 : LocalContext context;
1927 5 : Isolate* isolate = CcTest::i_isolate();
1928 : Factory* f = isolate->factory();
1929 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
1930 :
1931 10 : v8::HandleScope scope(CcTest::isolate());
1932 :
1933 : Vector<const uint8_t> source_a =
1934 : ConstructSource(StaticCharVector("var a = \""), StaticCharVector("a"),
1935 5 : StaticCharVector("\";"), 700000);
1936 : Handle<String> source_a_str =
1937 10 : f->NewStringFromOneByte(source_a).ToHandleChecked();
1938 :
1939 : Vector<const uint8_t> source_b =
1940 : ConstructSource(StaticCharVector("var b = \""), StaticCharVector("b"),
1941 5 : StaticCharVector("\";"), 400000);
1942 : Handle<String> source_b_str =
1943 10 : f->NewStringFromOneByte(source_b).ToHandleChecked();
1944 :
1945 : Vector<const uint8_t> source_c =
1946 : ConstructSource(StaticCharVector("var c = \""), StaticCharVector("c"),
1947 5 : StaticCharVector("\";"), 400000);
1948 : Handle<String> source_c_str =
1949 10 : f->NewStringFromOneByte(source_c).ToHandleChecked();
1950 :
1951 : Handle<String> source_str =
1952 : f->NewConsString(
1953 : f->NewConsString(source_a_str, source_b_str).ToHandleChecked(),
1954 15 : source_c_str).ToHandleChecked();
1955 :
1956 10 : Handle<JSObject> global(isolate->context()->global_object(), isolate);
1957 5 : ScriptData* cache = nullptr;
1958 :
1959 : Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
1960 : isolate, source_str, Handle<String>(), &cache,
1961 5 : v8::ScriptCompiler::kNoCompileOptions);
1962 :
1963 : Handle<SharedFunctionInfo> copy;
1964 : {
1965 : DisallowCompilation no_compile_expected(isolate);
1966 : copy = CompileScript(isolate, source_str, Handle<String>(), cache,
1967 10 : v8::ScriptCompiler::kConsumeCodeCache);
1968 : }
1969 15 : CHECK_NE(*orig, *copy);
1970 :
1971 : Handle<JSFunction> copy_fun =
1972 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
1973 10 : copy, isolate->native_context());
1974 :
1975 5 : USE(Execution::Call(isolate, copy_fun, global, 0, nullptr));
1976 :
1977 : v8::Maybe<int32_t> result =
1978 : CompileRun("(a + b).length")
1979 10 : ->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext());
1980 5 : CHECK_EQ(400000 + 700000, result.FromJust());
1981 : result = CompileRun("(b + c).length")
1982 10 : ->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext());
1983 5 : CHECK_EQ(400000 + 400000, result.FromJust());
1984 5 : Heap* heap = isolate->heap();
1985 : v8::Local<v8::String> result_str =
1986 : CompileRun("a")
1987 5 : ->ToString(CcTest::isolate()->GetCurrentContext())
1988 5 : .ToLocalChecked();
1989 5 : CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), LO_SPACE));
1990 : result_str = CompileRun("b")
1991 5 : ->ToString(CcTest::isolate()->GetCurrentContext())
1992 5 : .ToLocalChecked();
1993 : #if V8_HOST_ARCH_PPC
1994 : CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), LO_SPACE));
1995 : #else
1996 5 : CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), OLD_SPACE));
1997 : #endif
1998 :
1999 : result_str = CompileRun("c")
2000 5 : ->ToString(CcTest::isolate()->GetCurrentContext())
2001 5 : .ToLocalChecked();
2002 : #if V8_HOST_ARCH_PPC
2003 : CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), LO_SPACE));
2004 : #else
2005 5 : CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), OLD_SPACE));
2006 : #endif
2007 :
2008 10 : delete cache;
2009 : source_a.Dispose();
2010 : source_b.Dispose();
2011 5 : source_c.Dispose();
2012 5 : }
2013 :
2014 :
2015 56689 : class SerializerOneByteResource
2016 : : public v8::String::ExternalOneByteStringResource {
2017 : public:
2018 : SerializerOneByteResource(const char* data, size_t length)
2019 28352 : : data_(data), length_(length), dispose_count_(0) {}
2020 112 : const char* data() const override { return data_; }
2021 40 : size_t length() const override { return length_; }
2022 15 : void Dispose() override { dispose_count_++; }
2023 : int dispose_count() { return dispose_count_; }
2024 :
2025 : private:
2026 : const char* data_;
2027 : size_t length_;
2028 : int dispose_count_;
2029 : };
2030 :
2031 :
2032 : class SerializerTwoByteResource : public v8::String::ExternalStringResource {
2033 : public:
2034 : SerializerTwoByteResource(const char* data, size_t length)
2035 28342 : : data_(AsciiToTwoByteString(data)), length_(length), dispose_count_(0) {}
2036 56679 : ~SerializerTwoByteResource() override { DeleteArray<const uint16_t>(data_); }
2037 :
2038 72 : const uint16_t* data() const override { return data_; }
2039 25 : size_t length() const override { return length_; }
2040 15 : void Dispose() override { dispose_count_++; }
2041 : int dispose_count() { return dispose_count_; }
2042 :
2043 : private:
2044 : const uint16_t* data_;
2045 : size_t length_;
2046 : int dispose_count_;
2047 : };
2048 :
2049 28342 : TEST(CodeSerializerExternalString) {
2050 5 : LocalContext context;
2051 5 : Isolate* isolate = CcTest::i_isolate();
2052 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
2053 :
2054 10 : v8::HandleScope scope(CcTest::isolate());
2055 :
2056 : // Obtain external internalized one-byte string.
2057 : SerializerOneByteResource one_byte_resource("one_byte", 8);
2058 : Handle<String> one_byte_string =
2059 5 : isolate->factory()->NewStringFromAsciiChecked("one_byte");
2060 5 : one_byte_string = isolate->factory()->InternalizeString(one_byte_string);
2061 5 : one_byte_string->MakeExternal(&one_byte_resource);
2062 10 : CHECK(one_byte_string->IsExternalOneByteString());
2063 10 : CHECK(one_byte_string->IsInternalizedString());
2064 :
2065 : // Obtain external internalized two-byte string.
2066 : SerializerTwoByteResource two_byte_resource("two_byte", 8);
2067 : Handle<String> two_byte_string =
2068 5 : isolate->factory()->NewStringFromAsciiChecked("two_byte");
2069 5 : two_byte_string = isolate->factory()->InternalizeString(two_byte_string);
2070 5 : two_byte_string->MakeExternal(&two_byte_resource);
2071 10 : CHECK(two_byte_string->IsExternalTwoByteString());
2072 10 : CHECK(two_byte_string->IsInternalizedString());
2073 :
2074 : const char* source =
2075 : "var o = {} \n"
2076 : "o.one_byte = 7; \n"
2077 : "o.two_byte = 8; \n"
2078 : "o.one_byte + o.two_byte; \n";
2079 : Handle<String> source_string = isolate->factory()
2080 : ->NewStringFromUtf8(CStrVector(source))
2081 10 : .ToHandleChecked();
2082 :
2083 10 : Handle<JSObject> global(isolate->context()->global_object(), isolate);
2084 5 : ScriptData* cache = nullptr;
2085 :
2086 : Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
2087 : isolate, source_string, Handle<String>(), &cache,
2088 5 : v8::ScriptCompiler::kNoCompileOptions);
2089 :
2090 : Handle<SharedFunctionInfo> copy;
2091 : {
2092 : DisallowCompilation no_compile_expected(isolate);
2093 : copy = CompileScript(isolate, source_string, Handle<String>(), cache,
2094 10 : v8::ScriptCompiler::kConsumeCodeCache);
2095 : }
2096 15 : CHECK_NE(*orig, *copy);
2097 :
2098 : Handle<JSFunction> copy_fun =
2099 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
2100 10 : copy, isolate->native_context());
2101 :
2102 : Handle<Object> copy_result =
2103 10 : Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
2104 :
2105 5 : CHECK_EQ(15.0, copy_result->Number());
2106 :
2107 : // This avoids the GC from trying to free stack allocated resources.
2108 : i::Handle<i::ExternalOneByteString>::cast(one_byte_string)
2109 10 : ->SetResource(isolate, nullptr);
2110 : i::Handle<i::ExternalTwoByteString>::cast(two_byte_string)
2111 10 : ->SetResource(isolate, nullptr);
2112 15 : delete cache;
2113 5 : }
2114 :
2115 28342 : TEST(CodeSerializerLargeExternalString) {
2116 5 : LocalContext context;
2117 5 : Isolate* isolate = CcTest::i_isolate();
2118 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
2119 :
2120 : Factory* f = isolate->factory();
2121 :
2122 10 : v8::HandleScope scope(CcTest::isolate());
2123 :
2124 : // Create a huge external internalized string to use as variable name.
2125 : Vector<const uint8_t> string =
2126 : ConstructSource(StaticCharVector(""), StaticCharVector("abcdef"),
2127 5 : StaticCharVector(""), 999999);
2128 10 : Handle<String> name = f->NewStringFromOneByte(string).ToHandleChecked();
2129 : SerializerOneByteResource one_byte_resource(
2130 5 : reinterpret_cast<const char*>(string.start()), string.length());
2131 5 : name = f->InternalizeString(name);
2132 5 : name->MakeExternal(&one_byte_resource);
2133 10 : CHECK(name->IsExternalOneByteString());
2134 10 : CHECK(name->IsInternalizedString());
2135 5 : CHECK(isolate->heap()->InSpace(*name, LO_SPACE));
2136 :
2137 : // Create the source, which is "var <literal> = 42; <literal>".
2138 : Handle<String> source_str =
2139 : f->NewConsString(
2140 5 : f->NewConsString(f->NewStringFromAsciiChecked("var "), name)
2141 : .ToHandleChecked(),
2142 5 : f->NewConsString(f->NewStringFromAsciiChecked(" = 42; "), name)
2143 20 : .ToHandleChecked()).ToHandleChecked();
2144 :
2145 10 : Handle<JSObject> global(isolate->context()->global_object(), isolate);
2146 5 : ScriptData* cache = nullptr;
2147 :
2148 : Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
2149 : isolate, source_str, Handle<String>(), &cache,
2150 5 : v8::ScriptCompiler::kNoCompileOptions);
2151 :
2152 : Handle<SharedFunctionInfo> copy;
2153 : {
2154 : DisallowCompilation no_compile_expected(isolate);
2155 : copy = CompileScript(isolate, source_str, Handle<String>(), cache,
2156 10 : v8::ScriptCompiler::kConsumeCodeCache);
2157 : }
2158 15 : CHECK_NE(*orig, *copy);
2159 :
2160 : Handle<JSFunction> copy_fun =
2161 10 : f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
2162 :
2163 : Handle<Object> copy_result =
2164 10 : Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
2165 :
2166 5 : CHECK_EQ(42.0, copy_result->Number());
2167 :
2168 : // This avoids the GC from trying to free stack allocated resources.
2169 10 : i::Handle<i::ExternalOneByteString>::cast(name)->SetResource(isolate,
2170 5 : nullptr);
2171 10 : delete cache;
2172 5 : string.Dispose();
2173 5 : }
2174 :
2175 28342 : TEST(CodeSerializerExternalScriptName) {
2176 5 : LocalContext context;
2177 5 : Isolate* isolate = CcTest::i_isolate();
2178 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
2179 :
2180 : Factory* f = isolate->factory();
2181 :
2182 10 : v8::HandleScope scope(CcTest::isolate());
2183 :
2184 : const char* source =
2185 : "var a = [1, 2, 3, 4];"
2186 : "a.reduce(function(x, y) { return x + y }, 0)";
2187 :
2188 : Handle<String> source_string =
2189 10 : f->NewStringFromUtf8(CStrVector(source)).ToHandleChecked();
2190 :
2191 : const SerializerOneByteResource one_byte_resource("one_byte", 8);
2192 : Handle<String> name =
2193 10 : f->NewExternalStringFromOneByte(&one_byte_resource).ToHandleChecked();
2194 10 : CHECK(name->IsExternalOneByteString());
2195 10 : CHECK(!name->IsInternalizedString());
2196 :
2197 10 : Handle<JSObject> global(isolate->context()->global_object(), isolate);
2198 5 : ScriptData* cache = nullptr;
2199 :
2200 : Handle<SharedFunctionInfo> orig =
2201 : CompileScriptAndProduceCache(isolate, source_string, name, &cache,
2202 5 : v8::ScriptCompiler::kNoCompileOptions);
2203 :
2204 : Handle<SharedFunctionInfo> copy;
2205 : {
2206 : DisallowCompilation no_compile_expected(isolate);
2207 : copy = CompileScript(isolate, source_string, name, cache,
2208 5 : v8::ScriptCompiler::kConsumeCodeCache);
2209 : }
2210 15 : CHECK_NE(*orig, *copy);
2211 :
2212 : Handle<JSFunction> copy_fun =
2213 10 : f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
2214 :
2215 : Handle<Object> copy_result =
2216 10 : Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
2217 :
2218 5 : CHECK_EQ(10.0, copy_result->Number());
2219 :
2220 : // This avoids the GC from trying to free stack allocated resources.
2221 10 : i::Handle<i::ExternalOneByteString>::cast(name)->SetResource(isolate,
2222 5 : nullptr);
2223 15 : delete cache;
2224 5 : }
2225 :
2226 :
2227 : static bool toplevel_test_code_event_found = false;
2228 :
2229 :
2230 88 : static void SerializerCodeEventListener(const v8::JitCodeEvent* event) {
2231 118 : if (event->type == v8::JitCodeEvent::CODE_ADDED &&
2232 50 : (memcmp(event->name.str, "Script:~ test", 13) == 0 ||
2233 20 : memcmp(event->name.str, "Script: test", 12) == 0)) {
2234 10 : toplevel_test_code_event_found = true;
2235 : }
2236 88 : }
2237 :
2238 25 : v8::ScriptCompiler::CachedData* CompileRunAndProduceCache(
2239 : const char* source, CodeCacheType cacheType = CodeCacheType::kLazy) {
2240 : v8::ScriptCompiler::CachedData* cache;
2241 : v8::Isolate::CreateParams create_params;
2242 25 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
2243 25 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
2244 : {
2245 : v8::Isolate::Scope iscope(isolate1);
2246 50 : v8::HandleScope scope(isolate1);
2247 25 : v8::Local<v8::Context> context = v8::Context::New(isolate1);
2248 : v8::Context::Scope context_scope(context);
2249 :
2250 25 : v8::Local<v8::String> source_str = v8_str(source);
2251 25 : v8::ScriptOrigin origin(v8_str("test"));
2252 : v8::ScriptCompiler::Source source(source_str, origin);
2253 : v8::ScriptCompiler::CompileOptions options;
2254 25 : switch (cacheType) {
2255 : case CodeCacheType::kEager:
2256 : options = v8::ScriptCompiler::kEagerCompile;
2257 : break;
2258 : case CodeCacheType::kLazy:
2259 : case CodeCacheType::kAfterExecute:
2260 : options = v8::ScriptCompiler::kNoCompileOptions;
2261 20 : break;
2262 : default:
2263 0 : UNREACHABLE();
2264 : }
2265 : v8::Local<v8::UnboundScript> script =
2266 : v8::ScriptCompiler::CompileUnboundScript(isolate1, &source, options)
2267 25 : .ToLocalChecked();
2268 :
2269 25 : if (cacheType != CodeCacheType::kAfterExecute) {
2270 20 : cache = ScriptCompiler::CreateCodeCache(script);
2271 : }
2272 :
2273 : v8::Local<v8::Value> result = script->BindToCurrentContext()
2274 50 : ->Run(isolate1->GetCurrentContext())
2275 25 : .ToLocalChecked();
2276 : v8::Local<v8::String> result_string =
2277 25 : result->ToString(isolate1->GetCurrentContext()).ToLocalChecked();
2278 75 : CHECK(result_string->Equals(isolate1->GetCurrentContext(), v8_str("abcdef"))
2279 : .FromJust());
2280 :
2281 25 : if (cacheType == CodeCacheType::kAfterExecute) {
2282 5 : cache = ScriptCompiler::CreateCodeCache(script);
2283 : }
2284 25 : CHECK(cache);
2285 : }
2286 25 : isolate1->Dispose();
2287 25 : return cache;
2288 : }
2289 :
2290 28342 : TEST(CodeSerializerIsolates) {
2291 : const char* source = "function f() { return 'abc'; }; f() + 'def'";
2292 5 : v8::ScriptCompiler::CachedData* cache = CompileRunAndProduceCache(source);
2293 :
2294 : v8::Isolate::CreateParams create_params;
2295 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
2296 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
2297 : isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
2298 5 : SerializerCodeEventListener);
2299 5 : toplevel_test_code_event_found = false;
2300 : {
2301 : v8::Isolate::Scope iscope(isolate2);
2302 10 : v8::HandleScope scope(isolate2);
2303 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
2304 : v8::Context::Scope context_scope(context);
2305 :
2306 5 : v8::Local<v8::String> source_str = v8_str(source);
2307 5 : v8::ScriptOrigin origin(v8_str("test"));
2308 : v8::ScriptCompiler::Source source(source_str, origin, cache);
2309 : v8::Local<v8::UnboundScript> script;
2310 : {
2311 : DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
2312 : script = v8::ScriptCompiler::CompileUnboundScript(
2313 : isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
2314 5 : .ToLocalChecked();
2315 : }
2316 5 : CHECK(!cache->rejected);
2317 : v8::Local<v8::Value> result = script->BindToCurrentContext()
2318 10 : ->Run(isolate2->GetCurrentContext())
2319 5 : .ToLocalChecked();
2320 20 : CHECK(result->ToString(isolate2->GetCurrentContext())
2321 : .ToLocalChecked()
2322 : ->Equals(isolate2->GetCurrentContext(), v8_str("abcdef"))
2323 : .FromJust());
2324 : }
2325 5 : CHECK(toplevel_test_code_event_found);
2326 5 : isolate2->Dispose();
2327 5 : }
2328 :
2329 28342 : TEST(CodeSerializerIsolatesEager) {
2330 : const char* source =
2331 : "function f() {"
2332 : " return function g() {"
2333 : " return 'abc';"
2334 : " }"
2335 : "}"
2336 : "f()() + 'def'";
2337 : v8::ScriptCompiler::CachedData* cache =
2338 5 : CompileRunAndProduceCache(source, CodeCacheType::kEager);
2339 :
2340 : v8::Isolate::CreateParams create_params;
2341 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
2342 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
2343 : isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
2344 5 : SerializerCodeEventListener);
2345 5 : toplevel_test_code_event_found = false;
2346 : {
2347 : v8::Isolate::Scope iscope(isolate2);
2348 10 : v8::HandleScope scope(isolate2);
2349 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
2350 : v8::Context::Scope context_scope(context);
2351 :
2352 5 : v8::Local<v8::String> source_str = v8_str(source);
2353 5 : v8::ScriptOrigin origin(v8_str("test"));
2354 : v8::ScriptCompiler::Source source(source_str, origin, cache);
2355 : v8::Local<v8::UnboundScript> script;
2356 : {
2357 : DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
2358 : script = v8::ScriptCompiler::CompileUnboundScript(
2359 : isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
2360 5 : .ToLocalChecked();
2361 : }
2362 5 : CHECK(!cache->rejected);
2363 : v8::Local<v8::Value> result = script->BindToCurrentContext()
2364 10 : ->Run(isolate2->GetCurrentContext())
2365 5 : .ToLocalChecked();
2366 20 : CHECK(result->ToString(isolate2->GetCurrentContext())
2367 : .ToLocalChecked()
2368 : ->Equals(isolate2->GetCurrentContext(), v8_str("abcdef"))
2369 : .FromJust());
2370 : }
2371 5 : CHECK(toplevel_test_code_event_found);
2372 5 : isolate2->Dispose();
2373 5 : }
2374 :
2375 28342 : TEST(CodeSerializerAfterExecute) {
2376 : // We test that no compilations happen when running this code. Forcing
2377 : // to always optimize breaks this test.
2378 5 : bool prev_always_opt_value = FLAG_always_opt;
2379 5 : FLAG_always_opt = false;
2380 : const char* source = "function f() { return 'abc'; }; f() + 'def'";
2381 : v8::ScriptCompiler::CachedData* cache =
2382 5 : CompileRunAndProduceCache(source, CodeCacheType::kAfterExecute);
2383 :
2384 : v8::Isolate::CreateParams create_params;
2385 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
2386 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
2387 :
2388 : {
2389 : v8::Isolate::Scope iscope(isolate2);
2390 10 : v8::HandleScope scope(isolate2);
2391 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
2392 : v8::Context::Scope context_scope(context);
2393 :
2394 5 : v8::Local<v8::String> source_str = v8_str(source);
2395 5 : v8::ScriptOrigin origin(v8_str("test"));
2396 : v8::ScriptCompiler::Source source(source_str, origin, cache);
2397 : v8::Local<v8::UnboundScript> script;
2398 : {
2399 : DisallowCompilation no_compile_expected(
2400 : reinterpret_cast<Isolate*>(isolate2));
2401 : script = v8::ScriptCompiler::CompileUnboundScript(
2402 : isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
2403 5 : .ToLocalChecked();
2404 : }
2405 5 : CHECK(!cache->rejected);
2406 :
2407 : Handle<SharedFunctionInfo> sfi = v8::Utils::OpenHandle(*script);
2408 5 : CHECK(sfi->HasBytecodeArray());
2409 5 : BytecodeArray bytecode = sfi->GetBytecodeArray();
2410 10 : CHECK_EQ(bytecode->interrupt_budget(),
2411 : interpreter::Interpreter::InterruptBudget());
2412 5 : CHECK_EQ(bytecode->osr_loop_nesting_level(), 0);
2413 :
2414 : {
2415 : DisallowCompilation no_compile_expected(
2416 : reinterpret_cast<Isolate*>(isolate2));
2417 : v8::Local<v8::Value> result = script->BindToCurrentContext()
2418 10 : ->Run(isolate2->GetCurrentContext())
2419 5 : .ToLocalChecked();
2420 : v8::Local<v8::String> result_string =
2421 5 : result->ToString(isolate2->GetCurrentContext()).ToLocalChecked();
2422 15 : CHECK(
2423 : result_string->Equals(isolate2->GetCurrentContext(), v8_str("abcdef"))
2424 : .FromJust());
2425 : }
2426 : }
2427 5 : isolate2->Dispose();
2428 :
2429 : // Restore the flags.
2430 5 : FLAG_always_opt = prev_always_opt_value;
2431 5 : }
2432 :
2433 28342 : TEST(CodeSerializerFlagChange) {
2434 : const char* source = "function f() { return 'abc'; }; f() + 'def'";
2435 5 : v8::ScriptCompiler::CachedData* cache = CompileRunAndProduceCache(source);
2436 :
2437 : v8::Isolate::CreateParams create_params;
2438 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
2439 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
2440 :
2441 5 : FLAG_allow_natives_syntax = true; // Flag change should trigger cache reject.
2442 5 : FlagList::EnforceFlagImplications();
2443 : {
2444 : v8::Isolate::Scope iscope(isolate2);
2445 10 : v8::HandleScope scope(isolate2);
2446 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
2447 : v8::Context::Scope context_scope(context);
2448 :
2449 5 : v8::Local<v8::String> source_str = v8_str(source);
2450 5 : v8::ScriptOrigin origin(v8_str("test"));
2451 : v8::ScriptCompiler::Source source(source_str, origin, cache);
2452 : v8::ScriptCompiler::CompileUnboundScript(
2453 : isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
2454 5 : .ToLocalChecked();
2455 5 : CHECK(cache->rejected);
2456 : }
2457 5 : isolate2->Dispose();
2458 5 : }
2459 :
2460 28342 : TEST(CodeSerializerBitFlip) {
2461 : const char* source = "function f() { return 'abc'; }; f() + 'def'";
2462 5 : v8::ScriptCompiler::CachedData* cache = CompileRunAndProduceCache(source);
2463 :
2464 : // Random bit flip.
2465 5 : const_cast<uint8_t*>(cache->data)[337] ^= 0x40;
2466 :
2467 : v8::Isolate::CreateParams create_params;
2468 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
2469 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
2470 : {
2471 : v8::Isolate::Scope iscope(isolate2);
2472 10 : v8::HandleScope scope(isolate2);
2473 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
2474 : v8::Context::Scope context_scope(context);
2475 :
2476 5 : v8::Local<v8::String> source_str = v8_str(source);
2477 5 : v8::ScriptOrigin origin(v8_str("test"));
2478 : v8::ScriptCompiler::Source source(source_str, origin, cache);
2479 : v8::ScriptCompiler::CompileUnboundScript(
2480 : isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
2481 5 : .ToLocalChecked();
2482 5 : CHECK(cache->rejected);
2483 : }
2484 5 : isolate2->Dispose();
2485 5 : }
2486 :
2487 28342 : TEST(CodeSerializerWithHarmonyScoping) {
2488 : const char* source1 = "'use strict'; let x = 'X'";
2489 : const char* source2 = "'use strict'; let y = 'Y'";
2490 : const char* source3 = "'use strict'; x + y";
2491 :
2492 : v8::ScriptCompiler::CachedData* cache;
2493 :
2494 : v8::Isolate::CreateParams create_params;
2495 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
2496 5 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
2497 : {
2498 : v8::Isolate::Scope iscope(isolate1);
2499 10 : v8::HandleScope scope(isolate1);
2500 5 : v8::Local<v8::Context> context = v8::Context::New(isolate1);
2501 : v8::Context::Scope context_scope(context);
2502 :
2503 : CompileRun(source1);
2504 : CompileRun(source2);
2505 :
2506 5 : v8::Local<v8::String> source_str = v8_str(source3);
2507 5 : v8::ScriptOrigin origin(v8_str("test"));
2508 : v8::ScriptCompiler::Source source(source_str, origin);
2509 : v8::Local<v8::UnboundScript> script =
2510 : v8::ScriptCompiler::CompileUnboundScript(
2511 : isolate1, &source, v8::ScriptCompiler::kNoCompileOptions)
2512 5 : .ToLocalChecked();
2513 5 : cache = v8::ScriptCompiler::CreateCodeCache(script);
2514 5 : CHECK(cache);
2515 :
2516 : v8::Local<v8::Value> result = script->BindToCurrentContext()
2517 10 : ->Run(isolate1->GetCurrentContext())
2518 5 : .ToLocalChecked();
2519 : v8::Local<v8::String> result_str =
2520 5 : result->ToString(isolate1->GetCurrentContext()).ToLocalChecked();
2521 15 : CHECK(result_str->Equals(isolate1->GetCurrentContext(), v8_str("XY"))
2522 : .FromJust());
2523 : }
2524 5 : isolate1->Dispose();
2525 :
2526 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
2527 : {
2528 : v8::Isolate::Scope iscope(isolate2);
2529 10 : v8::HandleScope scope(isolate2);
2530 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
2531 : v8::Context::Scope context_scope(context);
2532 :
2533 : // Reverse order of prior running scripts.
2534 : CompileRun(source2);
2535 : CompileRun(source1);
2536 :
2537 5 : v8::Local<v8::String> source_str = v8_str(source3);
2538 5 : v8::ScriptOrigin origin(v8_str("test"));
2539 : v8::ScriptCompiler::Source source(source_str, origin, cache);
2540 : v8::Local<v8::UnboundScript> script;
2541 : {
2542 : DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
2543 : script = v8::ScriptCompiler::CompileUnboundScript(
2544 : isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
2545 5 : .ToLocalChecked();
2546 : }
2547 : v8::Local<v8::Value> result = script->BindToCurrentContext()
2548 10 : ->Run(isolate2->GetCurrentContext())
2549 5 : .ToLocalChecked();
2550 : v8::Local<v8::String> result_str =
2551 5 : result->ToString(isolate2->GetCurrentContext()).ToLocalChecked();
2552 15 : CHECK(result_str->Equals(isolate2->GetCurrentContext(), v8_str("XY"))
2553 : .FromJust());
2554 : }
2555 5 : isolate2->Dispose();
2556 5 : }
2557 :
2558 28342 : TEST(Regress503552) {
2559 5 : if (!FLAG_incremental_marking) return;
2560 : // Test that the code serializer can deal with weak cells that form a linked
2561 : // list during incremental marking.
2562 5 : CcTest::InitializeVM();
2563 : Isolate* isolate = CcTest::i_isolate();
2564 :
2565 : HandleScope scope(isolate);
2566 : Handle<String> source = isolate->factory()->NewStringFromAsciiChecked(
2567 5 : "function f() {} function g() {}");
2568 5 : ScriptData* script_data = nullptr;
2569 : Handle<SharedFunctionInfo> shared = CompileScriptAndProduceCache(
2570 : isolate, source, Handle<String>(), &script_data,
2571 5 : v8::ScriptCompiler::kNoCompileOptions);
2572 10 : delete script_data;
2573 :
2574 5 : heap::SimulateIncrementalMarking(isolate->heap());
2575 :
2576 : v8::ScriptCompiler::CachedData* cache_data =
2577 5 : CodeSerializer::Serialize(shared);
2578 5 : delete cache_data;
2579 : }
2580 :
2581 28342 : TEST(SnapshotCreatorMultipleContexts) {
2582 : DisableAlwaysOpt();
2583 : v8::StartupData blob;
2584 : {
2585 5 : v8::SnapshotCreator creator;
2586 5 : v8::Isolate* isolate = creator.GetIsolate();
2587 : {
2588 5 : v8::HandleScope handle_scope(isolate);
2589 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2590 : v8::Context::Scope context_scope(context);
2591 : CompileRun("var f = function() { return 1; }");
2592 10 : creator.SetDefaultContext(context);
2593 : }
2594 : {
2595 5 : v8::HandleScope handle_scope(isolate);
2596 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2597 : v8::Context::Scope context_scope(context);
2598 : CompileRun("var f = function() { return 2; }");
2599 10 : CHECK_EQ(0u, creator.AddContext(context));
2600 : }
2601 : {
2602 5 : v8::HandleScope handle_scope(isolate);
2603 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2604 5 : CHECK_EQ(1u, creator.AddContext(context));
2605 : }
2606 : blob =
2607 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
2608 : }
2609 :
2610 : v8::Isolate::CreateParams params;
2611 5 : params.snapshot_blob = &blob;
2612 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
2613 : // Test-appropriate equivalent of v8::Isolate::New.
2614 5 : v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2615 : {
2616 : v8::Isolate::Scope isolate_scope(isolate);
2617 : {
2618 5 : v8::HandleScope handle_scope(isolate);
2619 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2620 : v8::Context::Scope context_scope(context);
2621 10 : ExpectInt32("f()", 1);
2622 : }
2623 : {
2624 5 : v8::HandleScope handle_scope(isolate);
2625 : v8::Local<v8::Context> context =
2626 10 : v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
2627 : v8::Context::Scope context_scope(context);
2628 10 : ExpectInt32("f()", 2);
2629 : }
2630 : {
2631 5 : v8::HandleScope handle_scope(isolate);
2632 : v8::Local<v8::Context> context =
2633 10 : v8::Context::FromSnapshot(isolate, 1).ToLocalChecked();
2634 : v8::Context::Scope context_scope(context);
2635 10 : ExpectUndefined("this.f");
2636 : }
2637 : }
2638 :
2639 5 : isolate->Dispose();
2640 5 : delete[] blob.data;
2641 5 : }
2642 :
2643 : static int serialized_static_field = 314;
2644 :
2645 65 : static void SerializedCallback(
2646 170 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2647 65 : if (args.Data()->IsExternal()) {
2648 20 : CHECK_EQ(args.Data().As<v8::External>()->Value(),
2649 : static_cast<void*>(&serialized_static_field));
2650 : int* value =
2651 20 : reinterpret_cast<int*>(args.Data().As<v8::External>()->Value());
2652 20 : (*value)++;
2653 : }
2654 65 : args.GetReturnValue().Set(v8_num(42));
2655 65 : }
2656 :
2657 10 : static void SerializedCallbackReplacement(
2658 10 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2659 10 : args.GetReturnValue().Set(v8_num(1337));
2660 10 : }
2661 :
2662 145 : static void NamedPropertyGetterForSerialization(
2663 : v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2664 435 : if (name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("x"))
2665 290 : .FromJust()) {
2666 20 : info.GetReturnValue().Set(v8_num(2016));
2667 : }
2668 145 : }
2669 :
2670 10 : static void AccessorForSerialization(
2671 : v8::Local<v8::String> property,
2672 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2673 10 : info.GetReturnValue().Set(v8_num(2017));
2674 10 : }
2675 :
2676 :
2677 28337 : static SerializerOneByteResource serializable_one_byte_resource("one_byte", 8);
2678 28337 : static SerializerTwoByteResource serializable_two_byte_resource("two_byte", 8);
2679 :
2680 : intptr_t original_external_references[] = {
2681 : reinterpret_cast<intptr_t>(SerializedCallback),
2682 : reinterpret_cast<intptr_t>(&serialized_static_field),
2683 : reinterpret_cast<intptr_t>(&NamedPropertyGetterForSerialization),
2684 : reinterpret_cast<intptr_t>(&AccessorForSerialization),
2685 : reinterpret_cast<intptr_t>(&serialized_static_field), // duplicate entry
2686 : reinterpret_cast<intptr_t>(&serializable_one_byte_resource),
2687 : reinterpret_cast<intptr_t>(&serializable_two_byte_resource),
2688 : 0};
2689 :
2690 : intptr_t replaced_external_references[] = {
2691 : reinterpret_cast<intptr_t>(SerializedCallbackReplacement),
2692 : reinterpret_cast<intptr_t>(&serialized_static_field),
2693 : reinterpret_cast<intptr_t>(&NamedPropertyGetterForSerialization),
2694 : reinterpret_cast<intptr_t>(&AccessorForSerialization),
2695 : reinterpret_cast<intptr_t>(&serialized_static_field),
2696 : reinterpret_cast<intptr_t>(&serializable_one_byte_resource),
2697 : reinterpret_cast<intptr_t>(&serializable_two_byte_resource),
2698 : 0};
2699 :
2700 : intptr_t short_external_references[] = {
2701 : reinterpret_cast<intptr_t>(SerializedCallbackReplacement), 0};
2702 :
2703 28342 : TEST(SnapshotCreatorExternalReferences) {
2704 : DisableAlwaysOpt();
2705 : v8::StartupData blob;
2706 : {
2707 5 : v8::SnapshotCreator creator(original_external_references);
2708 5 : v8::Isolate* isolate = creator.GetIsolate();
2709 : {
2710 5 : v8::HandleScope handle_scope(isolate);
2711 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2712 : v8::Context::Scope context_scope(context);
2713 : v8::Local<v8::FunctionTemplate> callback =
2714 5 : v8::FunctionTemplate::New(isolate, SerializedCallback);
2715 : v8::Local<v8::Value> function =
2716 5 : callback->GetFunction(context).ToLocalChecked();
2717 20 : CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
2718 :
2719 25 : CHECK(context->Global()
2720 : ->Set(context, v8_str("one_byte"),
2721 : v8::String::NewExternalOneByte(
2722 : isolate, &serializable_one_byte_resource)
2723 : .ToLocalChecked())
2724 : .FromJust());
2725 25 : CHECK(context->Global()
2726 : ->Set(context, v8_str("two_byte"),
2727 : v8::String::NewExternalTwoByte(
2728 : isolate, &serializable_two_byte_resource)
2729 : .ToLocalChecked())
2730 : .FromJust());
2731 :
2732 5 : ExpectInt32("f()", 42);
2733 5 : ExpectString("one_byte", "one_byte");
2734 5 : ExpectString("two_byte", "two_byte");
2735 10 : creator.SetDefaultContext(context);
2736 : }
2737 : blob =
2738 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
2739 : }
2740 :
2741 5 : CHECK_EQ(1, serializable_one_byte_resource.dispose_count());
2742 5 : CHECK_EQ(1, serializable_two_byte_resource.dispose_count());
2743 :
2744 : // Deserialize with the original external reference.
2745 : {
2746 : v8::Isolate::CreateParams params;
2747 5 : params.snapshot_blob = &blob;
2748 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
2749 5 : params.external_references = original_external_references;
2750 : // Test-appropriate equivalent of v8::Isolate::New.
2751 5 : v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2752 : {
2753 : v8::Isolate::Scope isolate_scope(isolate);
2754 10 : v8::HandleScope handle_scope(isolate);
2755 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2756 : v8::Context::Scope context_scope(context);
2757 5 : ExpectInt32("f()", 42);
2758 5 : ExpectString("one_byte", "one_byte");
2759 5 : ExpectString("two_byte", "two_byte");
2760 5 : CHECK(CompileRun("one_byte").As<v8::String>()->IsExternalOneByte());
2761 5 : CHECK(CompileRun("two_byte").As<v8::String>()->IsExternal());
2762 : }
2763 5 : isolate->Dispose();
2764 : }
2765 :
2766 5 : CHECK_EQ(2, serializable_one_byte_resource.dispose_count());
2767 5 : CHECK_EQ(2, serializable_two_byte_resource.dispose_count());
2768 :
2769 : // Deserialize with some other external reference.
2770 : {
2771 : v8::Isolate::CreateParams params;
2772 5 : params.snapshot_blob = &blob;
2773 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
2774 5 : params.external_references = replaced_external_references;
2775 : // Test-appropriate equivalent of v8::Isolate::New.
2776 5 : v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2777 : {
2778 : v8::Isolate::Scope isolate_scope(isolate);
2779 10 : v8::HandleScope handle_scope(isolate);
2780 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2781 : v8::Context::Scope context_scope(context);
2782 5 : ExpectInt32("f()", 1337);
2783 : }
2784 5 : isolate->Dispose();
2785 : }
2786 :
2787 5 : CHECK_EQ(3, serializable_one_byte_resource.dispose_count());
2788 5 : CHECK_EQ(3, serializable_two_byte_resource.dispose_count());
2789 :
2790 5 : delete[] blob.data;
2791 5 : }
2792 :
2793 28342 : TEST(SnapshotCreatorShortExternalReferences) {
2794 : DisableAlwaysOpt();
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 : }
2834 :
2835 5 : v8::StartupData CreateSnapshotWithDefaultAndCustom() {
2836 5 : v8::SnapshotCreator creator(original_external_references);
2837 5 : v8::Isolate* isolate = creator.GetIsolate();
2838 : {
2839 5 : v8::HandleScope handle_scope(isolate);
2840 : {
2841 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2842 : v8::Context::Scope context_scope(context);
2843 : CompileRun("function f() { return 41; }");
2844 5 : creator.SetDefaultContext(context);
2845 5 : ExpectInt32("f()", 41);
2846 : }
2847 : {
2848 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2849 : v8::Context::Scope context_scope(context);
2850 : v8::Local<v8::FunctionTemplate> function_template =
2851 5 : v8::FunctionTemplate::New(isolate, SerializedCallback);
2852 : v8::Local<v8::Value> function =
2853 5 : function_template->GetFunction(context).ToLocalChecked();
2854 20 : CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
2855 : v8::Local<v8::ObjectTemplate> object_template =
2856 5 : v8::ObjectTemplate::New(isolate);
2857 5 : object_template->SetAccessor(v8_str("x"), AccessorForSerialization);
2858 : v8::Local<v8::Object> object =
2859 5 : object_template->NewInstance(context).ToLocalChecked();
2860 20 : CHECK(context->Global()->Set(context, v8_str("o"), object).FromJust());
2861 5 : ExpectInt32("f()", 42);
2862 5 : ExpectInt32("o.x", 2017);
2863 5 : creator.AddContext(context);
2864 5 : }
2865 : }
2866 5 : return creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
2867 : }
2868 :
2869 28342 : TEST(SnapshotCreatorNoExternalReferencesDefault) {
2870 : DisableAlwaysOpt();
2871 5 : v8::StartupData blob = CreateSnapshotWithDefaultAndCustom();
2872 :
2873 : // Deserialize with an incomplete list of external references.
2874 : {
2875 : v8::Isolate::CreateParams params;
2876 5 : params.snapshot_blob = &blob;
2877 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
2878 : params.external_references = nullptr;
2879 : // Test-appropriate equivalent of v8::Isolate::New.
2880 5 : v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2881 : {
2882 : v8::Isolate::Scope isolate_scope(isolate);
2883 10 : v8::HandleScope handle_scope(isolate);
2884 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2885 : v8::Context::Scope context_scope(context);
2886 5 : ExpectInt32("f()", 41);
2887 : }
2888 5 : isolate->Dispose();
2889 : }
2890 5 : delete[] blob.data;
2891 5 : }
2892 :
2893 5 : v8::StartupData CreateCustomSnapshotWithPreparseDataAndNoOuterScope() {
2894 5 : v8::SnapshotCreator creator;
2895 5 : v8::Isolate* isolate = creator.GetIsolate();
2896 : {
2897 5 : v8::HandleScope handle_scope(isolate);
2898 : {
2899 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2900 : v8::Context::Scope context_scope(context);
2901 : CompileRun(
2902 : "var foo = {\n"
2903 : " // This function is not top-level, but also has no outer scope.\n"
2904 : " bar: function(){\n"
2905 : " // Add an inner function so that the outer one has preparse\n"
2906 : " // scope data.\n"
2907 : " return function(){}\n"
2908 : " }\n"
2909 : "};\n");
2910 5 : creator.SetDefaultContext(context);
2911 5 : }
2912 : }
2913 5 : return creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
2914 : }
2915 :
2916 28342 : TEST(SnapshotCreatorPreparseDataAndNoOuterScope) {
2917 : DisableAlwaysOpt();
2918 5 : v8::StartupData blob = CreateCustomSnapshotWithPreparseDataAndNoOuterScope();
2919 :
2920 : // Deserialize with an incomplete list of external references.
2921 : {
2922 : v8::Isolate::CreateParams params;
2923 5 : params.snapshot_blob = &blob;
2924 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
2925 : // Test-appropriate equivalent of v8::Isolate::New.
2926 5 : v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2927 : {
2928 : v8::Isolate::Scope isolate_scope(isolate);
2929 10 : v8::HandleScope handle_scope(isolate);
2930 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2931 : v8::Context::Scope context_scope(context);
2932 : }
2933 5 : isolate->Dispose();
2934 : }
2935 5 : delete[] blob.data;
2936 5 : }
2937 :
2938 5 : v8::StartupData CreateCustomSnapshotArrayJoinWithKeep() {
2939 5 : v8::SnapshotCreator creator;
2940 5 : v8::Isolate* isolate = creator.GetIsolate();
2941 : {
2942 5 : v8::HandleScope handle_scope(isolate);
2943 : {
2944 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2945 : v8::Context::Scope context_scope(context);
2946 : CompileRun(
2947 : "[].join('');\n"
2948 : "function g() { return String([1,2,3]); }\n");
2949 5 : ExpectString("g()", "1,2,3");
2950 5 : creator.SetDefaultContext(context);
2951 5 : }
2952 : }
2953 5 : return creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kKeep);
2954 : }
2955 :
2956 28342 : TEST(SnapshotCreatorArrayJoinWithKeep) {
2957 : DisableAlwaysOpt();
2958 5 : v8::StartupData blob = CreateCustomSnapshotArrayJoinWithKeep();
2959 :
2960 : // Deserialize with an incomplete list of external references.
2961 : {
2962 : v8::Isolate::CreateParams params;
2963 5 : params.snapshot_blob = &blob;
2964 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
2965 : // Test-appropriate equivalent of v8::Isolate::New.
2966 5 : v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2967 : {
2968 : v8::Isolate::Scope isolate_scope(isolate);
2969 10 : v8::HandleScope handle_scope(isolate);
2970 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2971 : v8::Context::Scope context_scope(context);
2972 5 : ExpectString("g()", "1,2,3");
2973 : }
2974 5 : isolate->Dispose();
2975 : }
2976 5 : delete[] blob.data;
2977 5 : }
2978 :
2979 28337 : TEST(SnapshotCreatorNoExternalReferencesCustomFail1) {
2980 : DisableAlwaysOpt();
2981 0 : v8::StartupData blob = CreateSnapshotWithDefaultAndCustom();
2982 :
2983 : // Deserialize with an incomplete list of external references.
2984 : {
2985 : v8::Isolate::CreateParams params;
2986 0 : params.snapshot_blob = &blob;
2987 0 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
2988 : params.external_references = nullptr;
2989 : // Test-appropriate equivalent of v8::Isolate::New.
2990 0 : v8::Isolate* isolate = TestSerializer::NewIsolate(params);
2991 : {
2992 : v8::Isolate::Scope isolate_scope(isolate);
2993 0 : v8::HandleScope handle_scope(isolate);
2994 : v8::Local<v8::Context> context =
2995 0 : v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
2996 : v8::Context::Scope context_scope(context);
2997 0 : ExpectInt32("f()", 42);
2998 : }
2999 0 : isolate->Dispose();
3000 : }
3001 0 : delete[] blob.data;
3002 0 : }
3003 :
3004 28337 : TEST(SnapshotCreatorNoExternalReferencesCustomFail2) {
3005 : DisableAlwaysOpt();
3006 0 : v8::StartupData blob = CreateSnapshotWithDefaultAndCustom();
3007 :
3008 : // Deserialize with an incomplete list of external references.
3009 : {
3010 : v8::Isolate::CreateParams params;
3011 0 : params.snapshot_blob = &blob;
3012 0 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
3013 : params.external_references = nullptr;
3014 : // Test-appropriate equivalent of v8::Isolate::New.
3015 0 : v8::Isolate* isolate = TestSerializer::NewIsolate(params);
3016 : {
3017 : v8::Isolate::Scope isolate_scope(isolate);
3018 0 : v8::HandleScope handle_scope(isolate);
3019 : v8::Local<v8::Context> context =
3020 0 : v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
3021 : v8::Context::Scope context_scope(context);
3022 0 : ExpectInt32("o.x", 2017);
3023 : }
3024 0 : isolate->Dispose();
3025 : }
3026 0 : delete[] blob.data;
3027 0 : }
3028 :
3029 28337 : TEST(SnapshotCreatorUnknownExternalReferences) {
3030 : DisableAlwaysOpt();
3031 0 : v8::SnapshotCreator creator;
3032 0 : v8::Isolate* isolate = creator.GetIsolate();
3033 : {
3034 0 : v8::HandleScope handle_scope(isolate);
3035 0 : v8::Local<v8::Context> context = v8::Context::New(isolate);
3036 : v8::Context::Scope context_scope(context);
3037 :
3038 : v8::Local<v8::FunctionTemplate> callback =
3039 0 : v8::FunctionTemplate::New(isolate, SerializedCallback);
3040 : v8::Local<v8::Value> function =
3041 0 : callback->GetFunction(context).ToLocalChecked();
3042 0 : CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
3043 0 : ExpectInt32("f()", 42);
3044 :
3045 0 : creator.SetDefaultContext(context);
3046 : }
3047 : v8::StartupData blob =
3048 0 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3049 :
3050 0 : delete[] blob.data;
3051 0 : }
3052 :
3053 28342 : TEST(SnapshotCreatorTemplates) {
3054 : DisableAlwaysOpt();
3055 : v8::StartupData blob;
3056 :
3057 : {
3058 5 : InternalFieldData* a1 = new InternalFieldData{11};
3059 5 : InternalFieldData* b1 = new InternalFieldData{20};
3060 5 : InternalFieldData* c1 = new InternalFieldData{30};
3061 :
3062 5 : v8::SnapshotCreator creator(original_external_references);
3063 5 : v8::Isolate* isolate = creator.GetIsolate();
3064 : {
3065 5 : v8::HandleScope handle_scope(isolate);
3066 : v8::ExtensionConfiguration* no_extension = nullptr;
3067 : v8::Local<v8::ObjectTemplate> global_template =
3068 5 : v8::ObjectTemplate::New(isolate);
3069 : v8::Local<v8::External> external =
3070 5 : v8::External::New(isolate, &serialized_static_field);
3071 : v8::Local<v8::FunctionTemplate> callback =
3072 5 : v8::FunctionTemplate::New(isolate, SerializedCallback, external);
3073 10 : global_template->Set(v8_str("f"), callback);
3074 : v8::Local<v8::Context> context =
3075 5 : v8::Context::New(isolate, no_extension, global_template);
3076 5 : creator.SetDefaultContext(context);
3077 5 : context = v8::Context::New(isolate, no_extension, global_template);
3078 : v8::Local<v8::ObjectTemplate> object_template =
3079 5 : v8::ObjectTemplate::New(isolate);
3080 5 : object_template->SetInternalFieldCount(3);
3081 :
3082 : v8::Context::Scope context_scope(context);
3083 5 : ExpectInt32("f()", 42);
3084 5 : CHECK_EQ(315, serialized_static_field);
3085 :
3086 : v8::Local<v8::Object> a =
3087 5 : object_template->NewInstance(context).ToLocalChecked();
3088 : v8::Local<v8::Object> b =
3089 5 : object_template->NewInstance(context).ToLocalChecked();
3090 : v8::Local<v8::Object> c =
3091 5 : object_template->NewInstance(context).ToLocalChecked();
3092 : v8::Local<v8::External> null_external =
3093 5 : v8::External::New(isolate, nullptr);
3094 : v8::Local<v8::External> field_external =
3095 5 : v8::External::New(isolate, &serialized_static_field);
3096 :
3097 5 : a->SetInternalField(0, b);
3098 5 : b->SetInternalField(0, c);
3099 :
3100 5 : a->SetAlignedPointerInInternalField(1, a1);
3101 5 : b->SetAlignedPointerInInternalField(1, b1);
3102 5 : c->SetAlignedPointerInInternalField(1, c1);
3103 :
3104 5 : a->SetInternalField(2, null_external);
3105 5 : b->SetInternalField(2, field_external);
3106 5 : c->SetInternalField(2, v8_num(35));
3107 20 : CHECK(context->Global()->Set(context, v8_str("a"), a).FromJust());
3108 :
3109 5 : CHECK_EQ(0u,
3110 : creator.AddContext(context, v8::SerializeInternalFieldsCallback(
3111 : SerializeInternalFields,
3112 : reinterpret_cast<void*>(2000))));
3113 5 : CHECK_EQ(0u, creator.AddTemplate(callback));
3114 10 : CHECK_EQ(1u, creator.AddTemplate(global_template));
3115 : }
3116 : blob =
3117 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3118 :
3119 5 : delete a1;
3120 5 : delete b1;
3121 5 : delete c1;
3122 : }
3123 :
3124 : {
3125 : v8::Isolate::CreateParams params;
3126 5 : params.snapshot_blob = &blob;
3127 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
3128 5 : params.external_references = original_external_references;
3129 : // Test-appropriate equivalent of v8::Isolate::New.
3130 5 : v8::Isolate* isolate = TestSerializer::NewIsolate(params);
3131 : {
3132 : v8::Isolate::Scope isolate_scope(isolate);
3133 : {
3134 : // Create a new context without a new object template.
3135 5 : v8::HandleScope handle_scope(isolate);
3136 : v8::Local<v8::Context> context =
3137 : v8::Context::FromSnapshot(
3138 : isolate, 0,
3139 : v8::DeserializeInternalFieldsCallback(
3140 5 : DeserializeInternalFields, reinterpret_cast<void*>(2017)))
3141 5 : .ToLocalChecked();
3142 : v8::Context::Scope context_scope(context);
3143 5 : ExpectInt32("f()", 42);
3144 5 : CHECK_EQ(316, serialized_static_field);
3145 :
3146 : // Retrieve the snapshotted object template.
3147 : v8::Local<v8::ObjectTemplate> obj_template =
3148 5 : v8::ObjectTemplate::FromSnapshot(isolate, 1).ToLocalChecked();
3149 5 : CHECK(!obj_template.IsEmpty());
3150 : v8::Local<v8::Object> object =
3151 5 : obj_template->NewInstance(context).ToLocalChecked();
3152 20 : CHECK(context->Global()->Set(context, v8_str("o"), object).FromJust());
3153 5 : ExpectInt32("o.f()", 42);
3154 5 : CHECK_EQ(317, serialized_static_field);
3155 : // Check that it instantiates to the same prototype.
3156 : ExpectTrue("o.f.prototype === f.prototype");
3157 :
3158 : // Retrieve the snapshotted function template.
3159 : v8::Local<v8::FunctionTemplate> fun_template =
3160 5 : v8::FunctionTemplate::FromSnapshot(isolate, 0).ToLocalChecked();
3161 5 : CHECK(!fun_template.IsEmpty());
3162 : v8::Local<v8::Function> fun =
3163 5 : fun_template->GetFunction(context).ToLocalChecked();
3164 20 : CHECK(context->Global()->Set(context, v8_str("g"), fun).FromJust());
3165 5 : ExpectInt32("g()", 42);
3166 : // Check that it instantiates to the same prototype.
3167 : ExpectTrue("g.prototype === f.prototype");
3168 :
3169 : // Retrieve embedder fields.
3170 : v8::Local<v8::Object> a = context->Global()
3171 15 : ->Get(context, v8_str("a"))
3172 5 : .ToLocalChecked()
3173 : ->ToObject(context)
3174 5 : .ToLocalChecked();
3175 : v8::Local<v8::Object> b =
3176 5 : a->GetInternalField(0)->ToObject(context).ToLocalChecked();
3177 : v8::Local<v8::Object> c =
3178 5 : b->GetInternalField(0)->ToObject(context).ToLocalChecked();
3179 :
3180 : InternalFieldData* a1 = reinterpret_cast<InternalFieldData*>(
3181 : a->GetAlignedPointerFromInternalField(1));
3182 : v8::Local<v8::Value> a2 = a->GetInternalField(2);
3183 :
3184 : InternalFieldData* b1 = reinterpret_cast<InternalFieldData*>(
3185 : b->GetAlignedPointerFromInternalField(1));
3186 : v8::Local<v8::Value> b2 = b->GetInternalField(2);
3187 :
3188 : v8::Local<v8::Value> c0 = c->GetInternalField(0);
3189 : InternalFieldData* c1 = reinterpret_cast<InternalFieldData*>(
3190 : c->GetAlignedPointerFromInternalField(1));
3191 : v8::Local<v8::Value> c2 = c->GetInternalField(2);
3192 :
3193 5 : CHECK(c0->IsUndefined());
3194 :
3195 5 : CHECK_EQ(11u, a1->data);
3196 5 : CHECK_EQ(20u, b1->data);
3197 5 : CHECK_EQ(30u, c1->data);
3198 :
3199 5 : CHECK(a2->IsExternal());
3200 5 : CHECK_NULL(v8::Local<v8::External>::Cast(a2)->Value());
3201 5 : CHECK(b2->IsExternal());
3202 5 : CHECK_EQ(static_cast<void*>(&serialized_static_field),
3203 : v8::Local<v8::External>::Cast(b2)->Value());
3204 10 : CHECK(c2->IsInt32() && c2->Int32Value(context).FromJust() == 35);
3205 :
3206 : // Accessing out of bound returns empty MaybeHandle.
3207 10 : CHECK(v8::ObjectTemplate::FromSnapshot(isolate, 2).IsEmpty());
3208 10 : CHECK(v8::FunctionTemplate::FromSnapshot(isolate, 2).IsEmpty());
3209 10 : CHECK(v8::Context::FromSnapshot(isolate, 1).IsEmpty());
3210 :
3211 25 : for (auto data : deserialized_data) delete data;
3212 5 : deserialized_data.clear();
3213 : }
3214 : }
3215 5 : isolate->Dispose();
3216 : }
3217 5 : delete[] blob.data;
3218 5 : }
3219 :
3220 28342 : TEST(SnapshotCreatorAddData) {
3221 : DisableAlwaysOpt();
3222 : v8::StartupData blob;
3223 :
3224 : {
3225 5 : v8::SnapshotCreator creator;
3226 5 : v8::Isolate* isolate = creator.GetIsolate();
3227 : v8::Eternal<v8::Value> eternal_number;
3228 : v8::Persistent<v8::Value> persistent_number_1;
3229 : v8::Persistent<v8::Value> persistent_number_2;
3230 : v8::Persistent<v8::Context> persistent_context;
3231 : {
3232 5 : v8::HandleScope handle_scope(isolate);
3233 :
3234 5 : eternal_number.Set(isolate, v8_num(2017));
3235 10 : persistent_number_1.Reset(isolate, v8_num(2018));
3236 10 : persistent_number_2.Reset(isolate, v8_num(2019));
3237 :
3238 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
3239 5 : CHECK_EQ(0u, creator.AddData(context, persistent_number_2.Get(isolate)));
3240 5 : creator.SetDefaultContext(context);
3241 5 : context = v8::Context::New(isolate);
3242 : persistent_context.Reset(isolate, context);
3243 :
3244 : v8::Context::Scope context_scope(context);
3245 :
3246 : v8::Local<v8::Object> object = CompileRun("({ p: 12 })").As<v8::Object>();
3247 :
3248 : v8::Local<v8::ObjectTemplate> object_template =
3249 5 : v8::ObjectTemplate::New(isolate);
3250 5 : object_template->SetInternalFieldCount(3);
3251 :
3252 : v8::Local<v8::Private> private_symbol =
3253 5 : v8::Private::ForApi(isolate, v8_str("private_symbol"));
3254 :
3255 : v8::Local<v8::Signature> signature =
3256 5 : v8::Signature::New(isolate, v8::FunctionTemplate::New(isolate));
3257 :
3258 : v8::Local<v8::AccessorSignature> accessor_signature =
3259 : v8::AccessorSignature::New(isolate,
3260 5 : v8::FunctionTemplate::New(isolate));
3261 :
3262 5 : CHECK_EQ(0u, creator.AddData(context, object));
3263 10 : CHECK_EQ(1u, creator.AddData(context, v8_str("context-dependent")));
3264 5 : CHECK_EQ(2u, creator.AddData(context, persistent_number_1.Get(isolate)));
3265 5 : CHECK_EQ(3u, creator.AddData(context, object_template));
3266 5 : CHECK_EQ(4u, creator.AddData(context, persistent_context.Get(isolate)));
3267 5 : creator.AddContext(context);
3268 :
3269 10 : CHECK_EQ(0u, creator.AddData(v8_str("context-independent")));
3270 5 : CHECK_EQ(1u, creator.AddData(eternal_number.Get(isolate)));
3271 5 : CHECK_EQ(2u, creator.AddData(object_template));
3272 10 : CHECK_EQ(3u, creator.AddData(v8::FunctionTemplate::New(isolate)));
3273 5 : CHECK_EQ(4u, creator.AddData(private_symbol));
3274 5 : CHECK_EQ(5u, creator.AddData(signature));
3275 10 : CHECK_EQ(6u, creator.AddData(accessor_signature));
3276 : }
3277 :
3278 : blob =
3279 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3280 : }
3281 :
3282 : {
3283 : v8::Isolate::CreateParams params;
3284 5 : params.snapshot_blob = &blob;
3285 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
3286 : // Test-appropriate equivalent of v8::Isolate::New.
3287 5 : v8::Isolate* isolate = TestSerializer::NewIsolate(params);
3288 : {
3289 : v8::Isolate::Scope isolate_scope(isolate);
3290 10 : v8::HandleScope handle_scope(isolate);
3291 : v8::Local<v8::Context> context =
3292 10 : v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
3293 :
3294 : // Check serialized data on the context.
3295 : v8::Local<v8::Object> object =
3296 : context->GetDataFromSnapshotOnce<v8::Object>(0).ToLocalChecked();
3297 5 : CHECK(context->GetDataFromSnapshotOnce<v8::Object>(0).IsEmpty());
3298 20 : CHECK_EQ(12, object->Get(context, v8_str("p"))
3299 : .ToLocalChecked()
3300 : ->Int32Value(context)
3301 : .FromJust());
3302 :
3303 : v8::Local<v8::String> string =
3304 : context->GetDataFromSnapshotOnce<v8::String>(1).ToLocalChecked();
3305 5 : CHECK(context->GetDataFromSnapshotOnce<v8::String>(1).IsEmpty());
3306 15 : CHECK(string->Equals(context, v8_str("context-dependent")).FromJust());
3307 :
3308 : v8::Local<v8::Number> number =
3309 : context->GetDataFromSnapshotOnce<v8::Number>(2).ToLocalChecked();
3310 5 : CHECK(context->GetDataFromSnapshotOnce<v8::Number>(2).IsEmpty());
3311 10 : CHECK_EQ(2018, number->Int32Value(context).FromJust());
3312 :
3313 : v8::Local<v8::ObjectTemplate> templ =
3314 : context->GetDataFromSnapshotOnce<v8::ObjectTemplate>(3)
3315 : .ToLocalChecked();
3316 5 : CHECK(context->GetDataFromSnapshotOnce<v8::ObjectTemplate>(3).IsEmpty());
3317 5 : CHECK_EQ(3, templ->InternalFieldCount());
3318 :
3319 : v8::Local<v8::Context> serialized_context =
3320 : context->GetDataFromSnapshotOnce<v8::Context>(4).ToLocalChecked();
3321 5 : CHECK(context->GetDataFromSnapshotOnce<v8::Context>(4).IsEmpty());
3322 15 : CHECK_EQ(*v8::Utils::OpenHandle(*serialized_context),
3323 : *v8::Utils::OpenHandle(*context));
3324 :
3325 5 : CHECK(context->GetDataFromSnapshotOnce<v8::Value>(5).IsEmpty());
3326 :
3327 : // Check serialized data on the isolate.
3328 : string = isolate->GetDataFromSnapshotOnce<v8::String>(0).ToLocalChecked();
3329 5 : CHECK(context->GetDataFromSnapshotOnce<v8::String>(0).IsEmpty());
3330 15 : CHECK(string->Equals(context, v8_str("context-independent")).FromJust());
3331 :
3332 : number = isolate->GetDataFromSnapshotOnce<v8::Number>(1).ToLocalChecked();
3333 5 : CHECK(isolate->GetDataFromSnapshotOnce<v8::Number>(1).IsEmpty());
3334 10 : CHECK_EQ(2017, number->Int32Value(context).FromJust());
3335 :
3336 : templ = isolate->GetDataFromSnapshotOnce<v8::ObjectTemplate>(2)
3337 : .ToLocalChecked();
3338 5 : CHECK(isolate->GetDataFromSnapshotOnce<v8::ObjectTemplate>(2).IsEmpty());
3339 5 : CHECK_EQ(3, templ->InternalFieldCount());
3340 :
3341 : isolate->GetDataFromSnapshotOnce<v8::FunctionTemplate>(3)
3342 : .ToLocalChecked();
3343 5 : CHECK(
3344 : isolate->GetDataFromSnapshotOnce<v8::FunctionTemplate>(3).IsEmpty());
3345 :
3346 : isolate->GetDataFromSnapshotOnce<v8::Private>(4).ToLocalChecked();
3347 5 : CHECK(
3348 : isolate->GetDataFromSnapshotOnce<v8::Private>(4).IsEmpty());
3349 :
3350 : isolate->GetDataFromSnapshotOnce<v8::Signature>(5).ToLocalChecked();
3351 5 : CHECK(isolate->GetDataFromSnapshotOnce<v8::Signature>(5).IsEmpty());
3352 :
3353 : isolate->GetDataFromSnapshotOnce<v8::AccessorSignature>(6)
3354 : .ToLocalChecked();
3355 5 : CHECK(
3356 : isolate->GetDataFromSnapshotOnce<v8::AccessorSignature>(6).IsEmpty());
3357 :
3358 5 : CHECK(isolate->GetDataFromSnapshotOnce<v8::Value>(7).IsEmpty());
3359 : }
3360 5 : isolate->Dispose();
3361 : }
3362 : {
3363 5 : SnapshotCreator creator(nullptr, &blob);
3364 5 : v8::Isolate* isolate = creator.GetIsolate();
3365 : {
3366 : // Adding data to a snapshot replaces the list of existing data.
3367 5 : v8::HandleScope hscope(isolate);
3368 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
3369 5 : creator.SetDefaultContext(context);
3370 10 : context = v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
3371 : v8::Local<v8::String> string =
3372 : context->GetDataFromSnapshotOnce<v8::String>(1).ToLocalChecked();
3373 5 : CHECK(context->GetDataFromSnapshotOnce<v8::String>(1).IsEmpty());
3374 15 : CHECK(string->Equals(context, v8_str("context-dependent")).FromJust());
3375 : v8::Local<v8::Number> number =
3376 : isolate->GetDataFromSnapshotOnce<v8::Number>(1).ToLocalChecked();
3377 5 : CHECK(isolate->GetDataFromSnapshotOnce<v8::Number>(1).IsEmpty());
3378 10 : CHECK_EQ(2017, number->Int32Value(context).FromJust());
3379 :
3380 10 : CHECK_EQ(0u, creator.AddData(context, v8_num(2016)));
3381 5 : CHECK_EQ(0u, creator.AddContext(context));
3382 10 : CHECK_EQ(0u, creator.AddData(v8_str("stuff")));
3383 : }
3384 5 : delete[] blob.data;
3385 : blob =
3386 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3387 : }
3388 : {
3389 : v8::Isolate::CreateParams params;
3390 5 : params.snapshot_blob = &blob;
3391 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
3392 : // Test-appropriate equivalent of v8::Isolate::New.
3393 5 : v8::Isolate* isolate = TestSerializer::NewIsolate(params);
3394 : {
3395 : v8::Isolate::Scope isolate_scope(isolate);
3396 10 : v8::HandleScope handle_scope(isolate);
3397 :
3398 : // Context where we did not re-add data no longer has data.
3399 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
3400 5 : CHECK(context->GetDataFromSnapshotOnce<v8::Object>(0).IsEmpty());
3401 :
3402 : // Context where we re-added data has completely new ones.
3403 10 : context = v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
3404 : v8::Local<v8::Value> value =
3405 : context->GetDataFromSnapshotOnce<v8::Value>(0).ToLocalChecked();
3406 10 : CHECK_EQ(2016, value->Int32Value(context).FromJust());
3407 5 : CHECK(context->GetDataFromSnapshotOnce<v8::Value>(1).IsEmpty());
3408 :
3409 : // Ditto for the isolate.
3410 : v8::Local<v8::String> string =
3411 : isolate->GetDataFromSnapshotOnce<v8::String>(0).ToLocalChecked();
3412 15 : CHECK(string->Equals(context, v8_str("stuff")).FromJust());
3413 5 : CHECK(context->GetDataFromSnapshotOnce<v8::String>(1).IsEmpty());
3414 : }
3415 5 : isolate->Dispose();
3416 : }
3417 5 : delete[] blob.data;
3418 5 : }
3419 :
3420 28337 : TEST(SnapshotCreatorUnknownHandles) {
3421 : DisableAlwaysOpt();
3422 : v8::StartupData blob;
3423 :
3424 : {
3425 0 : v8::SnapshotCreator creator;
3426 0 : v8::Isolate* isolate = creator.GetIsolate();
3427 : v8::Eternal<v8::Value> eternal_number;
3428 : v8::Persistent<v8::Value> persistent_number;
3429 : {
3430 0 : v8::HandleScope handle_scope(isolate);
3431 :
3432 0 : eternal_number.Set(isolate, v8_num(2017));
3433 0 : persistent_number.Reset(isolate, v8_num(2018));
3434 :
3435 0 : v8::Local<v8::Context> context = v8::Context::New(isolate);
3436 0 : creator.SetDefaultContext(context);
3437 : }
3438 :
3439 : blob =
3440 0 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3441 : }
3442 0 : delete[] blob.data;
3443 0 : }
3444 :
3445 28342 : TEST(SnapshotCreatorIncludeGlobalProxy) {
3446 : DisableAlwaysOpt();
3447 : v8::StartupData blob;
3448 :
3449 : {
3450 5 : v8::SnapshotCreator creator(original_external_references);
3451 5 : v8::Isolate* isolate = creator.GetIsolate();
3452 : {
3453 : // Set default context. This context implicitly does *not* serialize
3454 : // the global proxy, and upon deserialization one has to be created
3455 : // in the bootstrapper from the global object template.
3456 : // Side effects from extensions are persisted though.
3457 5 : v8::HandleScope handle_scope(isolate);
3458 : v8::Local<v8::ObjectTemplate> global_template =
3459 5 : v8::ObjectTemplate::New(isolate);
3460 : v8::Local<v8::FunctionTemplate> callback =
3461 5 : v8::FunctionTemplate::New(isolate, SerializedCallback);
3462 10 : global_template->Set(v8_str("f"), callback);
3463 : global_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
3464 5 : NamedPropertyGetterForSerialization));
3465 : v8::Local<v8::Context> context =
3466 5 : v8::Context::New(isolate, nullptr, global_template);
3467 : v8::Context::Scope context_scope(context);
3468 : CompileRun(
3469 : "function h() { return 13; };"
3470 : "function i() { return 14; };"
3471 : "var o = { p: 7 };");
3472 5 : ExpectInt32("f()", 42);
3473 5 : ExpectInt32("h()", 13);
3474 5 : ExpectInt32("o.p", 7);
3475 5 : ExpectInt32("x", 2016);
3476 10 : creator.SetDefaultContext(context);
3477 : }
3478 : {
3479 : // Add additional context. This context implicitly *does* serialize
3480 : // the global proxy, and upon deserialization one has to be created
3481 : // in the bootstrapper from the global object template.
3482 : // Side effects from extensions are persisted.
3483 5 : v8::HandleScope handle_scope(isolate);
3484 : v8::Local<v8::ObjectTemplate> global_template =
3485 5 : v8::ObjectTemplate::New(isolate);
3486 : v8::Local<v8::FunctionTemplate> callback =
3487 5 : v8::FunctionTemplate::New(isolate, SerializedCallback);
3488 5 : global_template->SetInternalFieldCount(3);
3489 10 : global_template->Set(v8_str("f"), callback);
3490 : global_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
3491 5 : NamedPropertyGetterForSerialization));
3492 5 : global_template->SetAccessor(v8_str("y"), AccessorForSerialization);
3493 : v8::Local<v8::Private> priv =
3494 5 : v8::Private::ForApi(isolate, v8_str("cached"));
3495 : global_template->SetAccessorProperty(
3496 : v8_str("cached"),
3497 : v8::FunctionTemplate::NewWithCache(isolate, SerializedCallback, priv,
3498 10 : v8::Local<v8::Value>()));
3499 : v8::Local<v8::Context> context =
3500 5 : v8::Context::New(isolate, nullptr, global_template);
3501 : v8::Context::Scope context_scope(context);
3502 :
3503 20 : CHECK(context->Global()
3504 : ->SetPrivate(context, priv, v8_str("cached string"))
3505 : .FromJust());
3506 : v8::Local<v8::Private> hidden =
3507 5 : v8::Private::ForApi(isolate, v8_str("hidden"));
3508 20 : CHECK(context->Global()
3509 : ->SetPrivate(context, hidden, v8_str("hidden string"))
3510 : .FromJust());
3511 :
3512 5 : ExpectInt32("f()", 42);
3513 5 : ExpectInt32("x", 2016);
3514 5 : ExpectInt32("y", 2017);
3515 25 : CHECK(v8_str("hidden string")
3516 : ->Equals(context, context->Global()
3517 : ->GetPrivate(context, hidden)
3518 : .ToLocalChecked())
3519 : .FromJust());
3520 :
3521 5 : CHECK_EQ(0u,
3522 : creator.AddContext(context, v8::SerializeInternalFieldsCallback(
3523 : SerializeInternalFields,
3524 5 : reinterpret_cast<void*>(2016))));
3525 : }
3526 : blob =
3527 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3528 : }
3529 :
3530 : {
3531 : v8::Isolate::CreateParams params;
3532 5 : params.snapshot_blob = &blob;
3533 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
3534 5 : params.external_references = original_external_references;
3535 : // Test-appropriate equivalent of v8::Isolate::New.
3536 5 : v8::Isolate* isolate = TestSerializer::NewIsolate(params);
3537 : {
3538 : v8::Isolate::Scope isolate_scope(isolate);
3539 : // We can introduce new extensions, which could override functions already
3540 : // in the snapshot.
3541 : v8::Extension* extension = new v8::Extension("new extension",
3542 : "function i() { return 24; }"
3543 : "function j() { return 25; }"
3544 : "try {"
3545 : " if (o.p == 7) o.p++;"
3546 5 : "} catch {}");
3547 : extension->set_auto_enable(true);
3548 5 : v8::RegisterExtension(extension);
3549 : {
3550 : // Create a new context from default context snapshot. This will
3551 : // create a new global object from a new global object template
3552 : // without the interceptor.
3553 5 : v8::HandleScope handle_scope(isolate);
3554 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
3555 : v8::Context::Scope context_scope(context);
3556 5 : ExpectInt32("f()", 42);
3557 5 : ExpectInt32("h()", 13);
3558 5 : ExpectInt32("i()", 24);
3559 5 : ExpectInt32("j()", 25);
3560 5 : ExpectInt32("o.p", 8);
3561 10 : v8::TryCatch try_catch(isolate);
3562 5 : CHECK(CompileRun("x").IsEmpty());
3563 10 : CHECK(try_catch.HasCaught());
3564 : }
3565 : {
3566 : // Create a new context from first additional context snapshot. This
3567 : // will use the global object from the snapshot, including interceptor.
3568 5 : v8::HandleScope handle_scope(isolate);
3569 : v8::Local<v8::Context> context =
3570 : v8::Context::FromSnapshot(
3571 : isolate, 0,
3572 : v8::DeserializeInternalFieldsCallback(
3573 5 : DeserializeInternalFields, reinterpret_cast<void*>(2017)))
3574 5 : .ToLocalChecked();
3575 :
3576 : {
3577 : v8::Context::Scope context_scope(context);
3578 5 : ExpectInt32("f()", 42);
3579 5 : ExpectInt32("i()", 24);
3580 5 : ExpectInt32("j()", 25);
3581 5 : ExpectInt32("x", 2016);
3582 : v8::Local<v8::Private> hidden =
3583 5 : v8::Private::ForApi(isolate, v8_str("hidden"));
3584 25 : CHECK(v8_str("hidden string")
3585 : ->Equals(context, context->Global()
3586 : ->GetPrivate(context, hidden)
3587 : .ToLocalChecked())
3588 : .FromJust());
3589 5 : ExpectString("cached", "cached string");
3590 : }
3591 :
3592 5 : v8::Local<v8::Object> global = context->Global();
3593 5 : CHECK_EQ(3, global->InternalFieldCount());
3594 5 : context->DetachGlobal();
3595 :
3596 : // New context, but reuse global proxy.
3597 : v8::ExtensionConfiguration* no_extensions = nullptr;
3598 : v8::Local<v8::Context> context2 =
3599 : v8::Context::FromSnapshot(
3600 : isolate, 0,
3601 : v8::DeserializeInternalFieldsCallback(
3602 : DeserializeInternalFields, reinterpret_cast<void*>(2017)),
3603 5 : no_extensions, global)
3604 5 : .ToLocalChecked();
3605 : {
3606 : v8::Context::Scope context_scope(context2);
3607 5 : ExpectInt32("f()", 42);
3608 5 : ExpectInt32("i()", 24);
3609 5 : ExpectInt32("j()", 25);
3610 5 : ExpectInt32("x", 2016);
3611 : v8::Local<v8::Private> hidden =
3612 5 : v8::Private::ForApi(isolate, v8_str("hidden"));
3613 25 : CHECK(v8_str("hidden string")
3614 : ->Equals(context2, context2->Global()
3615 : ->GetPrivate(context2, hidden)
3616 : .ToLocalChecked())
3617 : .FromJust());
3618 :
3619 : // Set cached accessor property again.
3620 : v8::Local<v8::Private> priv =
3621 5 : v8::Private::ForApi(isolate, v8_str("cached"));
3622 20 : CHECK(context2->Global()
3623 : ->SetPrivate(context2, priv, v8_str("cached string 1"))
3624 : .FromJust());
3625 5 : ExpectString("cached", "cached string 1");
3626 : }
3627 :
3628 15 : CHECK(context2->Global()->Equals(context2, global).FromJust());
3629 : }
3630 : }
3631 5 : isolate->Dispose();
3632 : }
3633 5 : delete[] blob.data;
3634 5 : }
3635 :
3636 28342 : UNINITIALIZED_TEST(ReinitializeHashSeedNotRehashable) {
3637 : DisableAlwaysOpt();
3638 5 : i::FLAG_rehash_snapshot = true;
3639 5 : i::FLAG_hash_seed = 42;
3640 5 : i::FLAG_allow_natives_syntax = true;
3641 5 : DisableEmbeddedBlobRefcounting();
3642 : v8::StartupData blob;
3643 : {
3644 5 : v8::SnapshotCreator creator;
3645 5 : v8::Isolate* isolate = creator.GetIsolate();
3646 : {
3647 5 : v8::HandleScope handle_scope(isolate);
3648 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
3649 : v8::Context::Scope context_scope(context);
3650 : // Create an object with an ordered hash table.
3651 : CompileRun(
3652 : "var m = new Map();"
3653 : "m.set('a', 1);"
3654 : "m.set('b', 2);");
3655 5 : ExpectInt32("m.get('b')", 2);
3656 10 : creator.SetDefaultContext(context);
3657 : }
3658 : blob =
3659 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3660 : }
3661 :
3662 5 : i::FLAG_hash_seed = 1337;
3663 : v8::Isolate::CreateParams create_params;
3664 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
3665 5 : create_params.snapshot_blob = &blob;
3666 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
3667 : {
3668 : // Check that no rehashing has been performed.
3669 5 : CHECK_EQ(static_cast<uint64_t>(42),
3670 : reinterpret_cast<i::Isolate*>(isolate)->heap()->HashSeed());
3671 : v8::Isolate::Scope isolate_scope(isolate);
3672 10 : v8::HandleScope handle_scope(isolate);
3673 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
3674 5 : CHECK(!context.IsEmpty());
3675 : v8::Context::Scope context_scope(context);
3676 5 : ExpectInt32("m.get('b')", 2);
3677 : }
3678 5 : isolate->Dispose();
3679 5 : delete[] blob.data;
3680 5 : FreeCurrentEmbeddedBlob();
3681 5 : }
3682 :
3683 28342 : UNINITIALIZED_TEST(ReinitializeHashSeedRehashable) {
3684 : DisableAlwaysOpt();
3685 5 : i::FLAG_rehash_snapshot = true;
3686 5 : i::FLAG_hash_seed = 42;
3687 5 : i::FLAG_allow_natives_syntax = true;
3688 5 : DisableEmbeddedBlobRefcounting();
3689 : v8::StartupData blob;
3690 : {
3691 5 : v8::SnapshotCreator creator;
3692 5 : v8::Isolate* isolate = creator.GetIsolate();
3693 : {
3694 5 : v8::HandleScope handle_scope(isolate);
3695 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
3696 : v8::Context::Scope context_scope(context);
3697 : // Create dictionary mode object.
3698 : CompileRun(
3699 : "var a = new Array(10000);"
3700 : "%NormalizeElements(a);"
3701 : "a[133] = 1;"
3702 : "a[177] = 2;"
3703 : "a[971] = 3;"
3704 : "a[7997] = 4;"
3705 : "a[2111] = 5;"
3706 : "var o = {};"
3707 : "%OptimizeObjectForAddingMultipleProperties(o, 3);"
3708 : "o.a = 1;"
3709 : "o.b = 2;"
3710 : "o.c = 3;"
3711 : "var p = { foo: 1 };" // Test rehashing of transition arrays.
3712 : "p = JSON.parse('{\"foo\": {\"x\": 1}}');");
3713 : i::Handle<i::Object> i_a = v8::Utils::OpenHandle(*CompileRun("a"));
3714 5 : i::Handle<i::Object> i_o = v8::Utils::OpenHandle(*CompileRun("o"));
3715 10 : CHECK(i_a->IsJSArray());
3716 10 : CHECK(i_a->IsJSObject());
3717 15 : CHECK(!i::Handle<i::JSArray>::cast(i_a)->HasFastElements());
3718 10 : CHECK(!i::Handle<i::JSObject>::cast(i_o)->HasFastProperties());
3719 5 : ExpectInt32("a[2111]", 5);
3720 5 : ExpectInt32("o.c", 3);
3721 10 : creator.SetDefaultContext(context);
3722 : }
3723 : blob =
3724 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3725 : }
3726 :
3727 5 : i::FLAG_hash_seed = 1337;
3728 : v8::Isolate::CreateParams create_params;
3729 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
3730 5 : create_params.snapshot_blob = &blob;
3731 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
3732 : {
3733 : // Check that rehashing has been performed.
3734 5 : CHECK_EQ(static_cast<uint64_t>(1337),
3735 : reinterpret_cast<i::Isolate*>(isolate)->heap()->HashSeed());
3736 : v8::Isolate::Scope isolate_scope(isolate);
3737 10 : v8::HandleScope handle_scope(isolate);
3738 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
3739 5 : CHECK(!context.IsEmpty());
3740 : v8::Context::Scope context_scope(context);
3741 : i::Handle<i::Object> i_a = v8::Utils::OpenHandle(*CompileRun("a"));
3742 5 : i::Handle<i::Object> i_o = v8::Utils::OpenHandle(*CompileRun("o"));
3743 10 : CHECK(i_a->IsJSArray());
3744 10 : CHECK(i_a->IsJSObject());
3745 15 : CHECK(!i::Handle<i::JSArray>::cast(i_a)->HasFastElements());
3746 10 : CHECK(!i::Handle<i::JSObject>::cast(i_o)->HasFastProperties());
3747 5 : ExpectInt32("a[2111]", 5);
3748 5 : ExpectInt32("o.c", 3);
3749 : }
3750 5 : isolate->Dispose();
3751 5 : delete[] blob.data;
3752 5 : FreeCurrentEmbeddedBlob();
3753 5 : }
3754 :
3755 28342 : TEST(SerializationStats) {
3756 5 : FLAG_profile_deserialization = true;
3757 5 : FLAG_always_opt = false;
3758 : v8::StartupData blob = CreateSnapshotDataBlob();
3759 5 : delete[] blob.data;
3760 :
3761 : // Track the embedded blob size as well.
3762 : {
3763 : int embedded_blob_size = 0;
3764 : if (FLAG_embedded_builtins) {
3765 : i::EmbeddedData d = i::EmbeddedData::FromBlob();
3766 5 : embedded_blob_size = static_cast<int>(d.size());
3767 : }
3768 5 : PrintF("Embedded blob is %d bytes\n", embedded_blob_size);
3769 : }
3770 5 : }
3771 :
3772 10 : void CheckSFIsAreWeak(WeakFixedArray sfis, Isolate* isolate) {
3773 10 : CHECK_GT(sfis->length(), 0);
3774 : int no_of_weak = 0;
3775 50 : for (int i = 0; i < sfis->length(); ++i) {
3776 20 : MaybeObject maybe_object = sfis->Get(i);
3777 20 : HeapObject heap_object;
3778 20 : CHECK(maybe_object->IsWeakOrCleared() ||
3779 : (maybe_object->GetHeapObjectIfStrong(&heap_object) &&
3780 : heap_object->IsUndefined(isolate)));
3781 20 : if (maybe_object->IsWeak()) {
3782 15 : ++no_of_weak;
3783 : }
3784 : }
3785 10 : CHECK_GT(no_of_weak, 0);
3786 10 : }
3787 :
3788 28342 : TEST(WeakArraySerializizationInSnapshot) {
3789 : const char* code = "var my_func = function() { }";
3790 :
3791 : DisableAlwaysOpt();
3792 5 : i::FLAG_allow_natives_syntax = true;
3793 : v8::StartupData blob;
3794 : {
3795 5 : v8::SnapshotCreator creator;
3796 5 : v8::Isolate* isolate = creator.GetIsolate();
3797 : {
3798 5 : v8::HandleScope handle_scope(isolate);
3799 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
3800 : v8::Context::Scope context_scope(context);
3801 :
3802 : CompileRun(code);
3803 : creator.SetDefaultContext(
3804 : context, v8::SerializeInternalFieldsCallback(
3805 10 : SerializeInternalFields, reinterpret_cast<void*>(2016)));
3806 : }
3807 : blob =
3808 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3809 : }
3810 :
3811 : v8::Isolate::CreateParams create_params;
3812 5 : create_params.snapshot_blob = &blob;
3813 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
3814 5 : v8::Isolate* isolate = TestSerializer::NewIsolate(create_params);
3815 : {
3816 : v8::Isolate::Scope i_scope(isolate);
3817 10 : v8::HandleScope h_scope(isolate);
3818 : v8::Local<v8::Context> context = v8::Context::New(
3819 : isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
3820 : v8::MaybeLocal<v8::Value>(),
3821 : v8::DeserializeInternalFieldsCallback(DeserializeInternalFields,
3822 5 : reinterpret_cast<void*>(2017)));
3823 : v8::Context::Scope c_scope(context);
3824 :
3825 : v8::Local<v8::Value> x = CompileRun("my_func");
3826 5 : CHECK(x->IsFunction());
3827 : Handle<JSFunction> function =
3828 5 : Handle<JSFunction>::cast(v8::Utils::OpenHandle(*x));
3829 :
3830 : // Verify that the pointers in shared_function_infos are weak.
3831 : WeakFixedArray sfis =
3832 10 : Script::cast(function->shared()->script())->shared_function_infos();
3833 5 : CheckSFIsAreWeak(sfis, CcTest::i_isolate());
3834 : }
3835 5 : isolate->Dispose();
3836 5 : delete[] blob.data;
3837 5 : }
3838 :
3839 28342 : TEST(WeakArraySerializationInCodeCache) {
3840 5 : LocalContext context;
3841 5 : Isolate* isolate = CcTest::i_isolate();
3842 5 : isolate->compilation_cache()->Disable();
3843 :
3844 10 : v8::HandleScope scope(CcTest::isolate());
3845 :
3846 : const char* source = "function foo() { }";
3847 :
3848 : Handle<String> src = isolate->factory()
3849 : ->NewStringFromUtf8(CStrVector(source))
3850 10 : .ToHandleChecked();
3851 5 : ScriptData* cache = nullptr;
3852 :
3853 : CompileScriptAndProduceCache(isolate, src, src, &cache,
3854 5 : v8::ScriptCompiler::kNoCompileOptions);
3855 :
3856 : DisallowCompilation no_compile_expected(isolate);
3857 : Handle<SharedFunctionInfo> copy = CompileScript(
3858 5 : isolate, src, src, cache, v8::ScriptCompiler::kConsumeCodeCache);
3859 :
3860 : // Verify that the pointers in shared_function_infos are weak.
3861 10 : WeakFixedArray sfis = Script::cast(copy->script())->shared_function_infos();
3862 5 : CheckSFIsAreWeak(sfis, isolate);
3863 :
3864 15 : delete cache;
3865 5 : }
3866 :
3867 28342 : TEST(CachedCompileFunctionInContext) {
3868 : DisableAlwaysOpt();
3869 5 : LocalContext env;
3870 5 : Isolate* isolate = CcTest::i_isolate();
3871 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
3872 :
3873 10 : v8::HandleScope scope(CcTest::isolate());
3874 :
3875 5 : v8::Local<v8::String> source = v8_str("return x*x;");
3876 5 : v8::Local<v8::String> arg_str = v8_str("x");
3877 : ScriptCompiler::CachedData* cache;
3878 : {
3879 : v8::ScriptCompiler::Source script_source(source);
3880 : v8::Local<v8::Function> fun =
3881 : v8::ScriptCompiler::CompileFunctionInContext(
3882 : env.local(), &script_source, 1, &arg_str, 0, nullptr,
3883 5 : v8::ScriptCompiler::kEagerCompile)
3884 10 : .ToLocalChecked();
3885 5 : cache = v8::ScriptCompiler::CreateCodeCacheForFunction(fun);
3886 : }
3887 :
3888 : {
3889 : DisallowCompilation no_compile_expected(isolate);
3890 : v8::ScriptCompiler::Source script_source(source, cache);
3891 : v8::Local<v8::Function> fun =
3892 : v8::ScriptCompiler::CompileFunctionInContext(
3893 : env.local(), &script_source, 1, &arg_str, 0, nullptr,
3894 5 : v8::ScriptCompiler::kConsumeCodeCache)
3895 5 : .ToLocalChecked();
3896 5 : v8::Local<v8::Value> arg = v8_num(3);
3897 : v8::Local<v8::Value> result =
3898 15 : fun->Call(env.local(), v8::Undefined(CcTest::isolate()), 1, &arg)
3899 5 : .ToLocalChecked();
3900 10 : CHECK_EQ(9, result->Int32Value(env.local()).FromJust());
3901 5 : }
3902 5 : }
3903 :
3904 : } // namespace internal
3905 85011 : } // namespace v8
|