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.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/macro-assembler-inl.h"
42 : #include "src/objects-inl.h"
43 : #include "src/runtime/runtime.h"
44 : #include "src/snapshot/builtin-deserializer.h"
45 : #include "src/snapshot/builtin-serializer.h"
46 : #include "src/snapshot/code-serializer.h"
47 : #include "src/snapshot/natives.h"
48 : #include "src/snapshot/partial-deserializer.h"
49 : #include "src/snapshot/partial-serializer.h"
50 : #include "src/snapshot/snapshot.h"
51 : #include "src/snapshot/startup-deserializer.h"
52 : #include "src/snapshot/startup-serializer.h"
53 : #include "test/cctest/cctest.h"
54 : #include "test/cctest/heap/heap-utils.h"
55 : #include "test/cctest/setup-isolate-for-tests.h"
56 :
57 : namespace v8 {
58 : namespace internal {
59 :
60 0 : void DisableLazyDeserialization() {
61 : // UNINITIALIZED tests do not set up the isolate sufficiently for lazy
62 : // deserialization to work.
63 : // TODO(jgruber): Fix this. It may just be enough to set the snapshot_blob.
64 45 : FLAG_lazy_deserialization = false;
65 0 : }
66 :
67 0 : void DisableAlwaysOpt() {
68 : // Isolates prepared for serialization do not optimize. The only exception is
69 : // with the flag --always-opt.
70 130 : FLAG_always_opt = false;
71 0 : }
72 :
73 :
74 : // TestIsolate is used for testing isolate serialization.
75 : class TestIsolate : public Isolate {
76 : public:
77 30 : static v8::Isolate* NewInitialized(bool enable_serializer) {
78 30 : i::Isolate* isolate = new TestIsolate(enable_serializer);
79 60 : isolate->setup_delegate_ = new SetupIsolateDelegateForTests(true);
80 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
81 : v8::Isolate::Scope isolate_scope(v8_isolate);
82 30 : isolate->Init(nullptr);
83 30 : return v8_isolate;
84 : }
85 : // Wraps v8::Isolate::New, but with a TestIsolate under the hood.
86 : // Allows flexibility to bootstrap with or without snapshot even when
87 : // the production Isolate class has one or the other behavior baked in.
88 95 : static v8::Isolate* New(const v8::Isolate::CreateParams& params) {
89 95 : i::Isolate* isolate = new TestIsolate(false);
90 95 : bool create_heap_objects = params.snapshot_blob == nullptr;
91 : isolate->setup_delegate_ =
92 190 : new SetupIsolateDelegateForTests(create_heap_objects);
93 95 : return v8::IsolateNewImpl(isolate, params);
94 : }
95 155 : explicit TestIsolate(bool enable_serializer) : Isolate(enable_serializer) {
96 : set_array_buffer_allocator(CcTest::array_buffer_allocator());
97 : }
98 : void SetDeserializeFromSnapshot() {
99 60 : setup_delegate_ = new SetupIsolateDelegateForTests(false);
100 : }
101 : };
102 :
103 180 : static Vector<const byte> WritePayload(const Vector<const byte>& payload) {
104 : int length = payload.length();
105 90 : byte* blob = NewArray<byte>(length);
106 : memcpy(blob, payload.begin(), length);
107 90 : return Vector<const byte>(const_cast<const byte*>(blob), length);
108 : }
109 :
110 : // A convenience struct to simplify management of the two blobs required to
111 : // deserialize an isolate.
112 : struct StartupBlobs {
113 : Vector<const byte> startup;
114 : Vector<const byte> builtin;
115 :
116 40 : void Dispose() {
117 : startup.Dispose();
118 : builtin.Dispose();
119 40 : }
120 : };
121 :
122 30 : static StartupBlobs Serialize(v8::Isolate* isolate) {
123 : // We have to create one context. One reason for this is so that the builtins
124 : // can be loaded from v8natives.js and their addresses can be processed. This
125 : // will clear the pending fixups array, which would otherwise contain GC roots
126 : // that would confuse the serialization/deserialization process.
127 : v8::Isolate::Scope isolate_scope(isolate);
128 : {
129 30 : v8::HandleScope scope(isolate);
130 30 : v8::Context::New(isolate);
131 : }
132 :
133 : Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
134 : internal_isolate->heap()->CollectAllAvailableGarbage(
135 30 : i::GarbageCollectionReason::kTesting);
136 : StartupSerializer ser(internal_isolate,
137 60 : v8::SnapshotCreator::FunctionCodeHandling::kClear);
138 30 : ser.SerializeStrongReferences();
139 :
140 60 : i::BuiltinSerializer builtin_serializer(internal_isolate, &ser);
141 30 : builtin_serializer.SerializeBuiltins();
142 :
143 30 : ser.SerializeWeakReferencesAndDeferred();
144 30 : SnapshotData startup_snapshot(&ser);
145 30 : BuiltinSnapshotData builtin_snapshot(&builtin_serializer);
146 90 : return {WritePayload(startup_snapshot.RawData()),
147 90 : WritePayload(builtin_snapshot.RawData())};
148 : }
149 :
150 :
151 50 : Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head,
152 : Vector<const uint8_t> body,
153 : Vector<const uint8_t> tail, int repeats) {
154 100 : int source_length = head.length() + body.length() * repeats + tail.length();
155 50 : uint8_t* source = NewArray<uint8_t>(static_cast<size_t>(source_length));
156 50 : CopyChars(source, head.start(), head.length());
157 23105490 : for (int i = 0; i < repeats; i++) {
158 23105490 : CopyChars(source + head.length() + i * body.length(), body.start(),
159 46210980 : body.length());
160 : }
161 50 : CopyChars(source + head.length() + repeats * body.length(), tail.start(),
162 100 : tail.length());
163 : return Vector<const uint8_t>(const_cast<const uint8_t*>(source),
164 50 : source_length);
165 : }
166 :
167 30 : v8::Isolate* InitializeFromBlob(StartupBlobs& blobs) {
168 : v8::Isolate* v8_isolate = nullptr;
169 : {
170 : SnapshotData startup_snapshot(blobs.startup);
171 : BuiltinSnapshotData builtin_snapshot(blobs.builtin);
172 : StartupDeserializer deserializer(&startup_snapshot, &builtin_snapshot);
173 30 : TestIsolate* isolate = new TestIsolate(false);
174 : v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
175 : v8::Isolate::Scope isolate_scope(v8_isolate);
176 : isolate->SetDeserializeFromSnapshot();
177 30 : isolate->Init(&deserializer);
178 : }
179 30 : return v8_isolate;
180 : }
181 :
182 20 : static v8::Isolate* Deserialize(StartupBlobs& blobs) {
183 20 : v8::Isolate* isolate = InitializeFromBlob(blobs);
184 20 : CHECK(isolate);
185 20 : return isolate;
186 : }
187 :
188 :
189 15 : static void SanityCheck(v8::Isolate* v8_isolate) {
190 : Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
191 15 : v8::HandleScope scope(v8_isolate);
192 : #ifdef VERIFY_HEAP
193 : isolate->heap()->Verify();
194 : #endif
195 30 : CHECK(isolate->global_object()->IsJSObject());
196 30 : CHECK(isolate->native_context()->IsContext());
197 30 : CHECK(isolate->heap()->string_table()->IsStringTable());
198 15 : isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("Empty"));
199 15 : }
200 :
201 23723 : UNINITIALIZED_TEST(StartupSerializerOnce) {
202 : DisableLazyDeserialization();
203 : DisableAlwaysOpt();
204 5 : v8::Isolate* isolate = TestIsolate::NewInitialized(true);
205 5 : StartupBlobs blobs = Serialize(isolate);
206 5 : isolate->Dispose();
207 5 : isolate = Deserialize(blobs);
208 5 : blobs.Dispose();
209 : {
210 5 : v8::HandleScope handle_scope(isolate);
211 : v8::Isolate::Scope isolate_scope(isolate);
212 :
213 5 : v8::Local<v8::Context> env = v8::Context::New(isolate);
214 5 : env->Enter();
215 :
216 10 : SanityCheck(isolate);
217 : }
218 5 : isolate->Dispose();
219 5 : }
220 :
221 23723 : UNINITIALIZED_TEST(StartupSerializerRootMapDependencies) {
222 : DisableAlwaysOpt();
223 5 : v8::SnapshotCreator snapshot_creator;
224 5 : v8::Isolate* isolate = snapshot_creator.GetIsolate();
225 : {
226 : v8::Isolate::Scope isolate_scope(isolate);
227 10 : v8::HandleScope handle_scope(isolate);
228 : Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
229 : // Here is interesting retaining path:
230 : // - FreeSpaceMap
231 : // - Map for Map types itself
232 : // - NullValue
233 : // - Internalized one byte string
234 : // - Map for Internalized one byte string
235 : // - WeakCell
236 : // - TheHoleValue
237 : // - HeapNumber
238 : // HeapNumber objects require kDoubleUnaligned on 32-bit
239 : // platforms. So, without special measures we're risking to serialize
240 : // object, requiring alignment before FreeSpaceMap is fully serialized.
241 : v8::internal::Handle<Map> map(
242 5 : internal_isolate->heap()->one_byte_internalized_string_map());
243 5 : Map::WeakCellForMap(map);
244 : // Need to avoid DCHECKs inside SnapshotCreator.
245 5 : snapshot_creator.SetDefaultContext(v8::Context::New(isolate));
246 : }
247 :
248 : v8::StartupData startup_data = snapshot_creator.CreateBlob(
249 5 : v8::SnapshotCreator::FunctionCodeHandling::kKeep);
250 :
251 : v8::Isolate::CreateParams params;
252 5 : params.snapshot_blob = &startup_data;
253 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
254 5 : isolate = v8::Isolate::New(params);
255 :
256 : {
257 5 : v8::HandleScope handle_scope(isolate);
258 : v8::Isolate::Scope isolate_scope(isolate);
259 :
260 5 : v8::Local<v8::Context> env = v8::Context::New(isolate);
261 5 : env->Enter();
262 :
263 10 : SanityCheck(isolate);
264 : }
265 5 : isolate->Dispose();
266 5 : delete[] startup_data.data;
267 5 : }
268 :
269 23723 : UNINITIALIZED_TEST(StartupSerializerTwice) {
270 : DisableLazyDeserialization();
271 : DisableAlwaysOpt();
272 5 : v8::Isolate* isolate = TestIsolate::NewInitialized(true);
273 5 : StartupBlobs blobs1 = Serialize(isolate);
274 5 : StartupBlobs blobs2 = Serialize(isolate);
275 5 : isolate->Dispose();
276 5 : blobs1.Dispose();
277 5 : isolate = Deserialize(blobs2);
278 5 : blobs2.Dispose();
279 : {
280 : v8::Isolate::Scope isolate_scope(isolate);
281 10 : v8::HandleScope handle_scope(isolate);
282 :
283 5 : v8::Local<v8::Context> env = v8::Context::New(isolate);
284 5 : env->Enter();
285 :
286 5 : SanityCheck(isolate);
287 : }
288 5 : isolate->Dispose();
289 5 : }
290 :
291 23723 : UNINITIALIZED_TEST(StartupSerializerOnceRunScript) {
292 : DisableLazyDeserialization();
293 : DisableAlwaysOpt();
294 5 : v8::Isolate* isolate = TestIsolate::NewInitialized(true);
295 5 : StartupBlobs blobs = Serialize(isolate);
296 5 : isolate->Dispose();
297 5 : isolate = Deserialize(blobs);
298 5 : blobs.Dispose();
299 : {
300 : v8::Isolate::Scope isolate_scope(isolate);
301 10 : v8::HandleScope handle_scope(isolate);
302 :
303 :
304 5 : v8::Local<v8::Context> env = v8::Context::New(isolate);
305 5 : env->Enter();
306 :
307 : const char* c_source = "\"1234\".length";
308 : v8::Local<v8::Script> script = v8_compile(c_source);
309 5 : v8::Maybe<int32_t> result = script->Run(isolate->GetCurrentContext())
310 5 : .ToLocalChecked()
311 10 : ->Int32Value(isolate->GetCurrentContext());
312 5 : CHECK_EQ(4, result.FromJust());
313 : }
314 5 : isolate->Dispose();
315 5 : }
316 :
317 23723 : UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) {
318 : DisableLazyDeserialization();
319 : DisableAlwaysOpt();
320 5 : v8::Isolate* isolate = TestIsolate::NewInitialized(true);
321 5 : StartupBlobs blobs1 = Serialize(isolate);
322 5 : StartupBlobs blobs2 = Serialize(isolate);
323 5 : isolate->Dispose();
324 5 : blobs1.Dispose();
325 5 : isolate = Deserialize(blobs2);
326 5 : blobs2.Dispose();
327 : {
328 : v8::Isolate::Scope isolate_scope(isolate);
329 10 : v8::HandleScope handle_scope(isolate);
330 :
331 5 : v8::Local<v8::Context> env = v8::Context::New(isolate);
332 5 : env->Enter();
333 :
334 : const char* c_source = "\"1234\".length";
335 : v8::Local<v8::Script> script = v8_compile(c_source);
336 5 : v8::Maybe<int32_t> result = script->Run(isolate->GetCurrentContext())
337 5 : .ToLocalChecked()
338 10 : ->Int32Value(isolate->GetCurrentContext());
339 5 : CHECK_EQ(4, result.FromJust());
340 : }
341 5 : isolate->Dispose();
342 5 : }
343 :
344 5 : static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
345 : Vector<const byte>* builtin_blob_out,
346 : Vector<const byte>* partial_blob_out) {
347 5 : v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true);
348 : Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
349 5 : Heap* heap = isolate->heap();
350 : {
351 : v8::Isolate::Scope isolate_scope(v8_isolate);
352 :
353 : v8::Persistent<v8::Context> env;
354 : {
355 : HandleScope scope(isolate);
356 5 : env.Reset(v8_isolate, v8::Context::New(v8_isolate));
357 : }
358 5 : CHECK(!env.IsEmpty());
359 : {
360 5 : v8::HandleScope handle_scope(v8_isolate);
361 5 : v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
362 : }
363 :
364 : // If we don't do this then we end up with a stray root pointing at the
365 : // context even after we have disposed of env.
366 5 : heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
367 :
368 : {
369 5 : v8::HandleScope handle_scope(v8_isolate);
370 5 : v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
371 : }
372 :
373 5 : i::Object* raw_context = *v8::Utils::OpenPersistent(env);
374 :
375 : env.Reset();
376 :
377 : SnapshotByteSink startup_sink;
378 : StartupSerializer startup_serializer(
379 10 : isolate, v8::SnapshotCreator::FunctionCodeHandling::kClear);
380 5 : startup_serializer.SerializeStrongReferences();
381 :
382 : SnapshotByteSink partial_sink;
383 : PartialSerializer partial_serializer(isolate, &startup_serializer,
384 10 : v8::SerializeInternalFieldsCallback());
385 5 : partial_serializer.Serialize(&raw_context, false);
386 :
387 10 : i::BuiltinSerializer builtin_serializer(isolate, &startup_serializer);
388 5 : builtin_serializer.SerializeBuiltins();
389 :
390 5 : startup_serializer.SerializeWeakReferencesAndDeferred();
391 :
392 5 : SnapshotData startup_snapshot(&startup_serializer);
393 5 : BuiltinSnapshotData builtin_snapshot(&builtin_serializer);
394 5 : SnapshotData partial_snapshot(&partial_serializer);
395 :
396 10 : *partial_blob_out = WritePayload(partial_snapshot.RawData());
397 10 : *builtin_blob_out = WritePayload(builtin_snapshot.RawData());
398 10 : *startup_blob_out = WritePayload(startup_snapshot.RawData());
399 : }
400 5 : v8_isolate->Dispose();
401 5 : }
402 :
403 23723 : UNINITIALIZED_TEST(PartialSerializerContext) {
404 : DisableLazyDeserialization();
405 : DisableAlwaysOpt();
406 5 : Vector<const byte> startup_blob;
407 5 : Vector<const byte> builtin_blob;
408 5 : Vector<const byte> partial_blob;
409 5 : PartiallySerializeContext(&startup_blob, &builtin_blob, &partial_blob);
410 :
411 5 : StartupBlobs blobs = {startup_blob, builtin_blob};
412 5 : v8::Isolate* v8_isolate = InitializeFromBlob(blobs);
413 5 : CHECK(v8_isolate);
414 5 : blobs.Dispose();
415 : {
416 : v8::Isolate::Scope isolate_scope(v8_isolate);
417 :
418 : Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
419 : HandleScope handle_scope(isolate);
420 : Handle<Object> root;
421 : Handle<JSGlobalProxy> global_proxy =
422 : isolate->factory()->NewUninitializedJSGlobalProxy(
423 5 : JSGlobalProxy::SizeWithEmbedderFields(0));
424 : {
425 : SnapshotData snapshot_data(partial_blob);
426 : root = PartialDeserializer::DeserializeContext(
427 : isolate, &snapshot_data, false, global_proxy,
428 5 : v8::DeserializeInternalFieldsCallback())
429 10 : .ToHandleChecked();
430 5 : CHECK(root->IsContext());
431 10 : CHECK(Handle<Context>::cast(root)->global_proxy() == *global_proxy);
432 : }
433 :
434 : Handle<Object> root2;
435 : {
436 : SnapshotData snapshot_data(partial_blob);
437 : root2 = PartialDeserializer::DeserializeContext(
438 : isolate, &snapshot_data, false, global_proxy,
439 5 : v8::DeserializeInternalFieldsCallback())
440 10 : .ToHandleChecked();
441 5 : CHECK(root2->IsContext());
442 5 : CHECK(!root.is_identical_to(root2));
443 : }
444 : partial_blob.Dispose();
445 : }
446 5 : v8_isolate->Dispose();
447 5 : }
448 :
449 5 : static void PartiallySerializeCustomContext(
450 : Vector<const byte>* startup_blob_out, Vector<const byte>* builtin_blob_out,
451 : Vector<const byte>* partial_blob_out) {
452 5 : v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true);
453 : Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
454 : {
455 : v8::Isolate::Scope isolate_scope(v8_isolate);
456 :
457 : v8::Persistent<v8::Context> env;
458 : {
459 : HandleScope scope(isolate);
460 10 : env.Reset(v8_isolate, v8::Context::New(v8_isolate));
461 : }
462 5 : CHECK(!env.IsEmpty());
463 : {
464 5 : v8::HandleScope handle_scope(v8_isolate);
465 5 : v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
466 : // After execution, e's function context refers to the global object.
467 : CompileRun(
468 : "var e;"
469 : "(function() {"
470 : " e = function(s) { return eval (s); }"
471 : "})();"
472 : "var o = this;"
473 : "var r = Math.random();"
474 : "var c = Math.sin(0) + Math.cos(0);"
475 : "var f = (function(a, b) { return a + b; }).bind(1, 2, 3);"
476 : "var s = parseInt('12345');");
477 :
478 : Vector<const uint8_t> source = ConstructSource(
479 : STATIC_CHAR_VECTOR("function g() { return [,"),
480 : STATIC_CHAR_VECTOR("1,"),
481 5 : STATIC_CHAR_VECTOR("];} a = g(); b = g(); b.push(1);"), 100000);
482 : v8::MaybeLocal<v8::String> source_str = v8::String::NewFromOneByte(
483 : v8_isolate, source.start(), v8::NewStringType::kNormal,
484 5 : source.length());
485 5 : CompileRun(source_str.ToLocalChecked());
486 5 : source.Dispose();
487 : }
488 : // If we don't do this then we end up with a stray root pointing at the
489 : // context even after we have disposed of env.
490 : isolate->heap()->CollectAllAvailableGarbage(
491 5 : i::GarbageCollectionReason::kTesting);
492 :
493 : {
494 5 : v8::HandleScope handle_scope(v8_isolate);
495 5 : v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
496 : }
497 :
498 5 : i::Object* raw_context = *v8::Utils::OpenPersistent(env);
499 :
500 : env.Reset();
501 :
502 : SnapshotByteSink startup_sink;
503 : StartupSerializer startup_serializer(
504 10 : isolate, v8::SnapshotCreator::FunctionCodeHandling::kClear);
505 5 : startup_serializer.SerializeStrongReferences();
506 :
507 : SnapshotByteSink partial_sink;
508 : PartialSerializer partial_serializer(isolate, &startup_serializer,
509 10 : v8::SerializeInternalFieldsCallback());
510 5 : partial_serializer.Serialize(&raw_context, false);
511 :
512 10 : i::BuiltinSerializer builtin_serializer(isolate, &startup_serializer);
513 5 : builtin_serializer.SerializeBuiltins();
514 :
515 5 : startup_serializer.SerializeWeakReferencesAndDeferred();
516 :
517 5 : SnapshotData startup_snapshot(&startup_serializer);
518 5 : BuiltinSnapshotData builtin_snapshot(&builtin_serializer);
519 5 : SnapshotData partial_snapshot(&partial_serializer);
520 :
521 10 : *partial_blob_out = WritePayload(partial_snapshot.RawData());
522 10 : *builtin_blob_out = WritePayload(builtin_snapshot.RawData());
523 10 : *startup_blob_out = WritePayload(startup_snapshot.RawData());
524 : }
525 5 : v8_isolate->Dispose();
526 5 : }
527 :
528 23723 : UNINITIALIZED_TEST(PartialSerializerCustomContext) {
529 : DisableLazyDeserialization();
530 : DisableAlwaysOpt();
531 5 : Vector<const byte> startup_blob;
532 5 : Vector<const byte> builtin_blob;
533 5 : Vector<const byte> partial_blob;
534 5 : PartiallySerializeCustomContext(&startup_blob, &builtin_blob, &partial_blob);
535 :
536 5 : StartupBlobs blobs = {startup_blob, builtin_blob};
537 5 : v8::Isolate* v8_isolate = InitializeFromBlob(blobs);
538 5 : CHECK(v8_isolate);
539 5 : blobs.Dispose();
540 : {
541 : v8::Isolate::Scope isolate_scope(v8_isolate);
542 :
543 : Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
544 : HandleScope handle_scope(isolate);
545 : Handle<Object> root;
546 : Handle<JSGlobalProxy> global_proxy =
547 : isolate->factory()->NewUninitializedJSGlobalProxy(
548 5 : JSGlobalProxy::SizeWithEmbedderFields(0));
549 : {
550 : SnapshotData snapshot_data(partial_blob);
551 : root = PartialDeserializer::DeserializeContext(
552 : isolate, &snapshot_data, false, global_proxy,
553 5 : v8::DeserializeInternalFieldsCallback())
554 10 : .ToHandleChecked();
555 5 : CHECK(root->IsContext());
556 : Handle<Context> context = Handle<Context>::cast(root);
557 :
558 : // Add context to the weak native context list
559 : context->set(Context::NEXT_CONTEXT_LINK,
560 : isolate->heap()->native_contexts_list(),
561 10 : UPDATE_WEAK_WRITE_BARRIER);
562 : isolate->heap()->set_native_contexts_list(*context);
563 :
564 10 : CHECK(context->global_proxy() == *global_proxy);
565 5 : Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o");
566 5 : Handle<JSObject> global_object(context->global_object(), isolate);
567 5 : Handle<Object> property = JSReceiver::GetDataProperty(global_object, o);
568 5 : CHECK(property.is_identical_to(global_proxy));
569 :
570 : v8::Local<v8::Context> v8_context = v8::Utils::ToLocal(context);
571 : v8::Context::Scope context_scope(v8_context);
572 : double r = CompileRun("r")
573 5 : ->ToNumber(v8_isolate->GetCurrentContext())
574 5 : .ToLocalChecked()
575 5 : ->Value();
576 5 : CHECK(0.0 <= r && r < 1.0);
577 : // Math.random still works.
578 : double random = CompileRun("Math.random()")
579 5 : ->ToNumber(v8_isolate->GetCurrentContext())
580 5 : .ToLocalChecked()
581 5 : ->Value();
582 5 : CHECK(0.0 <= random && random < 1.0);
583 : double c = CompileRun("c")
584 5 : ->ToNumber(v8_isolate->GetCurrentContext())
585 5 : .ToLocalChecked()
586 5 : ->Value();
587 5 : CHECK_EQ(1, c);
588 : int f = CompileRun("f()")
589 5 : ->ToNumber(v8_isolate->GetCurrentContext())
590 5 : .ToLocalChecked()
591 5 : ->Int32Value(v8_isolate->GetCurrentContext())
592 10 : .FromJust();
593 5 : CHECK_EQ(5, f);
594 : f = CompileRun("e('f()')")
595 5 : ->ToNumber(v8_isolate->GetCurrentContext())
596 5 : .ToLocalChecked()
597 5 : ->Int32Value(v8_isolate->GetCurrentContext())
598 10 : .FromJust();
599 5 : CHECK_EQ(5, f);
600 : v8::Local<v8::String> s = CompileRun("s")
601 5 : ->ToString(v8_isolate->GetCurrentContext())
602 5 : .ToLocalChecked();
603 15 : CHECK(s->Equals(v8_isolate->GetCurrentContext(), v8_str("12345"))
604 : .FromJust());
605 : int a = CompileRun("a.length")
606 5 : ->ToNumber(v8_isolate->GetCurrentContext())
607 5 : .ToLocalChecked()
608 5 : ->Int32Value(v8_isolate->GetCurrentContext())
609 10 : .FromJust();
610 5 : CHECK_EQ(100001, a);
611 : int b = CompileRun("b.length")
612 5 : ->ToNumber(v8_isolate->GetCurrentContext())
613 5 : .ToLocalChecked()
614 5 : ->Int32Value(v8_isolate->GetCurrentContext())
615 10 : .FromJust();
616 5 : CHECK_EQ(100002, b);
617 : }
618 : partial_blob.Dispose();
619 : }
620 5 : v8_isolate->Dispose();
621 5 : }
622 :
623 23723 : TEST(CustomSnapshotDataBlob1) {
624 : DisableAlwaysOpt();
625 : const char* source1 = "function f() { return 42; }";
626 :
627 5 : v8::StartupData data1 = v8::V8::CreateSnapshotDataBlob(source1);
628 :
629 : v8::Isolate::CreateParams params1;
630 5 : params1.snapshot_blob = &data1;
631 5 : params1.array_buffer_allocator = CcTest::array_buffer_allocator();
632 :
633 : // Test-appropriate equivalent of v8::Isolate::New.
634 5 : v8::Isolate* isolate1 = TestIsolate::New(params1);
635 : {
636 : v8::Isolate::Scope i_scope(isolate1);
637 10 : v8::HandleScope h_scope(isolate1);
638 5 : v8::Local<v8::Context> context = v8::Context::New(isolate1);
639 5 : delete[] data1.data; // We can dispose of the snapshot blob now.
640 : v8::Context::Scope c_scope(context);
641 : v8::Maybe<int32_t> result =
642 10 : CompileRun("f()")->Int32Value(isolate1->GetCurrentContext());
643 5 : CHECK_EQ(42, result.FromJust());
644 5 : CHECK(CompileRun("this.g")->IsUndefined());
645 : }
646 5 : isolate1->Dispose();
647 5 : }
648 :
649 : struct InternalFieldData {
650 : uint32_t data;
651 : };
652 :
653 215 : v8::StartupData SerializeInternalFields(v8::Local<v8::Object> holder, int index,
654 : void* data) {
655 215 : CHECK_EQ(reinterpret_cast<void*>(2016), data);
656 : InternalFieldData* embedder_field = static_cast<InternalFieldData*>(
657 : holder->GetAlignedPointerFromInternalField(index));
658 215 : if (embedder_field == nullptr) return {nullptr, 0};
659 : int size = sizeof(*embedder_field);
660 15 : char* payload = new char[size];
661 : // We simply use memcpy to serialize the content.
662 : memcpy(payload, embedder_field, size);
663 15 : return {payload, size};
664 : }
665 :
666 23718 : std::vector<InternalFieldData*> deserialized_data;
667 :
668 215 : void DeserializeInternalFields(v8::Local<v8::Object> holder, int index,
669 : v8::StartupData payload, void* data) {
670 215 : if (payload.raw_size == 0) {
671 200 : holder->SetAlignedPointerInInternalField(index, nullptr);
672 415 : return;
673 : }
674 15 : CHECK_EQ(reinterpret_cast<void*>(2017), data);
675 15 : InternalFieldData* embedder_field = new InternalFieldData{0};
676 15 : memcpy(embedder_field, payload.data, payload.raw_size);
677 15 : holder->SetAlignedPointerInInternalField(index, embedder_field);
678 15 : deserialized_data.push_back(embedder_field);
679 : }
680 :
681 : typedef std::vector<std::tuple<const char*, int32_t>> Int32Expectations;
682 :
683 50 : void TestInt32Expectations(const Int32Expectations& expectations) {
684 300 : for (const auto& e : expectations) {
685 200 : ExpectInt32(std::get<0>(e), std::get<1>(e));
686 : }
687 50 : }
688 :
689 15 : void TypedArrayTestHelper(const char* code,
690 : const Int32Expectations& expectations) {
691 : DisableAlwaysOpt();
692 15 : i::FLAG_allow_natives_syntax = true;
693 : v8::StartupData blob;
694 : {
695 15 : v8::SnapshotCreator creator;
696 15 : v8::Isolate* isolate = creator.GetIsolate();
697 : {
698 15 : v8::HandleScope handle_scope(isolate);
699 15 : v8::Local<v8::Context> context = v8::Context::New(isolate);
700 : v8::Context::Scope context_scope(context);
701 :
702 : CompileRun(code);
703 15 : TestInt32Expectations(expectations);
704 : creator.SetDefaultContext(
705 : context, v8::SerializeInternalFieldsCallback(
706 30 : SerializeInternalFields, reinterpret_cast<void*>(2016)));
707 : }
708 : blob =
709 15 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
710 : }
711 :
712 : v8::Isolate::CreateParams create_params;
713 15 : create_params.snapshot_blob = &blob;
714 15 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
715 15 : v8::Isolate* isolate = TestIsolate::New(create_params);
716 : {
717 : v8::Isolate::Scope i_scope(isolate);
718 30 : v8::HandleScope h_scope(isolate);
719 : v8::Local<v8::Context> context = v8::Context::New(
720 : isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
721 : v8::MaybeLocal<v8::Value>(),
722 : v8::DeserializeInternalFieldsCallback(DeserializeInternalFields,
723 15 : reinterpret_cast<void*>(2017)));
724 15 : delete[] blob.data; // We can dispose of the snapshot blob now.
725 15 : CHECK(deserialized_data.empty()); // We do not expect any embedder data.
726 : v8::Context::Scope c_scope(context);
727 15 : TestInt32Expectations(expectations);
728 : }
729 15 : isolate->Dispose();
730 15 : }
731 :
732 23723 : TEST(CustomSnapshotDataBlobWithOffHeapTypedArray) {
733 : const char* code =
734 : "var x = new Uint8Array(128);"
735 : "x[0] = 12;"
736 : "var arr = new Array(17);"
737 : "arr[1] = 24;"
738 : "var y = new Uint32Array(arr);"
739 : "var buffer = new ArrayBuffer(128);"
740 : "var z = new Int16Array(buffer);"
741 : "z[0] = 48;";
742 : Int32Expectations expectations = {std::make_tuple("x[0]", 12),
743 : std::make_tuple("y[1]", 24),
744 5 : std::make_tuple("z[0]", 48)};
745 :
746 5 : TypedArrayTestHelper(code, expectations);
747 5 : }
748 :
749 23723 : TEST(CustomSnapshotDataBlobSharedArrayBuffer) {
750 : const char* code =
751 : "var x = new Int32Array([12, 24, 48, 96]);"
752 : "var y = new Uint8Array(x.buffer)";
753 : Int32Expectations expectations = {
754 : std::make_tuple("x[0]", 12),
755 : std::make_tuple("x[1]", 24),
756 : #if !V8_TARGET_BIG_ENDIAN
757 : std::make_tuple("y[0]", 12),
758 : std::make_tuple("y[1]", 0),
759 : std::make_tuple("y[2]", 0),
760 : std::make_tuple("y[3]", 0),
761 : std::make_tuple("y[4]", 24)
762 : #else
763 : std::make_tuple("y[3]", 12),
764 : std::make_tuple("y[2]", 0),
765 : std::make_tuple("y[1]", 0),
766 : std::make_tuple("y[0]", 0),
767 : std::make_tuple("y[7]", 24)
768 : #endif
769 5 : };
770 :
771 5 : TypedArrayTestHelper(code, expectations);
772 5 : }
773 :
774 23723 : TEST(CustomSnapshotDataBlobDataView) {
775 : const char* code =
776 : "var x = new Int8Array([1, 2, 3, 4]);"
777 : "var v = new DataView(x.buffer)";
778 : Int32Expectations expectations = {std::make_tuple("v.getInt8(0)", 1),
779 : std::make_tuple("v.getInt8(1)", 2),
780 : std::make_tuple("v.getInt16(0)", 258),
781 5 : std::make_tuple("v.getInt16(1)", 515)};
782 :
783 5 : TypedArrayTestHelper(code, expectations);
784 5 : }
785 :
786 23723 : TEST(CustomSnapshotDataBlobNeuteredArrayBuffer) {
787 : const char* code =
788 : "var x = new Int16Array([12, 24, 48]);"
789 : "%ArrayBufferNeuter(x.buffer);";
790 : Int32Expectations expectations = {std::make_tuple("x.buffer.byteLength", 0),
791 5 : std::make_tuple("x.length", 0)};
792 :
793 : DisableLazyDeserialization();
794 : DisableAlwaysOpt();
795 5 : i::FLAG_allow_natives_syntax = true;
796 : v8::StartupData blob;
797 : {
798 5 : v8::SnapshotCreator creator;
799 5 : v8::Isolate* isolate = creator.GetIsolate();
800 : {
801 5 : v8::HandleScope handle_scope(isolate);
802 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
803 : v8::Context::Scope context_scope(context);
804 :
805 : CompileRun(code);
806 5 : TestInt32Expectations(expectations);
807 : creator.SetDefaultContext(
808 : context, v8::SerializeInternalFieldsCallback(
809 10 : SerializeInternalFields, reinterpret_cast<void*>(2016)));
810 : }
811 : blob =
812 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
813 : }
814 :
815 : v8::Isolate::CreateParams create_params;
816 5 : create_params.snapshot_blob = &blob;
817 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
818 5 : v8::Isolate* isolate = TestIsolate::New(create_params);
819 : {
820 : v8::Isolate::Scope i_scope(isolate);
821 10 : v8::HandleScope h_scope(isolate);
822 : v8::Local<v8::Context> context = v8::Context::New(
823 : isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
824 : v8::MaybeLocal<v8::Value>(),
825 : v8::DeserializeInternalFieldsCallback(DeserializeInternalFields,
826 5 : reinterpret_cast<void*>(2017)));
827 5 : delete[] blob.data; // We can dispose of the snapshot blob now.
828 : v8::Context::Scope c_scope(context);
829 5 : TestInt32Expectations(expectations);
830 :
831 : v8::Local<v8::Value> x = CompileRun("x");
832 5 : CHECK(x->IsTypedArray());
833 : i::Handle<i::JSTypedArray> array =
834 : i::Handle<i::JSTypedArray>::cast(v8::Utils::OpenHandle(*x));
835 5 : CHECK(array->WasNeutered());
836 5 : CHECK_NULL(
837 : FixedTypedArrayBase::cast(array->elements())->external_pointer());
838 : }
839 5 : isolate->Dispose();
840 5 : }
841 :
842 15 : i::Handle<i::JSArrayBuffer> GetBufferFromTypedArray(
843 : v8::Local<v8::Value> typed_array) {
844 15 : CHECK(typed_array->IsTypedArray());
845 :
846 : i::Handle<i::JSArrayBufferView> view = i::Handle<i::JSArrayBufferView>::cast(
847 : v8::Utils::OpenHandle(*typed_array));
848 :
849 15 : return i::handle(i::JSArrayBuffer::cast(view->buffer()));
850 : }
851 :
852 23723 : TEST(CustomSnapshotDataBlobOnOrOffHeapTypedArray) {
853 : const char* code =
854 : "var x = new Uint8Array(8);"
855 : "x[0] = 12;"
856 : "x[7] = 24;"
857 : "var y = new Int16Array([12, 24, 48]);"
858 : "var z = new Int32Array(64);"
859 : "z[0] = 96;";
860 : Int32Expectations expectations = {
861 : std::make_tuple("x[0]", 12), std::make_tuple("x[7]", 24),
862 5 : std::make_tuple("y[2]", 48), std::make_tuple("z[0]", 96)};
863 :
864 : DisableAlwaysOpt();
865 5 : i::FLAG_allow_natives_syntax = true;
866 : v8::StartupData blob;
867 : {
868 5 : v8::SnapshotCreator creator;
869 5 : v8::Isolate* isolate = creator.GetIsolate();
870 : {
871 5 : v8::HandleScope handle_scope(isolate);
872 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
873 : v8::Context::Scope context_scope(context);
874 :
875 : CompileRun(code);
876 5 : TestInt32Expectations(expectations);
877 : creator.SetDefaultContext(
878 : context, v8::SerializeInternalFieldsCallback(
879 10 : SerializeInternalFields, reinterpret_cast<void*>(2016)));
880 : }
881 : blob =
882 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
883 : }
884 :
885 : v8::Isolate::CreateParams create_params;
886 5 : create_params.snapshot_blob = &blob;
887 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
888 5 : v8::Isolate* isolate = TestIsolate::New(create_params);
889 : {
890 : v8::Isolate::Scope i_scope(isolate);
891 10 : v8::HandleScope h_scope(isolate);
892 : v8::Local<v8::Context> context = v8::Context::New(
893 : isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
894 : v8::MaybeLocal<v8::Value>(),
895 : v8::DeserializeInternalFieldsCallback(DeserializeInternalFields,
896 5 : reinterpret_cast<void*>(2017)));
897 5 : delete[] blob.data; // We can dispose of the snapshot blob now.
898 : v8::Context::Scope c_scope(context);
899 5 : TestInt32Expectations(expectations);
900 :
901 : i::Handle<i::JSArrayBuffer> buffer =
902 5 : GetBufferFromTypedArray(CompileRun("x"));
903 : // The resulting buffer should be on-heap.
904 5 : CHECK_NULL(buffer->backing_store());
905 :
906 5 : buffer = GetBufferFromTypedArray(CompileRun("y"));
907 5 : CHECK_NULL(buffer->backing_store());
908 :
909 5 : buffer = GetBufferFromTypedArray(CompileRun("z"));
910 : // The resulting buffer should be off-heap.
911 5 : CHECK_NOT_NULL(buffer->backing_store());
912 : }
913 5 : isolate->Dispose();
914 5 : }
915 :
916 23723 : TEST(CustomSnapshotDataBlob2) {
917 : DisableAlwaysOpt();
918 : const char* source2 =
919 : "function f() { return g() * 2; }"
920 : "function g() { return 43; }"
921 : "/./.test('a')";
922 :
923 5 : v8::StartupData data2 = v8::V8::CreateSnapshotDataBlob(source2);
924 :
925 : v8::Isolate::CreateParams params2;
926 5 : params2.snapshot_blob = &data2;
927 5 : params2.array_buffer_allocator = CcTest::array_buffer_allocator();
928 : // Test-appropriate equivalent of v8::Isolate::New.
929 5 : v8::Isolate* isolate2 = TestIsolate::New(params2);
930 : {
931 : v8::Isolate::Scope i_scope(isolate2);
932 10 : v8::HandleScope h_scope(isolate2);
933 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
934 5 : delete[] data2.data; // We can dispose of the snapshot blob now.
935 : v8::Context::Scope c_scope(context);
936 : v8::Maybe<int32_t> result =
937 10 : CompileRun("f()")->Int32Value(isolate2->GetCurrentContext());
938 5 : CHECK_EQ(86, result.FromJust());
939 10 : result = CompileRun("g()")->Int32Value(isolate2->GetCurrentContext());
940 5 : CHECK_EQ(43, result.FromJust());
941 : }
942 5 : isolate2->Dispose();
943 5 : }
944 :
945 5 : static void SerializationFunctionTemplate(
946 5 : const v8::FunctionCallbackInfo<v8::Value>& args) {
947 : args.GetReturnValue().Set(args[0]);
948 5 : }
949 :
950 23723 : TEST(CustomSnapshotDataBlobOutdatedContextWithOverflow) {
951 : DisableAlwaysOpt();
952 : const char* source1 =
953 : "var o = {};"
954 : "(function() {"
955 : " function f1(x) { return f2(x) instanceof Array; }"
956 : " function f2(x) { return foo.bar(x); }"
957 : " o.a = f2.bind(null);"
958 : " o.b = 1;"
959 : " o.c = 2;"
960 : " o.d = 3;"
961 : " o.e = 4;"
962 : "})();\n";
963 :
964 : const char* source2 = "o.a(42)";
965 :
966 5 : v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source1);
967 :
968 : v8::Isolate::CreateParams params;
969 5 : params.snapshot_blob = &data;
970 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
971 :
972 : // Test-appropriate equivalent of v8::Isolate::New.
973 5 : v8::Isolate* isolate = TestIsolate::New(params);
974 : {
975 : v8::Isolate::Scope i_scope(isolate);
976 10 : v8::HandleScope h_scope(isolate);
977 :
978 5 : v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
979 5 : v8::Local<v8::ObjectTemplate> property = v8::ObjectTemplate::New(isolate);
980 : v8::Local<v8::FunctionTemplate> function =
981 5 : v8::FunctionTemplate::New(isolate, SerializationFunctionTemplate);
982 : property->Set(isolate, "bar", function);
983 : global->Set(isolate, "foo", property);
984 :
985 5 : v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);
986 5 : delete[] data.data; // We can dispose of the snapshot blob now.
987 : v8::Context::Scope c_scope(context);
988 5 : v8::Local<v8::Value> result = CompileRun(source2);
989 10 : v8::Maybe<bool> compare = v8_str("42")->Equals(
990 10 : v8::Isolate::GetCurrent()->GetCurrentContext(), result);
991 5 : CHECK(compare.FromJust());
992 : }
993 5 : isolate->Dispose();
994 5 : }
995 :
996 23723 : TEST(CustomSnapshotDataBlobWithLocker) {
997 : DisableAlwaysOpt();
998 : v8::Isolate::CreateParams create_params;
999 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
1000 5 : v8::Isolate* isolate0 = v8::Isolate::New(create_params);
1001 : {
1002 : v8::Locker locker(isolate0);
1003 : v8::Isolate::Scope i_scope(isolate0);
1004 10 : v8::HandleScope h_scope(isolate0);
1005 5 : v8::Local<v8::Context> context = v8::Context::New(isolate0);
1006 : v8::Context::Scope c_scope(context);
1007 : v8::Maybe<int32_t> result =
1008 10 : CompileRun("Math.cos(0)")->Int32Value(isolate0->GetCurrentContext());
1009 10 : CHECK_EQ(1, result.FromJust());
1010 : }
1011 5 : isolate0->Dispose();
1012 :
1013 : const char* source1 = "function f() { return 42; }";
1014 :
1015 5 : v8::StartupData data1 = v8::V8::CreateSnapshotDataBlob(source1);
1016 :
1017 : v8::Isolate::CreateParams params1;
1018 5 : params1.snapshot_blob = &data1;
1019 5 : params1.array_buffer_allocator = CcTest::array_buffer_allocator();
1020 : // Test-appropriate equivalent of v8::Isolate::New.
1021 5 : v8::Isolate* isolate1 = TestIsolate::New(params1);
1022 : {
1023 : v8::Locker locker(isolate1);
1024 : v8::Isolate::Scope i_scope(isolate1);
1025 10 : v8::HandleScope h_scope(isolate1);
1026 5 : v8::Local<v8::Context> context = v8::Context::New(isolate1);
1027 5 : delete[] data1.data; // We can dispose of the snapshot blob now.
1028 : v8::Context::Scope c_scope(context);
1029 5 : v8::Maybe<int32_t> result = CompileRun("f()")->Int32Value(context);
1030 10 : CHECK_EQ(42, result.FromJust());
1031 : }
1032 5 : isolate1->Dispose();
1033 5 : }
1034 :
1035 23723 : TEST(CustomSnapshotDataBlobStackOverflow) {
1036 : DisableAlwaysOpt();
1037 : const char* source =
1038 : "var a = [0];"
1039 : "var b = a;"
1040 : "for (var i = 0; i < 10000; i++) {"
1041 : " var c = [i];"
1042 : " b.push(c);"
1043 : " b.push(c);"
1044 : " b = c;"
1045 : "}";
1046 :
1047 5 : v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source);
1048 :
1049 : v8::Isolate::CreateParams params;
1050 5 : params.snapshot_blob = &data;
1051 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
1052 :
1053 : // Test-appropriate equivalent of v8::Isolate::New.
1054 5 : v8::Isolate* isolate = TestIsolate::New(params);
1055 : {
1056 : v8::Isolate::Scope i_scope(isolate);
1057 10 : v8::HandleScope h_scope(isolate);
1058 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
1059 5 : delete[] data.data; // We can dispose of the snapshot blob now.
1060 : v8::Context::Scope c_scope(context);
1061 : const char* test =
1062 : "var sum = 0;"
1063 : "while (a) {"
1064 : " sum += a[0];"
1065 : " a = a[1];"
1066 : "}"
1067 : "sum";
1068 : v8::Maybe<int32_t> result =
1069 10 : CompileRun(test)->Int32Value(isolate->GetCurrentContext());
1070 5 : CHECK_EQ(9999 * 5000, result.FromJust());
1071 : }
1072 5 : isolate->Dispose();
1073 5 : }
1074 :
1075 35 : bool IsCompiled(const char* name) {
1076 : return i::Handle<i::JSFunction>::cast(
1077 : v8::Utils::OpenHandle(*CompileRun(name)))
1078 : ->shared()
1079 35 : ->is_compiled();
1080 : }
1081 :
1082 23723 : TEST(SnapshotDataBlobWithWarmup) {
1083 : DisableLazyDeserialization();
1084 : DisableAlwaysOpt();
1085 : const char* warmup = "Math.abs(1); Math.random = 1;";
1086 :
1087 5 : v8::StartupData cold = v8::V8::CreateSnapshotDataBlob();
1088 5 : v8::StartupData warm = v8::V8::WarmUpSnapshotDataBlob(cold, warmup);
1089 5 : delete[] cold.data;
1090 :
1091 : v8::Isolate::CreateParams params;
1092 5 : params.snapshot_blob = &warm;
1093 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
1094 :
1095 : // Test-appropriate equivalent of v8::Isolate::New.
1096 5 : v8::Isolate* isolate = TestIsolate::New(params);
1097 : {
1098 : v8::Isolate::Scope i_scope(isolate);
1099 10 : v8::HandleScope h_scope(isolate);
1100 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
1101 5 : delete[] warm.data;
1102 : v8::Context::Scope c_scope(context);
1103 : // Running the warmup script has effect on whether functions are
1104 : // pre-compiled, but does not pollute the context.
1105 5 : CHECK(IsCompiled("Math.abs"));
1106 5 : CHECK(IsCompiled("String.raw"));
1107 5 : CHECK(CompileRun("Math.random")->IsFunction());
1108 : }
1109 5 : isolate->Dispose();
1110 5 : }
1111 :
1112 23723 : TEST(CustomSnapshotDataBlobWithWarmup) {
1113 : DisableLazyDeserialization();
1114 : DisableAlwaysOpt();
1115 : const char* source =
1116 : "function f() { return Math.abs(1); }\n"
1117 : "function g() { return String.raw(1); }\n"
1118 : "Object.valueOf(1);"
1119 : "var a = 5";
1120 : const char* warmup = "a = f()";
1121 :
1122 5 : v8::StartupData cold = v8::V8::CreateSnapshotDataBlob(source);
1123 5 : v8::StartupData warm = v8::V8::WarmUpSnapshotDataBlob(cold, warmup);
1124 5 : delete[] cold.data;
1125 :
1126 : v8::Isolate::CreateParams params;
1127 5 : params.snapshot_blob = &warm;
1128 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
1129 :
1130 : // Test-appropriate equivalent of v8::Isolate::New.
1131 5 : v8::Isolate* isolate = TestIsolate::New(params);
1132 : {
1133 : v8::Isolate::Scope i_scope(isolate);
1134 10 : v8::HandleScope h_scope(isolate);
1135 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
1136 5 : delete[] warm.data;
1137 : v8::Context::Scope c_scope(context);
1138 : // Running the warmup script has effect on whether functions are
1139 : // pre-compiled, but does not pollute the context.
1140 5 : CHECK(IsCompiled("f"));
1141 5 : CHECK(IsCompiled("Math.abs"));
1142 5 : CHECK(!IsCompiled("g"));
1143 5 : CHECK(IsCompiled("String.raw"));
1144 5 : CHECK(!IsCompiled("Array.prototype.sort"));
1145 10 : CHECK_EQ(5, CompileRun("a")->Int32Value(context).FromJust());
1146 : }
1147 5 : isolate->Dispose();
1148 5 : }
1149 :
1150 23723 : TEST(CustomSnapshotDataBlobImmortalImmovableRoots) {
1151 : DisableAlwaysOpt();
1152 : // Flood the startup snapshot with shared function infos. If they are
1153 : // serialized before the immortal immovable root, the root will no longer end
1154 : // up on the first page.
1155 : Vector<const uint8_t> source =
1156 : ConstructSource(STATIC_CHAR_VECTOR("var a = [];"),
1157 : STATIC_CHAR_VECTOR("a.push(function() {return 7});"),
1158 5 : STATIC_CHAR_VECTOR("\0"), 10000);
1159 :
1160 : v8::StartupData data = v8::V8::CreateSnapshotDataBlob(
1161 5 : reinterpret_cast<const char*>(source.start()));
1162 :
1163 : v8::Isolate::CreateParams params;
1164 5 : params.snapshot_blob = &data;
1165 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
1166 :
1167 : // Test-appropriate equivalent of v8::Isolate::New.
1168 5 : v8::Isolate* isolate = TestIsolate::New(params);
1169 : {
1170 : v8::Isolate::Scope i_scope(isolate);
1171 10 : v8::HandleScope h_scope(isolate);
1172 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
1173 5 : delete[] data.data; // We can dispose of the snapshot blob now.
1174 : v8::Context::Scope c_scope(context);
1175 10 : CHECK_EQ(7, CompileRun("a[0]()")->Int32Value(context).FromJust());
1176 : }
1177 5 : isolate->Dispose();
1178 : source.Dispose();
1179 5 : }
1180 :
1181 23723 : TEST(TestThatAlwaysSucceeds) {
1182 5 : }
1183 :
1184 :
1185 23718 : TEST(TestThatAlwaysFails) {
1186 : bool ArtificialFailure = false;
1187 0 : CHECK(ArtificialFailure);
1188 : }
1189 :
1190 :
1191 20 : int CountBuiltins() {
1192 : // Check that we have not deserialized any additional builtin.
1193 20 : HeapIterator iterator(CcTest::heap());
1194 : DisallowHeapAllocation no_allocation;
1195 : int counter = 0;
1196 160405 : for (HeapObject* obj = iterator.next(); obj != nullptr;
1197 : obj = iterator.next()) {
1198 179552 : if (obj->IsCode() && Code::cast(obj)->kind() == Code::BUILTIN) counter++;
1199 : }
1200 20 : return counter;
1201 : }
1202 :
1203 :
1204 100 : static Handle<SharedFunctionInfo> CompileScript(
1205 : Isolate* isolate, Handle<String> source, Handle<String> name,
1206 : ScriptData** cached_data, v8::ScriptCompiler::CompileOptions options) {
1207 : return Compiler::GetSharedFunctionInfoForScript(
1208 : source, name, 0, 0, v8::ScriptOriginOptions(), Handle<Object>(),
1209 : Handle<Context>(isolate->native_context()), nullptr, cached_data,
1210 200 : options, NOT_NATIVES_CODE, Handle<FixedArray>())
1211 300 : .ToHandleChecked();
1212 : }
1213 :
1214 23723 : TEST(CodeSerializerOnePlusOne) {
1215 5 : LocalContext context;
1216 10 : Isolate* isolate = CcTest::i_isolate();
1217 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
1218 :
1219 10 : v8::HandleScope scope(CcTest::isolate());
1220 :
1221 : const char* source = "1 + 1";
1222 :
1223 : Handle<String> orig_source = isolate->factory()
1224 : ->NewStringFromUtf8(CStrVector(source))
1225 10 : .ToHandleChecked();
1226 : Handle<String> copy_source = isolate->factory()
1227 : ->NewStringFromUtf8(CStrVector(source))
1228 10 : .ToHandleChecked();
1229 5 : CHECK(!orig_source.is_identical_to(copy_source));
1230 5 : CHECK(orig_source->Equals(*copy_source));
1231 :
1232 5 : ScriptData* cache = nullptr;
1233 :
1234 : Handle<SharedFunctionInfo> orig =
1235 : CompileScript(isolate, orig_source, Handle<String>(), &cache,
1236 5 : v8::ScriptCompiler::kProduceCodeCache);
1237 :
1238 5 : int builtins_count = CountBuiltins();
1239 :
1240 : Handle<SharedFunctionInfo> copy;
1241 : {
1242 : DisallowCompilation no_compile_expected(isolate);
1243 : copy = CompileScript(isolate, copy_source, Handle<String>(), &cache,
1244 5 : v8::ScriptCompiler::kConsumeCodeCache);
1245 : }
1246 :
1247 5 : CHECK_NE(*orig, *copy);
1248 5 : CHECK(Script::cast(copy->script())->source() == *copy_source);
1249 :
1250 : Handle<JSFunction> copy_fun =
1251 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
1252 5 : copy, isolate->native_context());
1253 5 : Handle<JSObject> global(isolate->context()->global_object());
1254 : Handle<Object> copy_result =
1255 10 : Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1256 5 : CHECK_EQ(2, Handle<Smi>::cast(copy_result)->value());
1257 :
1258 5 : CHECK_EQ(builtins_count, CountBuiltins());
1259 :
1260 15 : delete cache;
1261 5 : }
1262 :
1263 23723 : TEST(CodeSerializerPromotedToCompilationCache) {
1264 5 : LocalContext context;
1265 5 : Isolate* isolate = CcTest::i_isolate();
1266 :
1267 10 : v8::HandleScope scope(CcTest::isolate());
1268 :
1269 : const char* source = "1 + 1";
1270 :
1271 : Handle<String> src = isolate->factory()
1272 : ->NewStringFromUtf8(CStrVector(source))
1273 10 : .ToHandleChecked();
1274 5 : ScriptData* cache = nullptr;
1275 :
1276 : CompileScript(isolate, src, src, &cache,
1277 5 : v8::ScriptCompiler::kProduceCodeCache);
1278 :
1279 : DisallowCompilation no_compile_expected(isolate);
1280 : Handle<SharedFunctionInfo> copy = CompileScript(
1281 5 : isolate, src, src, &cache, v8::ScriptCompiler::kConsumeCodeCache);
1282 :
1283 : InfoVectorPair pair = isolate->compilation_cache()->LookupScript(
1284 : src, src, 0, 0, v8::ScriptOriginOptions(), isolate->native_context(),
1285 10 : LanguageMode::kSloppy);
1286 :
1287 10 : CHECK(pair.shared() == *copy);
1288 :
1289 15 : delete cache;
1290 5 : }
1291 :
1292 23723 : TEST(CodeSerializerInternalizedString) {
1293 5 : LocalContext context;
1294 10 : Isolate* isolate = CcTest::i_isolate();
1295 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
1296 :
1297 10 : v8::HandleScope scope(CcTest::isolate());
1298 :
1299 : const char* source = "'string1'";
1300 :
1301 : Handle<String> orig_source = isolate->factory()
1302 : ->NewStringFromUtf8(CStrVector(source))
1303 10 : .ToHandleChecked();
1304 : Handle<String> copy_source = isolate->factory()
1305 : ->NewStringFromUtf8(CStrVector(source))
1306 10 : .ToHandleChecked();
1307 5 : CHECK(!orig_source.is_identical_to(copy_source));
1308 5 : CHECK(orig_source->Equals(*copy_source));
1309 :
1310 5 : Handle<JSObject> global(isolate->context()->global_object());
1311 5 : ScriptData* cache = nullptr;
1312 :
1313 : Handle<SharedFunctionInfo> orig =
1314 : CompileScript(isolate, orig_source, Handle<String>(), &cache,
1315 5 : v8::ScriptCompiler::kProduceCodeCache);
1316 : Handle<JSFunction> orig_fun =
1317 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
1318 5 : orig, isolate->native_context());
1319 : Handle<Object> orig_result =
1320 10 : Execution::Call(isolate, orig_fun, global, 0, nullptr).ToHandleChecked();
1321 5 : CHECK(orig_result->IsInternalizedString());
1322 :
1323 5 : int builtins_count = CountBuiltins();
1324 :
1325 : Handle<SharedFunctionInfo> copy;
1326 : {
1327 : DisallowCompilation no_compile_expected(isolate);
1328 : copy = CompileScript(isolate, copy_source, Handle<String>(), &cache,
1329 5 : v8::ScriptCompiler::kConsumeCodeCache);
1330 : }
1331 5 : CHECK_NE(*orig, *copy);
1332 5 : CHECK(Script::cast(copy->script())->source() == *copy_source);
1333 :
1334 : Handle<JSFunction> copy_fun =
1335 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
1336 5 : copy, isolate->native_context());
1337 5 : CHECK_NE(*orig_fun, *copy_fun);
1338 : Handle<Object> copy_result =
1339 10 : Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1340 5 : CHECK(orig_result.is_identical_to(copy_result));
1341 : Handle<String> expected =
1342 5 : isolate->factory()->NewStringFromAsciiChecked("string1");
1343 :
1344 5 : CHECK(Handle<String>::cast(copy_result)->Equals(*expected));
1345 5 : CHECK_EQ(builtins_count, CountBuiltins());
1346 :
1347 15 : delete cache;
1348 5 : }
1349 :
1350 23723 : TEST(CodeSerializerLargeCodeObject) {
1351 5 : LocalContext context;
1352 10 : Isolate* isolate = CcTest::i_isolate();
1353 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
1354 :
1355 10 : v8::HandleScope scope(CcTest::isolate());
1356 :
1357 : // The serializer only tests the shared code, which is always the unoptimized
1358 : // code. Don't even bother generating optimized code to avoid timeouts.
1359 5 : FLAG_always_opt = false;
1360 :
1361 : Vector<const uint8_t> source =
1362 : ConstructSource(STATIC_CHAR_VECTOR("var j=1; if (j == 0) {"),
1363 : STATIC_CHAR_VECTOR("for (let i of Object.prototype);"),
1364 5 : STATIC_CHAR_VECTOR("} j=7; j"), 1100);
1365 : Handle<String> source_str =
1366 10 : isolate->factory()->NewStringFromOneByte(source).ToHandleChecked();
1367 :
1368 5 : Handle<JSObject> global(isolate->context()->global_object());
1369 5 : ScriptData* cache = nullptr;
1370 :
1371 : Handle<SharedFunctionInfo> orig =
1372 : CompileScript(isolate, source_str, Handle<String>(), &cache,
1373 5 : v8::ScriptCompiler::kProduceCodeCache);
1374 :
1375 5 : CHECK(isolate->heap()->InSpace(orig->abstract_code(), LO_SPACE));
1376 :
1377 : Handle<SharedFunctionInfo> copy;
1378 : {
1379 : DisallowCompilation no_compile_expected(isolate);
1380 : copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
1381 5 : v8::ScriptCompiler::kConsumeCodeCache);
1382 : }
1383 5 : CHECK_NE(*orig, *copy);
1384 :
1385 : Handle<JSFunction> copy_fun =
1386 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
1387 5 : copy, isolate->native_context());
1388 :
1389 : Handle<Object> copy_result =
1390 10 : Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1391 :
1392 : int result_int;
1393 5 : CHECK(copy_result->ToInt32(&result_int));
1394 5 : CHECK_EQ(7, result_int);
1395 :
1396 10 : delete cache;
1397 5 : source.Dispose();
1398 5 : }
1399 :
1400 23723 : TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) {
1401 5 : if (FLAG_never_compact) return;
1402 : ManualGCScope manual_gc_scope;
1403 5 : FLAG_always_opt = false;
1404 : const char* filter_flag = "--turbo-filter=NOTHING";
1405 5 : FlagList::SetFlagsFromString(filter_flag, StrLength(filter_flag));
1406 5 : FLAG_black_allocation = true;
1407 5 : FLAG_manual_evacuation_candidates_selection = true;
1408 :
1409 10 : LocalContext context;
1410 10 : Isolate* isolate = CcTest::i_isolate();
1411 15 : Heap* heap = isolate->heap();
1412 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
1413 :
1414 10 : v8::HandleScope scope(CcTest::isolate());
1415 :
1416 : Vector<const uint8_t> source = ConstructSource(
1417 : STATIC_CHAR_VECTOR("var j=1; if (j == 0) {"),
1418 : STATIC_CHAR_VECTOR("for (var i = 0; i < Object.prototype; i++);"),
1419 5 : STATIC_CHAR_VECTOR("} j=7; var s = 'happy_hippo'; j"), 10000);
1420 : Handle<String> source_str =
1421 10 : isolate->factory()->NewStringFromOneByte(source).ToHandleChecked();
1422 :
1423 : // Create a string on an evacuation candidate in old space.
1424 : Handle<String> moving_object;
1425 : Page* ec_page;
1426 : {
1427 : AlwaysAllocateScope always_allocate(isolate);
1428 5 : heap::SimulateFullSpace(heap->old_space());
1429 : moving_object = isolate->factory()->InternalizeString(
1430 5 : isolate->factory()->NewStringFromAsciiChecked("happy_hippo"));
1431 5 : ec_page = Page::FromAddress(moving_object->address());
1432 : }
1433 :
1434 5 : Handle<JSObject> global(isolate->context()->global_object());
1435 5 : ScriptData* cache = nullptr;
1436 :
1437 : Handle<SharedFunctionInfo> orig =
1438 : CompileScript(isolate, source_str, Handle<String>(), &cache,
1439 5 : v8::ScriptCompiler::kProduceCodeCache);
1440 :
1441 5 : CHECK(heap->InSpace(orig->abstract_code(), LO_SPACE));
1442 :
1443 : // Pretend that incremental marking is on when deserialization begins.
1444 5 : heap::ForceEvacuationCandidate(ec_page);
1445 5 : heap::SimulateIncrementalMarking(heap, false);
1446 : IncrementalMarking* marking = heap->incremental_marking();
1447 : marking->StartBlackAllocationForTesting();
1448 5 : CHECK(marking->IsCompacting());
1449 5 : CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*moving_object));
1450 :
1451 : Handle<SharedFunctionInfo> copy;
1452 : {
1453 : DisallowCompilation no_compile_expected(isolate);
1454 : copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
1455 5 : v8::ScriptCompiler::kConsumeCodeCache);
1456 : }
1457 5 : CHECK_NE(*orig, *copy);
1458 :
1459 : // We should have missed a write barrier. Complete incremental marking
1460 : // to flush out the bug.
1461 5 : heap::SimulateIncrementalMarking(heap, true);
1462 5 : CcTest::CollectAllGarbage();
1463 :
1464 : Handle<JSFunction> copy_fun =
1465 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
1466 5 : copy, isolate->native_context());
1467 :
1468 : Handle<Object> copy_result =
1469 10 : Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1470 :
1471 : int result_int;
1472 5 : CHECK(copy_result->ToInt32(&result_int));
1473 5 : CHECK_EQ(7, result_int);
1474 :
1475 10 : delete cache;
1476 : source.Dispose();
1477 : }
1478 23723 : TEST(CodeSerializerLargeStrings) {
1479 5 : LocalContext context;
1480 10 : Isolate* isolate = CcTest::i_isolate();
1481 : Factory* f = isolate->factory();
1482 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
1483 :
1484 10 : v8::HandleScope scope(CcTest::isolate());
1485 :
1486 : Vector<const uint8_t> source_s = ConstructSource(
1487 : STATIC_CHAR_VECTOR("var s = \""), STATIC_CHAR_VECTOR("abcdef"),
1488 5 : STATIC_CHAR_VECTOR("\";"), 1000000);
1489 : Vector<const uint8_t> source_t = ConstructSource(
1490 : STATIC_CHAR_VECTOR("var t = \""), STATIC_CHAR_VECTOR("uvwxyz"),
1491 5 : STATIC_CHAR_VECTOR("\"; s + t"), 999999);
1492 : Handle<String> source_str =
1493 : f->NewConsString(f->NewStringFromOneByte(source_s).ToHandleChecked(),
1494 15 : f->NewStringFromOneByte(source_t).ToHandleChecked())
1495 10 : .ToHandleChecked();
1496 :
1497 5 : Handle<JSObject> global(isolate->context()->global_object());
1498 5 : ScriptData* cache = nullptr;
1499 :
1500 : Handle<SharedFunctionInfo> orig =
1501 : CompileScript(isolate, source_str, Handle<String>(), &cache,
1502 5 : v8::ScriptCompiler::kProduceCodeCache);
1503 :
1504 : Handle<SharedFunctionInfo> copy;
1505 : {
1506 : DisallowCompilation no_compile_expected(isolate);
1507 : copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
1508 5 : v8::ScriptCompiler::kConsumeCodeCache);
1509 : }
1510 5 : CHECK_NE(*orig, *copy);
1511 :
1512 : Handle<JSFunction> copy_fun =
1513 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
1514 5 : copy, isolate->native_context());
1515 :
1516 : Handle<Object> copy_result =
1517 10 : Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1518 :
1519 5 : CHECK_EQ(6 * 1999999, Handle<String>::cast(copy_result)->length());
1520 : Handle<Object> property = JSReceiver::GetDataProperty(
1521 15 : isolate->global_object(), f->NewStringFromAsciiChecked("s"));
1522 5 : CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
1523 : property = JSReceiver::GetDataProperty(isolate->global_object(),
1524 15 : f->NewStringFromAsciiChecked("t"));
1525 5 : CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
1526 : // Make sure we do not serialize too much, e.g. include the source string.
1527 5 : CHECK_LT(cache->length(), 13000000);
1528 :
1529 10 : delete cache;
1530 : source_s.Dispose();
1531 5 : source_t.Dispose();
1532 5 : }
1533 :
1534 23723 : TEST(CodeSerializerThreeBigStrings) {
1535 5 : LocalContext context;
1536 10 : Isolate* isolate = CcTest::i_isolate();
1537 : Factory* f = isolate->factory();
1538 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
1539 :
1540 10 : v8::HandleScope scope(CcTest::isolate());
1541 :
1542 : Vector<const uint8_t> source_a =
1543 : ConstructSource(STATIC_CHAR_VECTOR("var a = \""), STATIC_CHAR_VECTOR("a"),
1544 5 : STATIC_CHAR_VECTOR("\";"), 700000);
1545 : Handle<String> source_a_str =
1546 10 : f->NewStringFromOneByte(source_a).ToHandleChecked();
1547 :
1548 : Vector<const uint8_t> source_b =
1549 : ConstructSource(STATIC_CHAR_VECTOR("var b = \""), STATIC_CHAR_VECTOR("b"),
1550 5 : STATIC_CHAR_VECTOR("\";"), 400000);
1551 : Handle<String> source_b_str =
1552 10 : f->NewStringFromOneByte(source_b).ToHandleChecked();
1553 :
1554 : Vector<const uint8_t> source_c =
1555 : ConstructSource(STATIC_CHAR_VECTOR("var c = \""), STATIC_CHAR_VECTOR("c"),
1556 5 : STATIC_CHAR_VECTOR("\";"), 400000);
1557 : Handle<String> source_c_str =
1558 10 : f->NewStringFromOneByte(source_c).ToHandleChecked();
1559 :
1560 : Handle<String> source_str =
1561 : f->NewConsString(
1562 : f->NewConsString(source_a_str, source_b_str).ToHandleChecked(),
1563 15 : source_c_str).ToHandleChecked();
1564 :
1565 5 : Handle<JSObject> global(isolate->context()->global_object());
1566 5 : ScriptData* cache = nullptr;
1567 :
1568 : Handle<SharedFunctionInfo> orig =
1569 : CompileScript(isolate, source_str, Handle<String>(), &cache,
1570 5 : v8::ScriptCompiler::kProduceCodeCache);
1571 :
1572 : Handle<SharedFunctionInfo> copy;
1573 : {
1574 : DisallowCompilation no_compile_expected(isolate);
1575 : copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
1576 5 : v8::ScriptCompiler::kConsumeCodeCache);
1577 : }
1578 5 : CHECK_NE(*orig, *copy);
1579 :
1580 : Handle<JSFunction> copy_fun =
1581 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
1582 5 : copy, isolate->native_context());
1583 :
1584 5 : USE(Execution::Call(isolate, copy_fun, global, 0, nullptr));
1585 :
1586 : v8::Maybe<int32_t> result =
1587 : CompileRun("(a + b).length")
1588 10 : ->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext());
1589 5 : CHECK_EQ(400000 + 700000, result.FromJust());
1590 : result = CompileRun("(b + c).length")
1591 10 : ->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext());
1592 5 : CHECK_EQ(400000 + 400000, result.FromJust());
1593 5 : Heap* heap = isolate->heap();
1594 : v8::Local<v8::String> result_str =
1595 : CompileRun("a")
1596 5 : ->ToString(CcTest::isolate()->GetCurrentContext())
1597 5 : .ToLocalChecked();
1598 5 : CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), LO_SPACE));
1599 : result_str = CompileRun("b")
1600 5 : ->ToString(CcTest::isolate()->GetCurrentContext())
1601 5 : .ToLocalChecked();
1602 5 : CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), OLD_SPACE));
1603 : result_str = CompileRun("c")
1604 5 : ->ToString(CcTest::isolate()->GetCurrentContext())
1605 5 : .ToLocalChecked();
1606 5 : CHECK(heap->InSpace(*v8::Utils::OpenHandle(*result_str), OLD_SPACE));
1607 :
1608 10 : delete cache;
1609 : source_a.Dispose();
1610 : source_b.Dispose();
1611 5 : source_c.Dispose();
1612 5 : }
1613 :
1614 :
1615 15 : class SerializerOneByteResource
1616 : : public v8::String::ExternalOneByteStringResource {
1617 : public:
1618 : SerializerOneByteResource(const char* data, size_t length)
1619 15 : : data_(data), length_(length) {}
1620 65 : virtual const char* data() const { return data_; }
1621 5 : virtual size_t length() const { return length_; }
1622 :
1623 : private:
1624 : const char* data_;
1625 : size_t length_;
1626 : };
1627 :
1628 :
1629 : class SerializerTwoByteResource : public v8::String::ExternalStringResource {
1630 : public:
1631 : SerializerTwoByteResource(const char* data, size_t length)
1632 5 : : data_(AsciiToTwoByteString(data)), length_(length) {}
1633 5 : ~SerializerTwoByteResource() { DeleteArray<const uint16_t>(data_); }
1634 :
1635 60 : virtual const uint16_t* data() const { return data_; }
1636 0 : virtual size_t length() const { return length_; }
1637 :
1638 : private:
1639 : const uint16_t* data_;
1640 : size_t length_;
1641 : };
1642 :
1643 23723 : TEST(CodeSerializerExternalString) {
1644 5 : LocalContext context;
1645 10 : Isolate* isolate = CcTest::i_isolate();
1646 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
1647 :
1648 10 : v8::HandleScope scope(CcTest::isolate());
1649 :
1650 : // Obtain external internalized one-byte string.
1651 : SerializerOneByteResource one_byte_resource("one_byte", 8);
1652 : Handle<String> one_byte_string =
1653 5 : isolate->factory()->NewStringFromAsciiChecked("one_byte");
1654 5 : one_byte_string = isolate->factory()->InternalizeString(one_byte_string);
1655 5 : one_byte_string->MakeExternal(&one_byte_resource);
1656 5 : CHECK(one_byte_string->IsExternalOneByteString());
1657 5 : CHECK(one_byte_string->IsInternalizedString());
1658 :
1659 : // Obtain external internalized two-byte string.
1660 : SerializerTwoByteResource two_byte_resource("two_byte", 8);
1661 : Handle<String> two_byte_string =
1662 5 : isolate->factory()->NewStringFromAsciiChecked("two_byte");
1663 5 : two_byte_string = isolate->factory()->InternalizeString(two_byte_string);
1664 5 : two_byte_string->MakeExternal(&two_byte_resource);
1665 5 : CHECK(two_byte_string->IsExternalTwoByteString());
1666 5 : CHECK(two_byte_string->IsInternalizedString());
1667 :
1668 : const char* source =
1669 : "var o = {} \n"
1670 : "o.one_byte = 7; \n"
1671 : "o.two_byte = 8; \n"
1672 : "o.one_byte + o.two_byte; \n";
1673 : Handle<String> source_string = isolate->factory()
1674 : ->NewStringFromUtf8(CStrVector(source))
1675 10 : .ToHandleChecked();
1676 :
1677 5 : Handle<JSObject> global(isolate->context()->global_object());
1678 5 : ScriptData* cache = nullptr;
1679 :
1680 : Handle<SharedFunctionInfo> orig =
1681 : CompileScript(isolate, source_string, Handle<String>(), &cache,
1682 5 : v8::ScriptCompiler::kProduceCodeCache);
1683 :
1684 : Handle<SharedFunctionInfo> copy;
1685 : {
1686 : DisallowCompilation no_compile_expected(isolate);
1687 : copy = CompileScript(isolate, source_string, Handle<String>(), &cache,
1688 5 : v8::ScriptCompiler::kConsumeCodeCache);
1689 : }
1690 5 : CHECK_NE(*orig, *copy);
1691 :
1692 : Handle<JSFunction> copy_fun =
1693 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
1694 5 : copy, isolate->native_context());
1695 :
1696 : Handle<Object> copy_result =
1697 10 : Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1698 :
1699 5 : CHECK_EQ(15.0, copy_result->Number());
1700 :
1701 15 : delete cache;
1702 5 : }
1703 :
1704 23723 : TEST(CodeSerializerLargeExternalString) {
1705 5 : LocalContext context;
1706 10 : Isolate* isolate = CcTest::i_isolate();
1707 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
1708 :
1709 : Factory* f = isolate->factory();
1710 :
1711 10 : v8::HandleScope scope(CcTest::isolate());
1712 :
1713 : // Create a huge external internalized string to use as variable name.
1714 : Vector<const uint8_t> string =
1715 : ConstructSource(STATIC_CHAR_VECTOR(""), STATIC_CHAR_VECTOR("abcdef"),
1716 5 : STATIC_CHAR_VECTOR(""), 999999);
1717 10 : Handle<String> name = f->NewStringFromOneByte(string).ToHandleChecked();
1718 : SerializerOneByteResource one_byte_resource(
1719 5 : reinterpret_cast<const char*>(string.start()), string.length());
1720 5 : name = f->InternalizeString(name);
1721 5 : name->MakeExternal(&one_byte_resource);
1722 5 : CHECK(name->IsExternalOneByteString());
1723 5 : CHECK(name->IsInternalizedString());
1724 5 : CHECK(isolate->heap()->InSpace(*name, LO_SPACE));
1725 :
1726 : // Create the source, which is "var <literal> = 42; <literal>".
1727 : Handle<String> source_str =
1728 : f->NewConsString(
1729 5 : f->NewConsString(f->NewStringFromAsciiChecked("var "), name)
1730 : .ToHandleChecked(),
1731 5 : f->NewConsString(f->NewStringFromAsciiChecked(" = 42; "), name)
1732 20 : .ToHandleChecked()).ToHandleChecked();
1733 :
1734 5 : Handle<JSObject> global(isolate->context()->global_object());
1735 5 : ScriptData* cache = nullptr;
1736 :
1737 : Handle<SharedFunctionInfo> orig =
1738 : CompileScript(isolate, source_str, Handle<String>(), &cache,
1739 5 : v8::ScriptCompiler::kProduceCodeCache);
1740 :
1741 : Handle<SharedFunctionInfo> copy;
1742 : {
1743 : DisallowCompilation no_compile_expected(isolate);
1744 : copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
1745 5 : v8::ScriptCompiler::kConsumeCodeCache);
1746 : }
1747 5 : CHECK_NE(*orig, *copy);
1748 :
1749 : Handle<JSFunction> copy_fun =
1750 5 : f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
1751 :
1752 : Handle<Object> copy_result =
1753 10 : Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1754 :
1755 5 : CHECK_EQ(42.0, copy_result->Number());
1756 :
1757 10 : delete cache;
1758 5 : string.Dispose();
1759 5 : }
1760 :
1761 23723 : TEST(CodeSerializerExternalScriptName) {
1762 5 : LocalContext context;
1763 10 : Isolate* isolate = CcTest::i_isolate();
1764 5 : isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
1765 :
1766 : Factory* f = isolate->factory();
1767 :
1768 10 : v8::HandleScope scope(CcTest::isolate());
1769 :
1770 : const char* source =
1771 : "var a = [1, 2, 3, 4];"
1772 : "a.reduce(function(x, y) { return x + y }, 0)";
1773 :
1774 : Handle<String> source_string =
1775 10 : f->NewStringFromUtf8(CStrVector(source)).ToHandleChecked();
1776 :
1777 : const SerializerOneByteResource one_byte_resource("one_byte", 8);
1778 : Handle<String> name =
1779 10 : f->NewExternalStringFromOneByte(&one_byte_resource).ToHandleChecked();
1780 5 : CHECK(name->IsExternalOneByteString());
1781 5 : CHECK(!name->IsInternalizedString());
1782 :
1783 5 : Handle<JSObject> global(isolate->context()->global_object());
1784 5 : ScriptData* cache = nullptr;
1785 :
1786 : Handle<SharedFunctionInfo> orig =
1787 : CompileScript(isolate, source_string, name, &cache,
1788 5 : v8::ScriptCompiler::kProduceCodeCache);
1789 :
1790 : Handle<SharedFunctionInfo> copy;
1791 : {
1792 : DisallowCompilation no_compile_expected(isolate);
1793 : copy = CompileScript(isolate, source_string, name, &cache,
1794 5 : v8::ScriptCompiler::kConsumeCodeCache);
1795 : }
1796 5 : CHECK_NE(*orig, *copy);
1797 :
1798 : Handle<JSFunction> copy_fun =
1799 5 : f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
1800 :
1801 : Handle<Object> copy_result =
1802 10 : Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
1803 :
1804 5 : CHECK_EQ(10.0, copy_result->Number());
1805 :
1806 15 : delete cache;
1807 5 : }
1808 :
1809 :
1810 : static bool toplevel_test_code_event_found = false;
1811 :
1812 :
1813 80 : static void SerializerCodeEventListener(const v8::JitCodeEvent* event) {
1814 102 : if (event->type == v8::JitCodeEvent::CODE_ADDED &&
1815 22 : memcmp(event->name.str, "Script:~test", 12) == 0) {
1816 10 : toplevel_test_code_event_found = true;
1817 : }
1818 80 : }
1819 :
1820 20 : v8::ScriptCompiler::CachedData* ProduceCache(const char* source,
1821 : bool eager = false) {
1822 : v8::ScriptCompiler::CachedData* cache;
1823 : v8::Isolate::CreateParams create_params;
1824 20 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
1825 20 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
1826 : {
1827 : v8::Isolate::Scope iscope(isolate1);
1828 40 : v8::HandleScope scope(isolate1);
1829 20 : v8::Local<v8::Context> context = v8::Context::New(isolate1);
1830 : v8::Context::Scope context_scope(context);
1831 :
1832 20 : v8::Local<v8::String> source_str = v8_str(source);
1833 20 : v8::ScriptOrigin origin(v8_str("test"));
1834 : v8::ScriptCompiler::Source source(source_str, origin);
1835 : v8::ScriptCompiler::CompileOptions options =
1836 : eager ? v8::ScriptCompiler::kProduceFullCodeCache
1837 20 : : v8::ScriptCompiler::kProduceCodeCache;
1838 : v8::Local<v8::UnboundScript> script =
1839 : v8::ScriptCompiler::CompileUnboundScript(isolate1, &source, options)
1840 20 : .ToLocalChecked();
1841 20 : const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
1842 20 : CHECK(data);
1843 : // Persist cached data.
1844 20 : uint8_t* buffer = NewArray<uint8_t>(data->length);
1845 20 : MemCopy(buffer, data->data, data->length);
1846 : cache = new v8::ScriptCompiler::CachedData(
1847 20 : buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
1848 :
1849 : v8::Local<v8::Value> result = script->BindToCurrentContext()
1850 40 : ->Run(isolate1->GetCurrentContext())
1851 20 : .ToLocalChecked();
1852 : v8::Local<v8::String> result_string =
1853 20 : result->ToString(isolate1->GetCurrentContext()).ToLocalChecked();
1854 60 : CHECK(result_string->Equals(isolate1->GetCurrentContext(), v8_str("abcdef"))
1855 : .FromJust());
1856 : }
1857 20 : isolate1->Dispose();
1858 20 : return cache;
1859 : }
1860 :
1861 15 : void CheckDeserializedFlag(v8::Local<v8::UnboundScript> script) {
1862 : i::Handle<i::SharedFunctionInfo> sfi = v8::Utils::OpenHandle(*script);
1863 : i::Handle<i::Script> i_script(Script::cast(sfi->script()));
1864 15 : i::SharedFunctionInfo::ScriptIterator iterator(i_script);
1865 45 : while (SharedFunctionInfo* next = iterator.Next()) {
1866 30 : CHECK_EQ(next->is_compiled(), next->deserialized());
1867 : }
1868 15 : }
1869 :
1870 23723 : TEST(CodeSerializerIsolates) {
1871 : const char* source = "function f() { return 'abc'; }; f() + 'def'";
1872 5 : v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
1873 :
1874 : v8::Isolate::CreateParams create_params;
1875 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
1876 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
1877 : isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
1878 5 : SerializerCodeEventListener);
1879 5 : toplevel_test_code_event_found = false;
1880 : {
1881 : v8::Isolate::Scope iscope(isolate2);
1882 10 : v8::HandleScope scope(isolate2);
1883 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
1884 : v8::Context::Scope context_scope(context);
1885 :
1886 5 : v8::Local<v8::String> source_str = v8_str(source);
1887 5 : v8::ScriptOrigin origin(v8_str("test"));
1888 : v8::ScriptCompiler::Source source(source_str, origin, cache);
1889 : v8::Local<v8::UnboundScript> script;
1890 : {
1891 : DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
1892 : script = v8::ScriptCompiler::CompileUnboundScript(
1893 : isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
1894 5 : .ToLocalChecked();
1895 : }
1896 5 : CHECK(!cache->rejected);
1897 5 : CheckDeserializedFlag(script);
1898 : v8::Local<v8::Value> result = script->BindToCurrentContext()
1899 10 : ->Run(isolate2->GetCurrentContext())
1900 5 : .ToLocalChecked();
1901 20 : CHECK(result->ToString(isolate2->GetCurrentContext())
1902 : .ToLocalChecked()
1903 : ->Equals(isolate2->GetCurrentContext(), v8_str("abcdef"))
1904 : .FromJust());
1905 : }
1906 5 : CHECK(toplevel_test_code_event_found);
1907 5 : isolate2->Dispose();
1908 5 : }
1909 :
1910 23723 : TEST(CodeSerializerIsolatesEager) {
1911 : const char* source =
1912 : "function f() {"
1913 : " return function g() {"
1914 : " return 'abc';"
1915 : " }"
1916 : "}"
1917 : "f()() + 'def'";
1918 5 : v8::ScriptCompiler::CachedData* cache = ProduceCache(source, true);
1919 :
1920 : v8::Isolate::CreateParams create_params;
1921 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
1922 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
1923 : isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
1924 5 : SerializerCodeEventListener);
1925 5 : toplevel_test_code_event_found = false;
1926 : {
1927 : v8::Isolate::Scope iscope(isolate2);
1928 10 : v8::HandleScope scope(isolate2);
1929 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
1930 : v8::Context::Scope context_scope(context);
1931 :
1932 5 : v8::Local<v8::String> source_str = v8_str(source);
1933 5 : v8::ScriptOrigin origin(v8_str("test"));
1934 : v8::ScriptCompiler::Source source(source_str, origin, cache);
1935 : v8::Local<v8::UnboundScript> script;
1936 : {
1937 : DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
1938 : script = v8::ScriptCompiler::CompileUnboundScript(
1939 : isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
1940 5 : .ToLocalChecked();
1941 : }
1942 5 : CHECK(!cache->rejected);
1943 5 : CheckDeserializedFlag(script);
1944 : v8::Local<v8::Value> result = script->BindToCurrentContext()
1945 10 : ->Run(isolate2->GetCurrentContext())
1946 5 : .ToLocalChecked();
1947 20 : CHECK(result->ToString(isolate2->GetCurrentContext())
1948 : .ToLocalChecked()
1949 : ->Equals(isolate2->GetCurrentContext(), v8_str("abcdef"))
1950 : .FromJust());
1951 : }
1952 5 : CHECK(toplevel_test_code_event_found);
1953 5 : isolate2->Dispose();
1954 5 : }
1955 :
1956 23723 : TEST(CodeSerializerFlagChange) {
1957 : const char* source = "function f() { return 'abc'; }; f() + 'def'";
1958 5 : v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
1959 :
1960 : v8::Isolate::CreateParams create_params;
1961 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
1962 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
1963 :
1964 5 : FLAG_allow_natives_syntax = true; // Flag change should trigger cache reject.
1965 5 : FlagList::EnforceFlagImplications();
1966 : {
1967 : v8::Isolate::Scope iscope(isolate2);
1968 10 : v8::HandleScope scope(isolate2);
1969 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
1970 : v8::Context::Scope context_scope(context);
1971 :
1972 5 : v8::Local<v8::String> source_str = v8_str(source);
1973 5 : v8::ScriptOrigin origin(v8_str("test"));
1974 : v8::ScriptCompiler::Source source(source_str, origin, cache);
1975 : v8::ScriptCompiler::CompileUnboundScript(
1976 : isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
1977 5 : .ToLocalChecked();
1978 5 : CHECK(cache->rejected);
1979 : }
1980 5 : isolate2->Dispose();
1981 5 : }
1982 :
1983 23723 : TEST(CodeSerializerBitFlip) {
1984 : const char* source = "function f() { return 'abc'; }; f() + 'def'";
1985 5 : v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
1986 :
1987 : // Random bit flip.
1988 5 : const_cast<uint8_t*>(cache->data)[337] ^= 0x40;
1989 :
1990 : v8::Isolate::CreateParams create_params;
1991 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
1992 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
1993 : {
1994 : v8::Isolate::Scope iscope(isolate2);
1995 10 : v8::HandleScope scope(isolate2);
1996 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
1997 : v8::Context::Scope context_scope(context);
1998 :
1999 5 : v8::Local<v8::String> source_str = v8_str(source);
2000 5 : v8::ScriptOrigin origin(v8_str("test"));
2001 : v8::ScriptCompiler::Source source(source_str, origin, cache);
2002 : v8::ScriptCompiler::CompileUnboundScript(
2003 : isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
2004 5 : .ToLocalChecked();
2005 5 : CHECK(cache->rejected);
2006 : }
2007 5 : isolate2->Dispose();
2008 5 : }
2009 :
2010 23723 : TEST(CodeSerializerWithHarmonyScoping) {
2011 : const char* source1 = "'use strict'; let x = 'X'";
2012 : const char* source2 = "'use strict'; let y = 'Y'";
2013 : const char* source3 = "'use strict'; x + y";
2014 :
2015 : v8::ScriptCompiler::CachedData* cache;
2016 :
2017 : v8::Isolate::CreateParams create_params;
2018 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
2019 5 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
2020 : {
2021 : v8::Isolate::Scope iscope(isolate1);
2022 10 : v8::HandleScope scope(isolate1);
2023 5 : v8::Local<v8::Context> context = v8::Context::New(isolate1);
2024 : v8::Context::Scope context_scope(context);
2025 :
2026 : CompileRun(source1);
2027 : CompileRun(source2);
2028 :
2029 5 : v8::Local<v8::String> source_str = v8_str(source3);
2030 5 : v8::ScriptOrigin origin(v8_str("test"));
2031 : v8::ScriptCompiler::Source source(source_str, origin);
2032 : v8::Local<v8::UnboundScript> script =
2033 : v8::ScriptCompiler::CompileUnboundScript(
2034 : isolate1, &source, v8::ScriptCompiler::kProduceCodeCache)
2035 5 : .ToLocalChecked();
2036 5 : const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
2037 5 : CHECK(data);
2038 : // Persist cached data.
2039 5 : uint8_t* buffer = NewArray<uint8_t>(data->length);
2040 5 : MemCopy(buffer, data->data, data->length);
2041 : cache = new v8::ScriptCompiler::CachedData(
2042 5 : buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
2043 :
2044 : v8::Local<v8::Value> result = script->BindToCurrentContext()
2045 10 : ->Run(isolate1->GetCurrentContext())
2046 5 : .ToLocalChecked();
2047 : v8::Local<v8::String> result_str =
2048 5 : result->ToString(isolate1->GetCurrentContext()).ToLocalChecked();
2049 15 : CHECK(result_str->Equals(isolate1->GetCurrentContext(), v8_str("XY"))
2050 : .FromJust());
2051 : }
2052 5 : isolate1->Dispose();
2053 :
2054 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
2055 : {
2056 : v8::Isolate::Scope iscope(isolate2);
2057 10 : v8::HandleScope scope(isolate2);
2058 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
2059 : v8::Context::Scope context_scope(context);
2060 :
2061 : // Reverse order of prior running scripts.
2062 : CompileRun(source2);
2063 : CompileRun(source1);
2064 :
2065 5 : v8::Local<v8::String> source_str = v8_str(source3);
2066 5 : v8::ScriptOrigin origin(v8_str("test"));
2067 : v8::ScriptCompiler::Source source(source_str, origin, cache);
2068 : v8::Local<v8::UnboundScript> script;
2069 : {
2070 : DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
2071 : script = v8::ScriptCompiler::CompileUnboundScript(
2072 : isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
2073 5 : .ToLocalChecked();
2074 : }
2075 5 : CheckDeserializedFlag(script);
2076 : v8::Local<v8::Value> result = script->BindToCurrentContext()
2077 10 : ->Run(isolate2->GetCurrentContext())
2078 5 : .ToLocalChecked();
2079 : v8::Local<v8::String> result_str =
2080 5 : result->ToString(isolate2->GetCurrentContext()).ToLocalChecked();
2081 15 : CHECK(result_str->Equals(isolate2->GetCurrentContext(), v8_str("XY"))
2082 : .FromJust());
2083 : }
2084 5 : isolate2->Dispose();
2085 5 : }
2086 :
2087 23723 : TEST(Regress503552) {
2088 5 : if (!FLAG_incremental_marking) return;
2089 : // Test that the code serializer can deal with weak cells that form a linked
2090 : // list during incremental marking.
2091 5 : CcTest::InitializeVM();
2092 : Isolate* isolate = CcTest::i_isolate();
2093 :
2094 : HandleScope scope(isolate);
2095 : Handle<String> source = isolate->factory()->NewStringFromAsciiChecked(
2096 5 : "function f() {} function g() {}");
2097 5 : ScriptData* script_data = nullptr;
2098 : Handle<SharedFunctionInfo> shared =
2099 : Compiler::GetSharedFunctionInfoForScript(
2100 : source, MaybeHandle<String>(), 0, 0, v8::ScriptOriginOptions(),
2101 : MaybeHandle<Object>(), Handle<Context>(isolate->native_context()),
2102 : nullptr, &script_data, v8::ScriptCompiler::kProduceCodeCache,
2103 10 : NOT_NATIVES_CODE, MaybeHandle<FixedArray>())
2104 10 : .ToHandleChecked();
2105 10 : delete script_data;
2106 :
2107 5 : heap::SimulateIncrementalMarking(isolate->heap());
2108 :
2109 5 : script_data = CodeSerializer::Serialize(isolate, shared, source);
2110 10 : delete script_data;
2111 : }
2112 :
2113 23723 : TEST(SnapshotCreatorMultipleContexts) {
2114 : DisableAlwaysOpt();
2115 : v8::StartupData blob;
2116 : {
2117 5 : v8::SnapshotCreator creator;
2118 5 : v8::Isolate* isolate = creator.GetIsolate();
2119 : {
2120 5 : v8::HandleScope handle_scope(isolate);
2121 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2122 : v8::Context::Scope context_scope(context);
2123 : CompileRun("var f = function() { return 1; }");
2124 10 : creator.SetDefaultContext(context);
2125 : }
2126 : {
2127 5 : v8::HandleScope handle_scope(isolate);
2128 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2129 : v8::Context::Scope context_scope(context);
2130 : CompileRun("var f = function() { return 2; }");
2131 10 : CHECK_EQ(0u, creator.AddContext(context));
2132 : }
2133 : {
2134 5 : v8::HandleScope handle_scope(isolate);
2135 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2136 5 : CHECK_EQ(1u, creator.AddContext(context));
2137 : }
2138 : blob =
2139 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
2140 : }
2141 :
2142 : v8::Isolate::CreateParams params;
2143 5 : params.snapshot_blob = &blob;
2144 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
2145 : // Test-appropriate equivalent of v8::Isolate::New.
2146 5 : v8::Isolate* isolate = TestIsolate::New(params);
2147 : {
2148 : v8::Isolate::Scope isolate_scope(isolate);
2149 : {
2150 5 : v8::HandleScope handle_scope(isolate);
2151 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2152 : v8::Context::Scope context_scope(context);
2153 10 : ExpectInt32("f()", 1);
2154 : }
2155 : {
2156 5 : v8::HandleScope handle_scope(isolate);
2157 : v8::Local<v8::Context> context =
2158 10 : v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
2159 : v8::Context::Scope context_scope(context);
2160 10 : ExpectInt32("f()", 2);
2161 : }
2162 : {
2163 5 : v8::HandleScope handle_scope(isolate);
2164 : v8::Local<v8::Context> context =
2165 10 : v8::Context::FromSnapshot(isolate, 1).ToLocalChecked();
2166 : v8::Context::Scope context_scope(context);
2167 10 : ExpectUndefined("this.f");
2168 : }
2169 : }
2170 :
2171 5 : isolate->Dispose();
2172 5 : delete[] blob.data;
2173 5 : }
2174 :
2175 60 : static void SerializedCallback(
2176 60 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2177 60 : args.GetReturnValue().Set(v8_num(42));
2178 60 : }
2179 :
2180 10 : static void SerializedCallbackReplacement(
2181 10 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2182 10 : args.GetReturnValue().Set(v8_num(1337));
2183 10 : }
2184 :
2185 185 : static void NamedPropertyGetterForSerialization(
2186 : v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2187 555 : if (name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("x"))
2188 370 : .FromJust()) {
2189 20 : info.GetReturnValue().Set(v8_num(2016));
2190 : }
2191 185 : }
2192 :
2193 5 : static void AccessorForSerialization(
2194 : v8::Local<v8::String> property,
2195 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2196 5 : info.GetReturnValue().Set(v8_num(2017));
2197 5 : }
2198 :
2199 : static int serialized_static_field = 314;
2200 :
2201 0 : class SerializedExtension : public v8::Extension {
2202 : public:
2203 5 : SerializedExtension()
2204 : : v8::Extension("serialized extension",
2205 : "native function g();"
2206 : "function h() { return 13; };"
2207 : "function i() { return 14; };"
2208 5 : "var o = { p: 7 };") {}
2209 :
2210 5 : virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
2211 : v8::Isolate* isolate, v8::Local<v8::String> name) {
2212 20 : CHECK(name->Equals(isolate->GetCurrentContext(), v8_str("g")).FromJust());
2213 5 : return v8::FunctionTemplate::New(isolate, FunctionCallback);
2214 : }
2215 :
2216 25 : static void FunctionCallback(
2217 25 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2218 25 : args.GetReturnValue().Set(v8_num(12));
2219 25 : }
2220 : };
2221 :
2222 : intptr_t original_external_references[] = {
2223 : reinterpret_cast<intptr_t>(SerializedCallback),
2224 : reinterpret_cast<intptr_t>(&serialized_static_field),
2225 : reinterpret_cast<intptr_t>(&NamedPropertyGetterForSerialization),
2226 : reinterpret_cast<intptr_t>(&AccessorForSerialization),
2227 : reinterpret_cast<intptr_t>(&SerializedExtension::FunctionCallback),
2228 : reinterpret_cast<intptr_t>(&serialized_static_field), // duplicate entry
2229 : 0};
2230 :
2231 : intptr_t replaced_external_references[] = {
2232 : reinterpret_cast<intptr_t>(SerializedCallbackReplacement),
2233 : reinterpret_cast<intptr_t>(&serialized_static_field),
2234 : reinterpret_cast<intptr_t>(&NamedPropertyGetterForSerialization),
2235 : reinterpret_cast<intptr_t>(&AccessorForSerialization),
2236 : reinterpret_cast<intptr_t>(&SerializedExtension::FunctionCallback),
2237 : reinterpret_cast<intptr_t>(&serialized_static_field),
2238 : 0};
2239 :
2240 : intptr_t short_external_references[] = {
2241 : reinterpret_cast<intptr_t>(SerializedCallbackReplacement), 0};
2242 :
2243 23723 : TEST(SnapshotCreatorExternalReferences) {
2244 : DisableAlwaysOpt();
2245 : v8::StartupData blob;
2246 : {
2247 5 : v8::SnapshotCreator creator(original_external_references);
2248 5 : v8::Isolate* isolate = creator.GetIsolate();
2249 : {
2250 5 : v8::HandleScope handle_scope(isolate);
2251 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2252 : v8::Context::Scope context_scope(context);
2253 : v8::Local<v8::FunctionTemplate> callback =
2254 5 : v8::FunctionTemplate::New(isolate, SerializedCallback);
2255 : v8::Local<v8::Value> function =
2256 5 : callback->GetFunction(context).ToLocalChecked();
2257 20 : CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
2258 5 : ExpectInt32("f()", 42);
2259 10 : creator.SetDefaultContext(context);
2260 : }
2261 : blob =
2262 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
2263 : }
2264 :
2265 : // Deserialize with the original external reference.
2266 : {
2267 : v8::Isolate::CreateParams params;
2268 5 : params.snapshot_blob = &blob;
2269 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
2270 5 : params.external_references = original_external_references;
2271 : // Test-appropriate equivalent of v8::Isolate::New.
2272 5 : v8::Isolate* isolate = TestIsolate::New(params);
2273 : {
2274 : v8::Isolate::Scope isolate_scope(isolate);
2275 10 : v8::HandleScope handle_scope(isolate);
2276 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2277 : v8::Context::Scope context_scope(context);
2278 5 : ExpectInt32("f()", 42);
2279 : }
2280 5 : isolate->Dispose();
2281 : }
2282 :
2283 : // Deserialize with some other external reference.
2284 : {
2285 : v8::Isolate::CreateParams params;
2286 5 : params.snapshot_blob = &blob;
2287 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
2288 5 : params.external_references = replaced_external_references;
2289 : // Test-appropriate equivalent of v8::Isolate::New.
2290 5 : v8::Isolate* isolate = TestIsolate::New(params);
2291 : {
2292 : v8::Isolate::Scope isolate_scope(isolate);
2293 10 : v8::HandleScope handle_scope(isolate);
2294 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2295 : v8::Context::Scope context_scope(context);
2296 5 : ExpectInt32("f()", 1337);
2297 : }
2298 5 : isolate->Dispose();
2299 : }
2300 5 : delete[] blob.data;
2301 5 : }
2302 :
2303 23723 : TEST(SnapshotCreatorShortExternalReferences) {
2304 : DisableAlwaysOpt();
2305 : v8::StartupData blob;
2306 : {
2307 5 : v8::SnapshotCreator creator(original_external_references);
2308 5 : v8::Isolate* isolate = creator.GetIsolate();
2309 : {
2310 5 : v8::HandleScope handle_scope(isolate);
2311 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2312 : v8::Context::Scope context_scope(context);
2313 : v8::Local<v8::FunctionTemplate> callback =
2314 5 : v8::FunctionTemplate::New(isolate, SerializedCallback);
2315 : v8::Local<v8::Value> function =
2316 5 : callback->GetFunction(context).ToLocalChecked();
2317 20 : CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
2318 5 : ExpectInt32("f()", 42);
2319 10 : creator.SetDefaultContext(context);
2320 : }
2321 : blob =
2322 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
2323 : }
2324 :
2325 : // Deserialize with an incomplete list of external references.
2326 : {
2327 : v8::Isolate::CreateParams params;
2328 5 : params.snapshot_blob = &blob;
2329 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
2330 5 : params.external_references = short_external_references;
2331 : // Test-appropriate equivalent of v8::Isolate::New.
2332 5 : v8::Isolate* isolate = TestIsolate::New(params);
2333 : {
2334 : v8::Isolate::Scope isolate_scope(isolate);
2335 10 : v8::HandleScope handle_scope(isolate);
2336 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2337 : v8::Context::Scope context_scope(context);
2338 5 : ExpectInt32("f()", 1337);
2339 : }
2340 5 : isolate->Dispose();
2341 : }
2342 5 : delete[] blob.data;
2343 5 : }
2344 :
2345 23718 : TEST(SnapshotCreatorUnknownExternalReferences) {
2346 : DisableAlwaysOpt();
2347 0 : v8::SnapshotCreator creator;
2348 0 : v8::Isolate* isolate = creator.GetIsolate();
2349 : {
2350 0 : v8::HandleScope handle_scope(isolate);
2351 0 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2352 : v8::Context::Scope context_scope(context);
2353 :
2354 : v8::Local<v8::FunctionTemplate> callback =
2355 0 : v8::FunctionTemplate::New(isolate, SerializedCallback);
2356 : v8::Local<v8::Value> function =
2357 0 : callback->GetFunction(context).ToLocalChecked();
2358 0 : CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
2359 0 : ExpectInt32("f()", 42);
2360 :
2361 0 : creator.SetDefaultContext(context);
2362 : }
2363 : v8::StartupData blob =
2364 0 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
2365 :
2366 0 : delete[] blob.data;
2367 0 : }
2368 :
2369 23723 : TEST(SnapshotCreatorTemplates) {
2370 : DisableAlwaysOpt();
2371 : v8::StartupData blob;
2372 :
2373 : {
2374 5 : InternalFieldData* a1 = new InternalFieldData{11};
2375 5 : InternalFieldData* b0 = new InternalFieldData{20};
2376 5 : InternalFieldData* c0 = new InternalFieldData{30};
2377 :
2378 5 : v8::SnapshotCreator creator(original_external_references);
2379 5 : v8::Isolate* isolate = creator.GetIsolate();
2380 : {
2381 5 : v8::HandleScope handle_scope(isolate);
2382 : v8::ExtensionConfiguration* no_extension = nullptr;
2383 : v8::Local<v8::ObjectTemplate> global_template =
2384 5 : v8::ObjectTemplate::New(isolate);
2385 : v8::Local<v8::FunctionTemplate> callback =
2386 5 : v8::FunctionTemplate::New(isolate, SerializedCallback);
2387 10 : global_template->Set(v8_str("f"), callback);
2388 : v8::Local<v8::Context> context =
2389 5 : v8::Context::New(isolate, no_extension, global_template);
2390 5 : creator.SetDefaultContext(context);
2391 5 : context = v8::Context::New(isolate, no_extension, global_template);
2392 : v8::Local<v8::ObjectTemplate> object_template =
2393 5 : v8::ObjectTemplate::New(isolate);
2394 5 : object_template->SetInternalFieldCount(3);
2395 :
2396 : v8::Context::Scope context_scope(context);
2397 5 : ExpectInt32("f()", 42);
2398 :
2399 : v8::Local<v8::Object> a =
2400 5 : object_template->NewInstance(context).ToLocalChecked();
2401 : v8::Local<v8::Object> b =
2402 5 : object_template->NewInstance(context).ToLocalChecked();
2403 : v8::Local<v8::Object> c =
2404 5 : object_template->NewInstance(context).ToLocalChecked();
2405 : v8::Local<v8::External> null_external =
2406 5 : v8::External::New(isolate, nullptr);
2407 : v8::Local<v8::External> field_external =
2408 5 : v8::External::New(isolate, &serialized_static_field);
2409 5 : a->SetInternalField(0, b);
2410 5 : a->SetAlignedPointerInInternalField(1, a1);
2411 5 : b->SetAlignedPointerInInternalField(0, b0);
2412 5 : b->SetInternalField(1, c);
2413 5 : c->SetAlignedPointerInInternalField(0, c0);
2414 5 : c->SetInternalField(1, null_external);
2415 5 : c->SetInternalField(2, field_external);
2416 20 : CHECK(context->Global()->Set(context, v8_str("a"), a).FromJust());
2417 :
2418 5 : CHECK_EQ(0u,
2419 : creator.AddContext(context, v8::SerializeInternalFieldsCallback(
2420 : SerializeInternalFields,
2421 : reinterpret_cast<void*>(2016))));
2422 5 : CHECK_EQ(0u, creator.AddTemplate(callback));
2423 10 : CHECK_EQ(1u, creator.AddTemplate(global_template));
2424 : }
2425 : blob =
2426 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
2427 :
2428 5 : delete a1;
2429 5 : delete b0;
2430 5 : delete c0;
2431 : }
2432 :
2433 : {
2434 : v8::Isolate::CreateParams params;
2435 5 : params.snapshot_blob = &blob;
2436 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
2437 5 : params.external_references = original_external_references;
2438 : // Test-appropriate equivalent of v8::Isolate::New.
2439 5 : v8::Isolate* isolate = TestIsolate::New(params);
2440 : {
2441 : v8::Isolate::Scope isolate_scope(isolate);
2442 : {
2443 : // Create a new context without a new object template.
2444 5 : v8::HandleScope handle_scope(isolate);
2445 : v8::Local<v8::Context> context =
2446 : v8::Context::FromSnapshot(
2447 : isolate, 0,
2448 : v8::DeserializeInternalFieldsCallback(
2449 5 : DeserializeInternalFields, reinterpret_cast<void*>(2017)))
2450 5 : .ToLocalChecked();
2451 : v8::Context::Scope context_scope(context);
2452 5 : ExpectInt32("f()", 42);
2453 :
2454 : // Retrieve the snapshotted object template.
2455 : v8::Local<v8::ObjectTemplate> obj_template =
2456 5 : v8::ObjectTemplate::FromSnapshot(isolate, 1).ToLocalChecked();
2457 5 : CHECK(!obj_template.IsEmpty());
2458 : v8::Local<v8::Object> object =
2459 5 : obj_template->NewInstance(context).ToLocalChecked();
2460 20 : CHECK(context->Global()->Set(context, v8_str("o"), object).FromJust());
2461 5 : ExpectInt32("o.f()", 42);
2462 : // Check that it instantiates to the same prototype.
2463 : ExpectTrue("o.f.prototype === f.prototype");
2464 :
2465 : // Retrieve the snapshotted function template.
2466 : v8::Local<v8::FunctionTemplate> fun_template =
2467 5 : v8::FunctionTemplate::FromSnapshot(isolate, 0).ToLocalChecked();
2468 5 : CHECK(!fun_template.IsEmpty());
2469 : v8::Local<v8::Function> fun =
2470 5 : fun_template->GetFunction(context).ToLocalChecked();
2471 20 : CHECK(context->Global()->Set(context, v8_str("g"), fun).FromJust());
2472 5 : ExpectInt32("g()", 42);
2473 : // Check that it instantiates to the same prototype.
2474 : ExpectTrue("g.prototype === f.prototype");
2475 :
2476 : // Retrieve embedder fields.
2477 : v8::Local<v8::Object> a = context->Global()
2478 15 : ->Get(context, v8_str("a"))
2479 5 : .ToLocalChecked()
2480 : ->ToObject(context)
2481 5 : .ToLocalChecked();
2482 : v8::Local<v8::Object> b =
2483 5 : a->GetInternalField(0)->ToObject(context).ToLocalChecked();
2484 : InternalFieldData* a1 = reinterpret_cast<InternalFieldData*>(
2485 : a->GetAlignedPointerFromInternalField(1));
2486 : v8::Local<v8::Value> a2 = a->GetInternalField(2);
2487 :
2488 : InternalFieldData* b0 = reinterpret_cast<InternalFieldData*>(
2489 : b->GetAlignedPointerFromInternalField(0));
2490 : v8::Local<v8::Object> c =
2491 5 : b->GetInternalField(1)->ToObject(context).ToLocalChecked();
2492 : v8::Local<v8::Value> b2 = b->GetInternalField(2);
2493 :
2494 : InternalFieldData* c0 = reinterpret_cast<InternalFieldData*>(
2495 : c->GetAlignedPointerFromInternalField(0));
2496 : v8::Local<v8::Value> c1 = c->GetInternalField(1);
2497 : v8::Local<v8::Value> c2 = c->GetInternalField(2);
2498 :
2499 5 : CHECK_EQ(11u, a1->data);
2500 5 : CHECK(a2->IsUndefined());
2501 5 : CHECK_EQ(20u, b0->data);
2502 5 : CHECK(b2->IsUndefined());
2503 5 : CHECK_EQ(30u, c0->data);
2504 5 : CHECK(c1->IsExternal());
2505 5 : CHECK_NULL(v8::Local<v8::External>::Cast(c1)->Value());
2506 5 : CHECK_EQ(static_cast<void*>(&serialized_static_field),
2507 : v8::Local<v8::External>::Cast(c2)->Value());
2508 :
2509 : // Accessing out of bound returns empty MaybeHandle.
2510 10 : CHECK(v8::ObjectTemplate::FromSnapshot(isolate, 2).IsEmpty());
2511 10 : CHECK(v8::FunctionTemplate::FromSnapshot(isolate, 2).IsEmpty());
2512 10 : CHECK(v8::Context::FromSnapshot(isolate, 1).IsEmpty());
2513 :
2514 25 : for (auto data : deserialized_data) delete data;
2515 5 : deserialized_data.clear();
2516 : }
2517 : }
2518 5 : isolate->Dispose();
2519 : }
2520 5 : delete[] blob.data;
2521 5 : }
2522 :
2523 23723 : TEST(SnapshotCreatorIncludeGlobalProxy) {
2524 : DisableAlwaysOpt();
2525 : v8::StartupData blob;
2526 :
2527 : {
2528 5 : v8::SnapshotCreator creator(original_external_references);
2529 5 : v8::Isolate* isolate = creator.GetIsolate();
2530 5 : v8::RegisterExtension(new SerializedExtension);
2531 5 : const char* extension_names[] = {"serialized extension"};
2532 : v8::ExtensionConfiguration extensions(1, extension_names);
2533 : {
2534 : // Set default context. This context implicitly does *not* serialize
2535 : // the global proxy, and upon deserialization one has to be created
2536 : // in the bootstrapper from the global object template.
2537 : // Side effects from extensions are persisted though.
2538 5 : v8::HandleScope handle_scope(isolate);
2539 : v8::Local<v8::ObjectTemplate> global_template =
2540 5 : v8::ObjectTemplate::New(isolate);
2541 : v8::Local<v8::FunctionTemplate> callback =
2542 5 : v8::FunctionTemplate::New(isolate, SerializedCallback);
2543 10 : global_template->Set(v8_str("f"), callback);
2544 : global_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
2545 5 : NamedPropertyGetterForSerialization));
2546 : v8::Local<v8::Context> context =
2547 5 : v8::Context::New(isolate, &extensions, global_template);
2548 : v8::Context::Scope context_scope(context);
2549 5 : ExpectInt32("f()", 42);
2550 5 : ExpectInt32("g()", 12);
2551 5 : ExpectInt32("h()", 13);
2552 5 : ExpectInt32("o.p", 7);
2553 5 : ExpectInt32("x", 2016);
2554 10 : creator.SetDefaultContext(context);
2555 : }
2556 : {
2557 : // Add additional context. This context implicitly *does* serialize
2558 : // the global proxy, and upon deserialization one has to be created
2559 : // in the bootstrapper from the global object template.
2560 : // Side effects from extensions are persisted.
2561 5 : v8::HandleScope handle_scope(isolate);
2562 : v8::Local<v8::ObjectTemplate> global_template =
2563 5 : v8::ObjectTemplate::New(isolate);
2564 : v8::Local<v8::FunctionTemplate> callback =
2565 5 : v8::FunctionTemplate::New(isolate, SerializedCallback);
2566 5 : global_template->SetInternalFieldCount(3);
2567 10 : global_template->Set(v8_str("f"), callback);
2568 : global_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
2569 5 : NamedPropertyGetterForSerialization));
2570 5 : global_template->SetAccessor(v8_str("y"), AccessorForSerialization);
2571 : v8::Local<v8::Private> priv =
2572 5 : v8::Private::ForApi(isolate, v8_str("cached"));
2573 : global_template->SetAccessorProperty(
2574 : v8_str("cached"),
2575 : v8::FunctionTemplate::NewWithCache(isolate, SerializedCallback, priv,
2576 10 : v8::Local<v8::Value>()));
2577 : v8::Local<v8::Context> context =
2578 5 : v8::Context::New(isolate, &extensions, global_template);
2579 : v8::Context::Scope context_scope(context);
2580 :
2581 20 : CHECK(context->Global()
2582 : ->SetPrivate(context, priv, v8_str("cached string"))
2583 : .FromJust());
2584 : v8::Local<v8::Private> hidden =
2585 5 : v8::Private::ForApi(isolate, v8_str("hidden"));
2586 20 : CHECK(context->Global()
2587 : ->SetPrivate(context, hidden, v8_str("hidden string"))
2588 : .FromJust());
2589 :
2590 5 : ExpectInt32("f()", 42);
2591 5 : ExpectInt32("g()", 12);
2592 5 : ExpectInt32("h()", 13);
2593 5 : ExpectInt32("o.p", 7);
2594 5 : ExpectInt32("x", 2016);
2595 5 : ExpectInt32("y", 2017);
2596 25 : CHECK(v8_str("hidden string")
2597 : ->Equals(context, context->Global()
2598 : ->GetPrivate(context, hidden)
2599 : .ToLocalChecked())
2600 : .FromJust());
2601 :
2602 5 : CHECK_EQ(0u,
2603 : creator.AddContext(context, v8::SerializeInternalFieldsCallback(
2604 : SerializeInternalFields,
2605 5 : reinterpret_cast<void*>(2016))));
2606 : }
2607 : blob =
2608 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
2609 : }
2610 :
2611 : {
2612 : v8::Isolate::CreateParams params;
2613 5 : params.snapshot_blob = &blob;
2614 5 : params.array_buffer_allocator = CcTest::array_buffer_allocator();
2615 5 : params.external_references = original_external_references;
2616 : // Test-appropriate equivalent of v8::Isolate::New.
2617 5 : v8::Isolate* isolate = TestIsolate::New(params);
2618 : {
2619 : v8::Isolate::Scope isolate_scope(isolate);
2620 : // We can introduce new extensions, which could override the already
2621 : // snapshotted extension.
2622 : v8::Extension* extension = new v8::Extension("new extension",
2623 : "function i() { return 24; }"
2624 : "function j() { return 25; }"
2625 5 : "if (o.p == 7) o.p++;");
2626 : extension->set_auto_enable(true);
2627 5 : v8::RegisterExtension(extension);
2628 : {
2629 : // Create a new context from default context snapshot. This will
2630 : // create a new global object from a new global object template
2631 : // without the interceptor.
2632 5 : v8::HandleScope handle_scope(isolate);
2633 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2634 : v8::Context::Scope context_scope(context);
2635 5 : ExpectInt32("f()", 42);
2636 5 : ExpectInt32("g()", 12);
2637 5 : ExpectInt32("h()", 13);
2638 5 : ExpectInt32("i()", 24);
2639 5 : ExpectInt32("j()", 25);
2640 5 : ExpectInt32("o.p", 8);
2641 10 : v8::TryCatch try_catch(isolate);
2642 5 : CHECK(CompileRun("x").IsEmpty());
2643 10 : CHECK(try_catch.HasCaught());
2644 : }
2645 : {
2646 : // Create a new context from first additional context snapshot. This
2647 : // will use the global object from the snapshot, including interceptor.
2648 5 : v8::HandleScope handle_scope(isolate);
2649 : v8::Local<v8::Context> context =
2650 : v8::Context::FromSnapshot(
2651 : isolate, 0,
2652 : v8::DeserializeInternalFieldsCallback(
2653 5 : DeserializeInternalFields, reinterpret_cast<void*>(2017)))
2654 5 : .ToLocalChecked();
2655 :
2656 : {
2657 : v8::Context::Scope context_scope(context);
2658 5 : ExpectInt32("f()", 42);
2659 5 : ExpectInt32("g()", 12);
2660 5 : ExpectInt32("h()", 13);
2661 5 : ExpectInt32("i()", 24);
2662 5 : ExpectInt32("j()", 25);
2663 5 : ExpectInt32("o.p", 8);
2664 5 : ExpectInt32("x", 2016);
2665 : v8::Local<v8::Private> hidden =
2666 5 : v8::Private::ForApi(isolate, v8_str("hidden"));
2667 25 : CHECK(v8_str("hidden string")
2668 : ->Equals(context, context->Global()
2669 : ->GetPrivate(context, hidden)
2670 : .ToLocalChecked())
2671 : .FromJust());
2672 5 : ExpectString("cached", "cached string");
2673 : }
2674 :
2675 5 : v8::Local<v8::Object> global = context->Global();
2676 5 : CHECK_EQ(3, global->InternalFieldCount());
2677 5 : context->DetachGlobal();
2678 :
2679 : // New context, but reuse global proxy.
2680 : v8::ExtensionConfiguration* no_extensions = nullptr;
2681 : v8::Local<v8::Context> context2 =
2682 : v8::Context::FromSnapshot(
2683 : isolate, 0,
2684 : v8::DeserializeInternalFieldsCallback(
2685 : DeserializeInternalFields, reinterpret_cast<void*>(2017)),
2686 5 : no_extensions, global)
2687 5 : .ToLocalChecked();
2688 : {
2689 : v8::Context::Scope context_scope(context2);
2690 5 : ExpectInt32("f()", 42);
2691 5 : ExpectInt32("g()", 12);
2692 5 : ExpectInt32("h()", 13);
2693 5 : ExpectInt32("i()", 24);
2694 5 : ExpectInt32("j()", 25);
2695 5 : ExpectInt32("o.p", 8);
2696 5 : ExpectInt32("x", 2016);
2697 : v8::Local<v8::Private> hidden =
2698 5 : v8::Private::ForApi(isolate, v8_str("hidden"));
2699 25 : CHECK(v8_str("hidden string")
2700 : ->Equals(context2, context2->Global()
2701 : ->GetPrivate(context2, hidden)
2702 : .ToLocalChecked())
2703 : .FromJust());
2704 :
2705 : // Set cached accessor property again.
2706 : v8::Local<v8::Private> priv =
2707 5 : v8::Private::ForApi(isolate, v8_str("cached"));
2708 20 : CHECK(context2->Global()
2709 : ->SetPrivate(context2, priv, v8_str("cached string 1"))
2710 : .FromJust());
2711 5 : ExpectString("cached", "cached string 1");
2712 : }
2713 :
2714 15 : CHECK(context2->Global()->Equals(context2, global).FromJust());
2715 : }
2716 : }
2717 5 : isolate->Dispose();
2718 : }
2719 5 : delete[] blob.data;
2720 5 : }
2721 :
2722 23723 : UNINITIALIZED_TEST(ReinitializeStringHashSeedNotRehashable) {
2723 : DisableAlwaysOpt();
2724 5 : i::FLAG_rehash_snapshot = true;
2725 5 : i::FLAG_hash_seed = 42;
2726 5 : i::FLAG_allow_natives_syntax = true;
2727 : v8::StartupData blob;
2728 : {
2729 5 : v8::SnapshotCreator creator;
2730 5 : v8::Isolate* isolate = creator.GetIsolate();
2731 : {
2732 5 : v8::HandleScope handle_scope(isolate);
2733 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2734 : v8::Context::Scope context_scope(context);
2735 : // Create dictionary mode object.
2736 : CompileRun(
2737 : "var a = {};"
2738 : "a.b = 1;"
2739 : "a.c = 2;"
2740 : "delete a.b;");
2741 5 : ExpectInt32("a.c", 2);
2742 10 : creator.SetDefaultContext(context);
2743 : }
2744 : blob =
2745 5 : creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
2746 : }
2747 :
2748 5 : i::FLAG_hash_seed = 1337;
2749 : v8::Isolate::CreateParams create_params;
2750 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
2751 5 : create_params.snapshot_blob = &blob;
2752 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
2753 : {
2754 : // Check that no rehashing has been performed.
2755 5 : CHECK_EQ(42, reinterpret_cast<i::Isolate*>(isolate)->heap()->HashSeed());
2756 : v8::Isolate::Scope isolate_scope(isolate);
2757 10 : v8::HandleScope handle_scope(isolate);
2758 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
2759 5 : CHECK(!context.IsEmpty());
2760 : v8::Context::Scope context_scope(context);
2761 5 : ExpectInt32("a.c", 2);
2762 : }
2763 5 : isolate->Dispose();
2764 5 : delete[] blob.data;
2765 5 : }
2766 :
2767 23723 : TEST(SerializationMemoryStats) {
2768 5 : FLAG_profile_deserialization = true;
2769 5 : FLAG_always_opt = false;
2770 5 : v8::StartupData blob = v8::V8::CreateSnapshotDataBlob();
2771 5 : delete[] blob.data;
2772 5 : }
2773 :
2774 23723 : TEST(BuiltinsHaveBuiltinIdForLazyDeserialization) {
2775 5 : CcTest::InitializeVM();
2776 : Isolate* isolate = CcTest::i_isolate();
2777 : i::HandleScope scope(isolate);
2778 :
2779 5 : CHECK(Builtins::IsLazy(Builtins::kRegExpPrototypeExec));
2780 10 : CHECK_EQ(Builtins::kRegExpPrototypeExec,
2781 : isolate->regexp_exec_function()
2782 : ->shared()
2783 : ->lazy_deserialization_builtin_id());
2784 5 : CHECK(Builtins::IsLazy(Builtins::kAsyncIteratorValueUnwrap));
2785 10 : CHECK_EQ(Builtins::kAsyncIteratorValueUnwrap,
2786 : isolate->async_iterator_value_unwrap_shared_fun()
2787 : ->lazy_deserialization_builtin_id());
2788 :
2789 5 : CHECK(!Builtins::IsLazy(Builtins::kIllegal));
2790 10 : CHECK(!isolate->opaque_reference_function()
2791 : ->shared()
2792 : ->HasLazyDeserializationBuiltinId());
2793 5 : }
2794 :
2795 : } // namespace internal
2796 71154 : } // namespace v8
|