blob: 45da25024f74c1d49664fc1cd8f7d23539cabeac [file] [log] [blame]
Leon Clarkee46be812010-01-19 14:06:41 +00001// Copyright 2007-2010 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// 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
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030#include <sys/stat.h>
Steve Blocka7e24c12009-10-30 11:49:00 +000031
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032#include "src/v8.h"
33
34#include "src/bootstrapper.h"
35#include "src/compilation-cache.h"
36#include "src/debug.h"
37#include "src/heap/spaces.h"
38#include "src/natives.h"
39#include "src/objects.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040040#include "src/runtime/runtime.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041#include "src/scopeinfo.h"
42#include "src/serialize.h"
43#include "src/snapshot.h"
44#include "test/cctest/cctest.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000045
46using namespace v8::internal;
47
Steve Blocka7e24c12009-10-30 11:49:00 +000048
49template <class T>
50static Address AddressOf(T id) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000051 return ExternalReference(id, CcTest::i_isolate()).address();
Steve Blocka7e24c12009-10-30 11:49:00 +000052}
53
54
55template <class T>
56static uint32_t Encode(const ExternalReferenceEncoder& encoder, T id) {
57 return encoder.Encode(AddressOf(id));
58}
59
60
61static int make_code(TypeCode type, int id) {
62 return static_cast<uint32_t>(type) << kReferenceTypeShift | id;
63}
64
65
Steve Blocka7e24c12009-10-30 11:49:00 +000066TEST(ExternalReferenceEncoder) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000067 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000068 v8::V8::Initialize();
69
Ben Murdochb8a8cc12014-11-26 15:28:44 +000070 ExternalReferenceEncoder encoder(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +010071 CHECK_EQ(make_code(BUILTIN, Builtins::kArrayCode),
72 Encode(encoder, Builtins::kArrayCode));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010073 CHECK_EQ(make_code(v8::internal::RUNTIME_FUNCTION, Runtime::kAbort),
Steve Blocka7e24c12009-10-30 11:49:00 +000074 Encode(encoder, Runtime::kAbort));
Steve Blockd0582a62009-12-15 09:54:21 +000075 ExternalReference stack_limit_address =
Steve Block44f0eee2011-05-26 01:26:41 +010076 ExternalReference::address_of_stack_limit(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000077 CHECK_EQ(make_code(UNCLASSIFIED, 2),
Steve Blockd0582a62009-12-15 09:54:21 +000078 encoder.Encode(stack_limit_address.address()));
79 ExternalReference real_stack_limit_address =
Steve Block44f0eee2011-05-26 01:26:41 +010080 ExternalReference::address_of_real_stack_limit(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000081 CHECK_EQ(make_code(UNCLASSIFIED, 3),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082 encoder.Encode(real_stack_limit_address.address()));
83 CHECK_EQ(make_code(UNCLASSIFIED, 8),
84 encoder.Encode(ExternalReference::debug_break(isolate).address()));
85 CHECK_EQ(
86 make_code(UNCLASSIFIED, 4),
87 encoder.Encode(ExternalReference::new_space_start(isolate).address()));
88 CHECK_EQ(
89 make_code(UNCLASSIFIED, 1),
90 encoder.Encode(ExternalReference::roots_array_start(isolate).address()));
91 CHECK_EQ(make_code(UNCLASSIFIED, 34),
92 encoder.Encode(ExternalReference::cpu_features().address()));
Steve Blocka7e24c12009-10-30 11:49:00 +000093}
94
95
96TEST(ExternalReferenceDecoder) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000097 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000098 v8::V8::Initialize();
99
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100 ExternalReferenceDecoder decoder(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +0100101 CHECK_EQ(AddressOf(Builtins::kArrayCode),
102 decoder.Decode(make_code(BUILTIN, Builtins::kArrayCode)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000103 CHECK_EQ(AddressOf(Runtime::kAbort),
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100104 decoder.Decode(make_code(v8::internal::RUNTIME_FUNCTION,
105 Runtime::kAbort)));
Steve Block44f0eee2011-05-26 01:26:41 +0100106 CHECK_EQ(ExternalReference::address_of_stack_limit(isolate).address(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000107 decoder.Decode(make_code(UNCLASSIFIED, 2)));
Steve Block44f0eee2011-05-26 01:26:41 +0100108 CHECK_EQ(ExternalReference::address_of_real_stack_limit(isolate).address(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000109 decoder.Decode(make_code(UNCLASSIFIED, 3)));
Steve Block44f0eee2011-05-26 01:26:41 +0100110 CHECK_EQ(ExternalReference::debug_break(isolate).address(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111 decoder.Decode(make_code(UNCLASSIFIED, 8)));
Steve Block44f0eee2011-05-26 01:26:41 +0100112 CHECK_EQ(ExternalReference::new_space_start(isolate).address(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 decoder.Decode(make_code(UNCLASSIFIED, 4)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000114}
115
116
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400117void WritePayload(const Vector<const byte>& payload, const char* file_name) {
118 FILE* file = v8::base::OS::FOpen(file_name, "wb");
119 if (file == NULL) {
120 PrintF("Unable to write to snapshot file \"%s\"\n", file_name);
121 exit(1);
Leon Clarked91b9f72010-01-27 17:25:45 +0000122 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400123 size_t written = fwrite(payload.begin(), 1, payload.length(), file);
124 if (written != static_cast<size_t>(payload.length())) {
125 i::PrintF("Writing snapshot file failed.. Aborting.\n");
126 exit(1);
Leon Clarked91b9f72010-01-27 17:25:45 +0000127 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400128 fclose(file);
Leon Clarked91b9f72010-01-27 17:25:45 +0000129}
130
131
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132static bool WriteToFile(Isolate* isolate, const char* snapshot_file) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400133 SnapshotByteSink sink;
134 StartupSerializer ser(isolate, &sink);
Leon Clarked91b9f72010-01-27 17:25:45 +0000135 ser.Serialize();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400136 SnapshotData snapshot_data(sink, ser);
137 WritePayload(snapshot_data.RawData(), snapshot_file);
Leon Clarked91b9f72010-01-27 17:25:45 +0000138 return true;
139}
140
141
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000142static void Serialize(v8::Isolate* isolate) {
Steve Blockd0582a62009-12-15 09:54:21 +0000143 // We have to create one context. One reason for this is so that the builtins
144 // can be loaded from v8natives.js and their addresses can be processed. This
145 // will clear the pending fixups array, which would otherwise contain GC roots
146 // that would confuse the serialization/deserialization process.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000147 v8::Isolate::Scope isolate_scope(isolate);
148 {
149 v8::HandleScope scope(isolate);
150 v8::Context::New(isolate);
151 }
152
153 Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400154 internal_isolate->heap()->CollectAllAvailableGarbage("serialize");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000155 WriteToFile(internal_isolate, FLAG_testing_serialization_file);
Steve Blocka7e24c12009-10-30 11:49:00 +0000156}
157
158
Steve Blockd0582a62009-12-15 09:54:21 +0000159// Test that the whole heap can be serialized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000160UNINITIALIZED_TEST(Serialize) {
161 if (!Snapshot::HaveASnapshotToStartFrom()) {
162 v8::Isolate::CreateParams params;
163 params.enable_serializer = true;
164 v8::Isolate* isolate = v8::Isolate::New(params);
165 Serialize(isolate);
166 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000167}
168
169
Steve Blockd0582a62009-12-15 09:54:21 +0000170// Test that heap serialization is non-destructive.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171UNINITIALIZED_TEST(SerializeTwice) {
172 if (!Snapshot::HaveASnapshotToStartFrom()) {
173 v8::Isolate::CreateParams params;
174 params.enable_serializer = true;
175 v8::Isolate* isolate = v8::Isolate::New(params);
176 Serialize(isolate);
177 Serialize(isolate);
178 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000179}
180
Steve Blockd0582a62009-12-15 09:54:21 +0000181
Steve Blocka7e24c12009-10-30 11:49:00 +0000182//----------------------------------------------------------------------------
183// Tests that the heap can be deserialized.
184
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185v8::Isolate* InitializeFromFile(const char* snapshot_file) {
186 int len;
187 byte* str = ReadBytes(snapshot_file, &len);
188 if (!str) return NULL;
189 v8::Isolate* v8_isolate = NULL;
190 {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400191 SnapshotData snapshot_data(Vector<const byte>(str, len));
192 Deserializer deserializer(&snapshot_data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193 Isolate* isolate = Isolate::NewForTesting();
194 v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
195 v8::Isolate::Scope isolate_scope(v8_isolate);
196 isolate->Init(&deserializer);
197 }
198 DeleteArray(str);
199 return v8_isolate;
200}
201
202
203static v8::Isolate* Deserialize() {
204 v8::Isolate* isolate = InitializeFromFile(FLAG_testing_serialization_file);
205 CHECK(isolate);
206 return isolate;
207}
208
209
210static void SanityCheck(v8::Isolate* v8_isolate) {
211 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
212 v8::HandleScope scope(v8_isolate);
213#ifdef VERIFY_HEAP
214 isolate->heap()->Verify();
215#endif
216 CHECK(isolate->global_object()->IsJSObject());
217 CHECK(isolate->native_context()->IsContext());
218 CHECK(isolate->heap()->string_table()->IsStringTable());
219 isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("Empty"));
220}
221
222
223UNINITIALIZED_DEPENDENT_TEST(Deserialize, Serialize) {
224 // The serialize-deserialize tests only work if the VM is built without
225 // serialization. That doesn't matter. We don't need to be able to
226 // serialize a snapshot in a VM that is booted from a snapshot.
227 if (!Snapshot::HaveASnapshotToStartFrom()) {
228 v8::Isolate* isolate = Deserialize();
229 {
230 v8::HandleScope handle_scope(isolate);
231 v8::Isolate::Scope isolate_scope(isolate);
232
233 v8::Local<v8::Context> env = v8::Context::New(isolate);
234 env->Enter();
235
236 SanityCheck(isolate);
237 }
238 isolate->Dispose();
239 }
240}
241
242
243UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerialization,
244 SerializeTwice) {
245 if (!Snapshot::HaveASnapshotToStartFrom()) {
246 v8::Isolate* isolate = Deserialize();
247 {
248 v8::Isolate::Scope isolate_scope(isolate);
249 v8::HandleScope handle_scope(isolate);
250
251 v8::Local<v8::Context> env = v8::Context::New(isolate);
252 env->Enter();
253
254 SanityCheck(isolate);
255 }
256 isolate->Dispose();
257 }
258}
259
260
261UNINITIALIZED_DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
262 if (!Snapshot::HaveASnapshotToStartFrom()) {
263 v8::Isolate* isolate = Deserialize();
264 {
265 v8::Isolate::Scope isolate_scope(isolate);
266 v8::HandleScope handle_scope(isolate);
267
268
269 v8::Local<v8::Context> env = v8::Context::New(isolate);
270 env->Enter();
271
272 const char* c_source = "\"1234\".length";
273 v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
274 v8::Local<v8::Script> script = v8::Script::Compile(source);
275 CHECK_EQ(4, script->Run()->Int32Value());
276 }
277 isolate->Dispose();
278 }
279}
280
281
282UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
283 SerializeTwice) {
284 if (!Snapshot::HaveASnapshotToStartFrom()) {
285 v8::Isolate* isolate = Deserialize();
286 {
287 v8::Isolate::Scope isolate_scope(isolate);
288 v8::HandleScope handle_scope(isolate);
289
290 v8::Local<v8::Context> env = v8::Context::New(isolate);
291 env->Enter();
292
293 const char* c_source = "\"1234\".length";
294 v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
295 v8::Local<v8::Script> script = v8::Script::Compile(source);
296 CHECK_EQ(4, script->Run()->Int32Value());
297 }
298 isolate->Dispose();
299 }
300}
301
302
303UNINITIALIZED_TEST(PartialSerialization) {
304 if (!Snapshot::HaveASnapshotToStartFrom()) {
305 v8::Isolate::CreateParams params;
306 params.enable_serializer = true;
307 v8::Isolate* v8_isolate = v8::Isolate::New(params);
308 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
309 v8_isolate->Enter();
310 {
311 Heap* heap = isolate->heap();
312
313 v8::Persistent<v8::Context> env;
314 {
315 HandleScope scope(isolate);
316 env.Reset(v8_isolate, v8::Context::New(v8_isolate));
317 }
318 DCHECK(!env.IsEmpty());
319 {
320 v8::HandleScope handle_scope(v8_isolate);
321 v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
322 }
323 // Make sure all builtin scripts are cached.
324 {
325 HandleScope scope(isolate);
326 for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
327 isolate->bootstrapper()->NativesSourceLookup(i);
328 }
329 }
330 heap->CollectAllGarbage(Heap::kNoGCFlags);
331 heap->CollectAllGarbage(Heap::kNoGCFlags);
332
333 Object* raw_foo;
334 {
335 v8::HandleScope handle_scope(v8_isolate);
336 v8::Local<v8::String> foo = v8::String::NewFromUtf8(v8_isolate, "foo");
337 DCHECK(!foo.IsEmpty());
338 raw_foo = *(v8::Utils::OpenHandle(*foo));
339 }
340
341 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
342 Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
343 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
344
345 {
346 v8::HandleScope handle_scope(v8_isolate);
347 v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
348 }
349 env.Reset();
350
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400351 SnapshotByteSink startup_sink;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000352 StartupSerializer startup_serializer(isolate, &startup_sink);
353 startup_serializer.SerializeStrongReferences();
354
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400355 SnapshotByteSink partial_sink;
356 PartialSerializer partial_serializer(isolate, &startup_serializer,
357 &partial_sink);
358 partial_serializer.Serialize(&raw_foo);
359
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000360 startup_serializer.SerializeWeakReferences();
361
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400362 SnapshotData startup_snapshot(startup_sink, startup_serializer);
363 SnapshotData partial_snapshot(partial_sink, partial_serializer);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000364
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400365 WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
366 WritePayload(startup_snapshot.RawData(), startup_name.start());
367
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000368 startup_name.Dispose();
369 }
370 v8_isolate->Exit();
371 v8_isolate->Dispose();
372 }
373}
374
375
376UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
377 if (!Snapshot::HaveASnapshotToStartFrom()) {
Andrei Popescu31002712010-02-23 13:46:05 +0000378 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
379 Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000380 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
Andrei Popescu31002712010-02-23 13:46:05 +0000381
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000382 v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
383 CHECK(v8_isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800384 startup_name.Dispose();
Andrei Popescu31002712010-02-23 13:46:05 +0000385 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000386 v8::Isolate::Scope isolate_scope(v8_isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000387
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000388 const char* file_name = FLAG_testing_serialization_file;
Andrei Popescu31002712010-02-23 13:46:05 +0000389
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000390 int snapshot_size = 0;
391 byte* snapshot = ReadBytes(file_name, &snapshot_size);
392
393 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
394 Object* root;
395 {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400396 SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
397 Deserializer deserializer(&snapshot_data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000398 deserializer.DeserializePartial(isolate, &root);
399 CHECK(root->IsString());
400 }
401 HandleScope handle_scope(isolate);
402 Handle<Object> root_handle(root, isolate);
403
404
405 Object* root2;
406 {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400407 SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
408 Deserializer deserializer(&snapshot_data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000409 deserializer.DeserializePartial(isolate, &root2);
410 CHECK(root2->IsString());
411 CHECK(*root_handle == root2);
412 }
Andrei Popescu31002712010-02-23 13:46:05 +0000413 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000414 v8_isolate->Dispose();
Leon Clarked91b9f72010-01-27 17:25:45 +0000415 }
Andrei Popescu31002712010-02-23 13:46:05 +0000416}
Leon Clarked91b9f72010-01-27 17:25:45 +0000417
Andrei Popescu31002712010-02-23 13:46:05 +0000418
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000419UNINITIALIZED_TEST(ContextSerialization) {
420 if (!Snapshot::HaveASnapshotToStartFrom()) {
421 v8::Isolate::CreateParams params;
422 params.enable_serializer = true;
423 v8::Isolate* v8_isolate = v8::Isolate::New(params);
424 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
425 Heap* heap = isolate->heap();
426 {
427 v8::Isolate::Scope isolate_scope(v8_isolate);
Andrei Popescu31002712010-02-23 13:46:05 +0000428
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000429 v8::Persistent<v8::Context> env;
430 {
431 HandleScope scope(isolate);
432 env.Reset(v8_isolate, v8::Context::New(v8_isolate));
433 }
434 DCHECK(!env.IsEmpty());
435 {
436 v8::HandleScope handle_scope(v8_isolate);
437 v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
438 }
439 // Make sure all builtin scripts are cached.
440 {
441 HandleScope scope(isolate);
442 for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
443 isolate->bootstrapper()->NativesSourceLookup(i);
444 }
445 }
446 // If we don't do this then we end up with a stray root pointing at the
447 // context even after we have disposed of env.
448 heap->CollectAllGarbage(Heap::kNoGCFlags);
449
450 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
451 Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
452 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
453
454 {
455 v8::HandleScope handle_scope(v8_isolate);
456 v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
457 }
458
459 i::Object* raw_context = *v8::Utils::OpenPersistent(env);
460
461 env.Reset();
462
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400463 SnapshotByteSink startup_sink;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000464 StartupSerializer startup_serializer(isolate, &startup_sink);
465 startup_serializer.SerializeStrongReferences();
466
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400467 SnapshotByteSink partial_sink;
468 PartialSerializer partial_serializer(isolate, &startup_serializer,
469 &partial_sink);
470 partial_serializer.Serialize(&raw_context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000471 startup_serializer.SerializeWeakReferences();
472
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400473 SnapshotData startup_snapshot(startup_sink, startup_serializer);
474 SnapshotData partial_snapshot(partial_sink, partial_serializer);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000475
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400476 WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
477 WritePayload(startup_snapshot.RawData(), startup_name.start());
478
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000479 startup_name.Dispose();
Andrei Popescu31002712010-02-23 13:46:05 +0000480 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000481 v8_isolate->Dispose();
Andrei Popescu31002712010-02-23 13:46:05 +0000482 }
Andrei Popescu31002712010-02-23 13:46:05 +0000483}
484
485
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000486UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization, ContextSerialization) {
487 if (!Snapshot::HaveASnapshotToStartFrom()) {
Andrei Popescu31002712010-02-23 13:46:05 +0000488 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
489 Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000490 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
Andrei Popescu31002712010-02-23 13:46:05 +0000491
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000492 v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
493 CHECK(v8_isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800494 startup_name.Dispose();
Andrei Popescu31002712010-02-23 13:46:05 +0000495 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000496 v8::Isolate::Scope isolate_scope(v8_isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000497
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000498 const char* file_name = FLAG_testing_serialization_file;
Andrei Popescu31002712010-02-23 13:46:05 +0000499
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500 int snapshot_size = 0;
501 byte* snapshot = ReadBytes(file_name, &snapshot_size);
Leon Clarkee46be812010-01-19 14:06:41 +0000502
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000503 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
504 Object* root;
505 {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400506 SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
507 Deserializer deserializer(&snapshot_data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000508 deserializer.DeserializePartial(isolate, &root);
509 CHECK(root->IsContext());
Leon Clarkee46be812010-01-19 14:06:41 +0000510 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000511 HandleScope handle_scope(isolate);
512 Handle<Object> root_handle(root, isolate);
Leon Clarkee46be812010-01-19 14:06:41 +0000513
Leon Clarkee46be812010-01-19 14:06:41 +0000514
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000515 Object* root2;
516 {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400517 SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
518 Deserializer deserializer(&snapshot_data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000519 deserializer.DeserializePartial(isolate, &root2);
520 CHECK(root2->IsContext());
521 CHECK(*root_handle != root2);
Leon Clarkee46be812010-01-19 14:06:41 +0000522 }
Leon Clarkee46be812010-01-19 14:06:41 +0000523 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000524 v8_isolate->Dispose();
Leon Clarkee46be812010-01-19 14:06:41 +0000525 }
526}
527
528
Steve Block3ce2e202009-11-05 08:53:23 +0000529TEST(TestThatAlwaysSucceeds) {
530}
531
532
533TEST(TestThatAlwaysFails) {
534 bool ArtificialFailure = false;
535 CHECK(ArtificialFailure);
536}
537
538
539DEPENDENT_TEST(DependentTestThatAlwaysFails, TestThatAlwaysSucceeds) {
540 bool ArtificialFailure2 = false;
541 CHECK(ArtificialFailure2);
542}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000543
544
545int CountBuiltins() {
546 // Check that we have not deserialized any additional builtin.
547 HeapIterator iterator(CcTest::heap());
548 DisallowHeapAllocation no_allocation;
549 int counter = 0;
550 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
551 if (obj->IsCode() && Code::cast(obj)->kind() == Code::BUILTIN) counter++;
552 }
553 return counter;
554}
555
556
557TEST(SerializeToplevelOnePlusOne) {
558 FLAG_serialize_toplevel = true;
559 LocalContext context;
560 Isolate* isolate = CcTest::i_isolate();
561 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
562
563 v8::HandleScope scope(CcTest::isolate());
564
565 const char* source = "1 + 1";
566
567 Handle<String> orig_source = isolate->factory()
568 ->NewStringFromUtf8(CStrVector(source))
569 .ToHandleChecked();
570 Handle<String> copy_source = isolate->factory()
571 ->NewStringFromUtf8(CStrVector(source))
572 .ToHandleChecked();
573 CHECK(!orig_source.is_identical_to(copy_source));
574 CHECK(orig_source->Equals(*copy_source));
575
576 ScriptData* cache = NULL;
577
578 Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
579 orig_source, Handle<String>(), 0, 0, false,
580 Handle<Context>(isolate->native_context()), NULL, &cache,
581 v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
582
583 int builtins_count = CountBuiltins();
584
585 Handle<SharedFunctionInfo> copy;
586 {
587 DisallowCompilation no_compile_expected(isolate);
588 copy = Compiler::CompileScript(
589 copy_source, Handle<String>(), 0, 0, false,
590 Handle<Context>(isolate->native_context()), NULL, &cache,
591 v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
592 }
593
594 CHECK_NE(*orig, *copy);
595 CHECK(Script::cast(copy->script())->source() == *copy_source);
596
597 Handle<JSFunction> copy_fun =
598 isolate->factory()->NewFunctionFromSharedFunctionInfo(
599 copy, isolate->native_context());
600 Handle<JSObject> global(isolate->context()->global_object());
601 Handle<Object> copy_result =
602 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
603 CHECK_EQ(2, Handle<Smi>::cast(copy_result)->value());
604
605 CHECK_EQ(builtins_count, CountBuiltins());
606
607 delete cache;
608}
609
610
611TEST(SerializeToplevelInternalizedString) {
612 FLAG_serialize_toplevel = true;
613 LocalContext context;
614 Isolate* isolate = CcTest::i_isolate();
615 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
616
617 v8::HandleScope scope(CcTest::isolate());
618
619 const char* source = "'string1'";
620
621 Handle<String> orig_source = isolate->factory()
622 ->NewStringFromUtf8(CStrVector(source))
623 .ToHandleChecked();
624 Handle<String> copy_source = isolate->factory()
625 ->NewStringFromUtf8(CStrVector(source))
626 .ToHandleChecked();
627 CHECK(!orig_source.is_identical_to(copy_source));
628 CHECK(orig_source->Equals(*copy_source));
629
630 Handle<JSObject> global(isolate->context()->global_object());
631 ScriptData* cache = NULL;
632
633 Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
634 orig_source, Handle<String>(), 0, 0, false,
635 Handle<Context>(isolate->native_context()), NULL, &cache,
636 v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
637 Handle<JSFunction> orig_fun =
638 isolate->factory()->NewFunctionFromSharedFunctionInfo(
639 orig, isolate->native_context());
640 Handle<Object> orig_result =
641 Execution::Call(isolate, orig_fun, global, 0, NULL).ToHandleChecked();
642 CHECK(orig_result->IsInternalizedString());
643
644 int builtins_count = CountBuiltins();
645
646 Handle<SharedFunctionInfo> copy;
647 {
648 DisallowCompilation no_compile_expected(isolate);
649 copy = Compiler::CompileScript(
650 copy_source, Handle<String>(), 0, 0, false,
651 Handle<Context>(isolate->native_context()), NULL, &cache,
652 v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
653 }
654 CHECK_NE(*orig, *copy);
655 CHECK(Script::cast(copy->script())->source() == *copy_source);
656
657 Handle<JSFunction> copy_fun =
658 isolate->factory()->NewFunctionFromSharedFunctionInfo(
659 copy, isolate->native_context());
660 CHECK_NE(*orig_fun, *copy_fun);
661 Handle<Object> copy_result =
662 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
663 CHECK(orig_result.is_identical_to(copy_result));
664 Handle<String> expected =
665 isolate->factory()->NewStringFromAsciiChecked("string1");
666
667 CHECK(Handle<String>::cast(copy_result)->Equals(*expected));
668 CHECK_EQ(builtins_count, CountBuiltins());
669
670 delete cache;
671}
672
673
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400674Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head,
675 Vector<const uint8_t> body,
676 Vector<const uint8_t> tail, int repeats) {
677 int source_length = head.length() + body.length() * repeats + tail.length();
678 uint8_t* source = NewArray<uint8_t>(static_cast<size_t>(source_length));
679 CopyChars(source, head.start(), head.length());
680 for (int i = 0; i < repeats; i++) {
681 CopyChars(source + head.length() + i * body.length(), body.start(),
682 body.length());
683 }
684 CopyChars(source + head.length() + repeats * body.length(), tail.start(),
685 tail.length());
686 return Vector<const uint8_t>(const_cast<const uint8_t*>(source),
687 source_length);
688}
689
690
691TEST(SerializeToplevelLargeCodeObject) {
692 FLAG_serialize_toplevel = true;
693 LocalContext context;
694 Isolate* isolate = CcTest::i_isolate();
695 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
696
697 v8::HandleScope scope(CcTest::isolate());
698
699 Vector<const uint8_t> source =
700 ConstructSource(STATIC_CHAR_VECTOR("var j=1; try { if (j) throw 1;"),
701 STATIC_CHAR_VECTOR("for(var i=0;i<1;i++)j++;"),
702 STATIC_CHAR_VECTOR("} catch (e) { j=7; } j"), 10000);
703 Handle<String> source_str =
704 isolate->factory()->NewStringFromOneByte(source).ToHandleChecked();
705
706 Handle<JSObject> global(isolate->context()->global_object());
707 ScriptData* cache = NULL;
708
709 Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
710 source_str, Handle<String>(), 0, 0, false,
711 Handle<Context>(isolate->native_context()), NULL, &cache,
712 v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
713
714 CHECK(isolate->heap()->InSpace(orig->code(), LO_SPACE));
715
716 Handle<SharedFunctionInfo> copy;
717 {
718 DisallowCompilation no_compile_expected(isolate);
719 copy = Compiler::CompileScript(
720 source_str, Handle<String>(), 0, 0, false,
721 Handle<Context>(isolate->native_context()), NULL, &cache,
722 v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
723 }
724 CHECK_NE(*orig, *copy);
725
726 Handle<JSFunction> copy_fun =
727 isolate->factory()->NewFunctionFromSharedFunctionInfo(
728 copy, isolate->native_context());
729
730 Handle<Object> copy_result =
731 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
732
733 int result_int;
734 CHECK(copy_result->ToInt32(&result_int));
735 CHECK_EQ(7, result_int);
736
737 delete cache;
738 source.Dispose();
739}
740
741
742TEST(SerializeToplevelLargeStrings) {
743 FLAG_serialize_toplevel = true;
744 LocalContext context;
745 Isolate* isolate = CcTest::i_isolate();
746 Factory* f = isolate->factory();
747 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
748
749 v8::HandleScope scope(CcTest::isolate());
750
751 Vector<const uint8_t> source_s = ConstructSource(
752 STATIC_CHAR_VECTOR("var s = \""), STATIC_CHAR_VECTOR("abcdef"),
753 STATIC_CHAR_VECTOR("\";"), 1000000);
754 Vector<const uint8_t> source_t = ConstructSource(
755 STATIC_CHAR_VECTOR("var t = \""), STATIC_CHAR_VECTOR("uvwxyz"),
756 STATIC_CHAR_VECTOR("\"; s + t"), 999999);
757 Handle<String> source_str =
758 f->NewConsString(f->NewStringFromOneByte(source_s).ToHandleChecked(),
759 f->NewStringFromOneByte(source_t).ToHandleChecked())
760 .ToHandleChecked();
761
762 Handle<JSObject> global(isolate->context()->global_object());
763 ScriptData* cache = NULL;
764
765 Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
766 source_str, Handle<String>(), 0, 0, false,
767 Handle<Context>(isolate->native_context()), NULL, &cache,
768 v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
769
770 Handle<SharedFunctionInfo> copy;
771 {
772 DisallowCompilation no_compile_expected(isolate);
773 copy = Compiler::CompileScript(
774 source_str, Handle<String>(), 0, 0, false,
775 Handle<Context>(isolate->native_context()), NULL, &cache,
776 v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
777 }
778 CHECK_NE(*orig, *copy);
779
780 Handle<JSFunction> copy_fun =
781 isolate->factory()->NewFunctionFromSharedFunctionInfo(
782 copy, isolate->native_context());
783
784 Handle<Object> copy_result =
785 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
786
787 CHECK_EQ(6 * 1999999, Handle<String>::cast(copy_result)->length());
788 Handle<Object> property = JSObject::GetDataProperty(
789 isolate->global_object(), f->NewStringFromAsciiChecked("s"));
790 CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
791 property = JSObject::GetDataProperty(isolate->global_object(),
792 f->NewStringFromAsciiChecked("t"));
793 CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
794 // Make sure we do not serialize too much, e.g. include the source string.
795 CHECK_LT(cache->length(), 13000000);
796
797 delete cache;
798 source_s.Dispose();
799 source_t.Dispose();
800}
801
802
803TEST(SerializeToplevelThreeBigStrings) {
804 FLAG_serialize_toplevel = true;
805 LocalContext context;
806 Isolate* isolate = CcTest::i_isolate();
807 Factory* f = isolate->factory();
808 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
809
810 v8::HandleScope scope(CcTest::isolate());
811
812 Vector<const uint8_t> source_a =
813 ConstructSource(STATIC_CHAR_VECTOR("var a = \""), STATIC_CHAR_VECTOR("a"),
814 STATIC_CHAR_VECTOR("\";"), 700000);
815 Handle<String> source_a_str =
816 f->NewStringFromOneByte(source_a).ToHandleChecked();
817
818 Vector<const uint8_t> source_b =
819 ConstructSource(STATIC_CHAR_VECTOR("var b = \""), STATIC_CHAR_VECTOR("b"),
820 STATIC_CHAR_VECTOR("\";"), 600000);
821 Handle<String> source_b_str =
822 f->NewStringFromOneByte(source_b).ToHandleChecked();
823
824 Vector<const uint8_t> source_c =
825 ConstructSource(STATIC_CHAR_VECTOR("var c = \""), STATIC_CHAR_VECTOR("c"),
826 STATIC_CHAR_VECTOR("\";"), 500000);
827 Handle<String> source_c_str =
828 f->NewStringFromOneByte(source_c).ToHandleChecked();
829
830 Handle<String> source_str =
831 f->NewConsString(
832 f->NewConsString(source_a_str, source_b_str).ToHandleChecked(),
833 source_c_str).ToHandleChecked();
834
835 Handle<JSObject> global(isolate->context()->global_object());
836 ScriptData* cache = NULL;
837
838 Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
839 source_str, Handle<String>(), 0, 0, false,
840 Handle<Context>(isolate->native_context()), NULL, &cache,
841 v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
842
843 Handle<SharedFunctionInfo> copy;
844 {
845 DisallowCompilation no_compile_expected(isolate);
846 copy = Compiler::CompileScript(
847 source_str, Handle<String>(), 0, 0, false,
848 Handle<Context>(isolate->native_context()), NULL, &cache,
849 v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
850 }
851 CHECK_NE(*orig, *copy);
852
853 Handle<JSFunction> copy_fun =
854 isolate->factory()->NewFunctionFromSharedFunctionInfo(
855 copy, isolate->native_context());
856
857 USE(Execution::Call(isolate, copy_fun, global, 0, NULL));
858
859 CHECK_EQ(600000 + 700000, CompileRun("(a + b).length")->Int32Value());
860 CHECK_EQ(500000 + 600000, CompileRun("(b + c).length")->Int32Value());
861 Heap* heap = isolate->heap();
862 CHECK(heap->InSpace(
863 *v8::Utils::OpenHandle(*CompileRun("a")->ToString(CcTest::isolate())),
864 OLD_DATA_SPACE));
865 CHECK(heap->InSpace(
866 *v8::Utils::OpenHandle(*CompileRun("b")->ToString(CcTest::isolate())),
867 OLD_DATA_SPACE));
868 CHECK(heap->InSpace(
869 *v8::Utils::OpenHandle(*CompileRun("c")->ToString(CcTest::isolate())),
870 OLD_DATA_SPACE));
871
872 delete cache;
873 source_a.Dispose();
874 source_b.Dispose();
875 source_c.Dispose();
876}
877
878
879class SerializerOneByteResource
880 : public v8::String::ExternalOneByteStringResource {
881 public:
882 SerializerOneByteResource(const char* data, size_t length)
883 : data_(data), length_(length) {}
884 virtual const char* data() const { return data_; }
885 virtual size_t length() const { return length_; }
886
887 private:
888 const char* data_;
889 size_t length_;
890};
891
892
893class SerializerTwoByteResource : public v8::String::ExternalStringResource {
894 public:
895 SerializerTwoByteResource(const char* data, size_t length)
896 : data_(AsciiToTwoByteString(data)), length_(length) {}
897 ~SerializerTwoByteResource() { DeleteArray<const uint16_t>(data_); }
898
899 virtual const uint16_t* data() const { return data_; }
900 virtual size_t length() const { return length_; }
901
902 private:
903 const uint16_t* data_;
904 size_t length_;
905};
906
907
908TEST(SerializeToplevelExternalString) {
909 FLAG_serialize_toplevel = true;
910 LocalContext context;
911 Isolate* isolate = CcTest::i_isolate();
912 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
913
914 v8::HandleScope scope(CcTest::isolate());
915
916 // Obtain external internalized one-byte string.
917 SerializerOneByteResource one_byte_resource("one_byte", 8);
918 Handle<String> one_byte_string =
919 isolate->factory()->NewStringFromAsciiChecked("one_byte");
920 one_byte_string = isolate->factory()->InternalizeString(one_byte_string);
921 one_byte_string->MakeExternal(&one_byte_resource);
922 CHECK(one_byte_string->IsExternalOneByteString());
923 CHECK(one_byte_string->IsInternalizedString());
924
925 // Obtain external internalized two-byte string.
926 SerializerTwoByteResource two_byte_resource("two_byte", 8);
927 Handle<String> two_byte_string =
928 isolate->factory()->NewStringFromAsciiChecked("two_byte");
929 two_byte_string = isolate->factory()->InternalizeString(two_byte_string);
930 two_byte_string->MakeExternal(&two_byte_resource);
931 CHECK(two_byte_string->IsExternalTwoByteString());
932 CHECK(two_byte_string->IsInternalizedString());
933
934 const char* source =
935 "var o = {} \n"
936 "o.one_byte = 7; \n"
937 "o.two_byte = 8; \n"
938 "o.one_byte + o.two_byte; \n";
939 Handle<String> source_string = isolate->factory()
940 ->NewStringFromUtf8(CStrVector(source))
941 .ToHandleChecked();
942
943 Handle<JSObject> global(isolate->context()->global_object());
944 ScriptData* cache = NULL;
945
946 Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
947 source_string, Handle<String>(), 0, 0, false,
948 Handle<Context>(isolate->native_context()), NULL, &cache,
949 v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
950
951 Handle<SharedFunctionInfo> copy;
952 {
953 DisallowCompilation no_compile_expected(isolate);
954 copy = Compiler::CompileScript(
955 source_string, Handle<String>(), 0, 0, false,
956 Handle<Context>(isolate->native_context()), NULL, &cache,
957 v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
958 }
959 CHECK_NE(*orig, *copy);
960
961 Handle<JSFunction> copy_fun =
962 isolate->factory()->NewFunctionFromSharedFunctionInfo(
963 copy, isolate->native_context());
964
965 Handle<Object> copy_result =
966 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
967
968 CHECK_EQ(15.0f, copy_result->Number());
969
970 delete cache;
971}
972
973
974TEST(SerializeToplevelLargeExternalString) {
975 FLAG_serialize_toplevel = true;
976 LocalContext context;
977 Isolate* isolate = CcTest::i_isolate();
978 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
979
980 Factory* f = isolate->factory();
981
982 v8::HandleScope scope(CcTest::isolate());
983
984 // Create a huge external internalized string to use as variable name.
985 Vector<const uint8_t> string =
986 ConstructSource(STATIC_CHAR_VECTOR(""), STATIC_CHAR_VECTOR("abcdef"),
987 STATIC_CHAR_VECTOR(""), 999999);
988 Handle<String> name = f->NewStringFromOneByte(string).ToHandleChecked();
989 SerializerOneByteResource one_byte_resource(
990 reinterpret_cast<const char*>(string.start()), string.length());
991 name = f->InternalizeString(name);
992 name->MakeExternal(&one_byte_resource);
993 CHECK(name->IsExternalOneByteString());
994 CHECK(name->IsInternalizedString());
995 CHECK(isolate->heap()->InSpace(*name, LO_SPACE));
996
997 // Create the source, which is "var <literal> = 42; <literal>".
998 Handle<String> source_str =
999 f->NewConsString(
1000 f->NewConsString(f->NewStringFromAsciiChecked("var "), name)
1001 .ToHandleChecked(),
1002 f->NewConsString(f->NewStringFromAsciiChecked(" = 42; "), name)
1003 .ToHandleChecked()).ToHandleChecked();
1004
1005 Handle<JSObject> global(isolate->context()->global_object());
1006 ScriptData* cache = NULL;
1007
1008 Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
1009 source_str, Handle<String>(), 0, 0, false,
1010 Handle<Context>(isolate->native_context()), NULL, &cache,
1011 v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
1012
1013 Handle<SharedFunctionInfo> copy;
1014 {
1015 DisallowCompilation no_compile_expected(isolate);
1016 copy = Compiler::CompileScript(
1017 source_str, Handle<String>(), 0, 0, false,
1018 Handle<Context>(isolate->native_context()), NULL, &cache,
1019 v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
1020 }
1021 CHECK_NE(*orig, *copy);
1022
1023 Handle<JSFunction> copy_fun =
1024 f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
1025
1026 Handle<Object> copy_result =
1027 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
1028
1029 CHECK_EQ(42.0f, copy_result->Number());
1030
1031 delete cache;
1032 string.Dispose();
1033}
1034
1035
1036TEST(SerializeToplevelExternalScriptName) {
1037 FLAG_serialize_toplevel = true;
1038 LocalContext context;
1039 Isolate* isolate = CcTest::i_isolate();
1040 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
1041
1042 Factory* f = isolate->factory();
1043
1044 v8::HandleScope scope(CcTest::isolate());
1045
1046 const char* source =
1047 "var a = [1, 2, 3, 4];"
1048 "a.reduce(function(x, y) { return x + y }, 0)";
1049
1050 Handle<String> source_string =
1051 f->NewStringFromUtf8(CStrVector(source)).ToHandleChecked();
1052
1053 const SerializerOneByteResource one_byte_resource("one_byte", 8);
1054 Handle<String> name =
1055 f->NewExternalStringFromOneByte(&one_byte_resource).ToHandleChecked();
1056 CHECK(name->IsExternalOneByteString());
1057 CHECK(!name->IsInternalizedString());
1058
1059 Handle<JSObject> global(isolate->context()->global_object());
1060 ScriptData* cache = NULL;
1061
1062 Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
1063 source_string, name, 0, 0, false,
1064 Handle<Context>(isolate->native_context()), NULL, &cache,
1065 v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
1066
1067 Handle<SharedFunctionInfo> copy;
1068 {
1069 DisallowCompilation no_compile_expected(isolate);
1070 copy = Compiler::CompileScript(
1071 source_string, name, 0, 0, false,
1072 Handle<Context>(isolate->native_context()), NULL, &cache,
1073 v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
1074 }
1075 CHECK_NE(*orig, *copy);
1076
1077 Handle<JSFunction> copy_fun =
1078 f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
1079
1080 Handle<Object> copy_result =
1081 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
1082
1083 CHECK_EQ(10.0f, copy_result->Number());
1084
1085 delete cache;
1086}
1087
1088
1089static bool toplevel_test_code_event_found = false;
1090
1091
1092static void SerializerCodeEventListener(const v8::JitCodeEvent* event) {
1093 if (event->type == v8::JitCodeEvent::CODE_ADDED &&
1094 memcmp(event->name.str, "Script:~test", 12) == 0) {
1095 toplevel_test_code_event_found = true;
1096 }
1097}
1098
1099
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001100TEST(SerializeToplevelIsolates) {
1101 FLAG_serialize_toplevel = true;
1102
1103 const char* source = "function f() { return 'abc'; }; f() + 'def'";
1104 v8::ScriptCompiler::CachedData* cache;
1105
1106 v8::Isolate* isolate1 = v8::Isolate::New();
1107 {
1108 v8::Isolate::Scope iscope(isolate1);
1109 v8::HandleScope scope(isolate1);
1110 v8::Local<v8::Context> context = v8::Context::New(isolate1);
1111 v8::Context::Scope context_scope(context);
1112
1113 v8::Local<v8::String> source_str = v8_str(source);
1114 v8::ScriptOrigin origin(v8_str("test"));
1115 v8::ScriptCompiler::Source source(source_str, origin);
1116 v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
1117 isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
1118 const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001119 CHECK(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001120 // Persist cached data.
1121 uint8_t* buffer = NewArray<uint8_t>(data->length);
1122 MemCopy(buffer, data->data, data->length);
1123 cache = new v8::ScriptCompiler::CachedData(
1124 buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
1125
1126 v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001127 CHECK(result->ToString(isolate1)->Equals(v8_str("abcdef")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001128 }
1129 isolate1->Dispose();
1130
1131 v8::Isolate* isolate2 = v8::Isolate::New();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001132 isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
1133 SerializerCodeEventListener);
1134 toplevel_test_code_event_found = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001135 {
1136 v8::Isolate::Scope iscope(isolate2);
1137 v8::HandleScope scope(isolate2);
1138 v8::Local<v8::Context> context = v8::Context::New(isolate2);
1139 v8::Context::Scope context_scope(context);
1140
1141 v8::Local<v8::String> source_str = v8_str(source);
1142 v8::ScriptOrigin origin(v8_str("test"));
1143 v8::ScriptCompiler::Source source(source_str, origin, cache);
1144 v8::Local<v8::UnboundScript> script;
1145 {
1146 DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
1147 script = v8::ScriptCompiler::CompileUnbound(
1148 isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache);
1149 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001150 CHECK(!cache->rejected);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001151 v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001152 CHECK(result->ToString(isolate2)->Equals(v8_str("abcdef")));
1153 }
1154 DCHECK(toplevel_test_code_event_found);
1155 isolate2->Dispose();
1156}
1157
1158
1159TEST(SerializeToplevelFlagChange) {
1160 FLAG_serialize_toplevel = true;
1161
1162 const char* source = "function f() { return 'abc'; }; f() + 'def'";
1163 v8::ScriptCompiler::CachedData* cache;
1164
1165 v8::Isolate* isolate1 = v8::Isolate::New();
1166 {
1167 v8::Isolate::Scope iscope(isolate1);
1168 v8::HandleScope scope(isolate1);
1169 v8::Local<v8::Context> context = v8::Context::New(isolate1);
1170 v8::Context::Scope context_scope(context);
1171
1172 v8::Local<v8::String> source_str = v8_str(source);
1173 v8::ScriptOrigin origin(v8_str("test"));
1174 v8::ScriptCompiler::Source source(source_str, origin);
1175 v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
1176 isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
1177 const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
1178 CHECK(data);
1179 // Persist cached data.
1180 uint8_t* buffer = NewArray<uint8_t>(data->length);
1181 MemCopy(buffer, data->data, data->length);
1182 cache = new v8::ScriptCompiler::CachedData(
1183 buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
1184
1185 v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
1186 CHECK(result->ToString(isolate1)->Equals(v8_str("abcdef")));
1187 }
1188 isolate1->Dispose();
1189
1190 v8::Isolate* isolate2 = v8::Isolate::New();
1191 FLAG_allow_natives_syntax = true; // Flag change should trigger cache reject.
1192 {
1193 v8::Isolate::Scope iscope(isolate2);
1194 v8::HandleScope scope(isolate2);
1195 v8::Local<v8::Context> context = v8::Context::New(isolate2);
1196 v8::Context::Scope context_scope(context);
1197
1198 v8::Local<v8::String> source_str = v8_str(source);
1199 v8::ScriptOrigin origin(v8_str("test"));
1200 v8::ScriptCompiler::Source source(source_str, origin, cache);
1201 v8::ScriptCompiler::CompileUnbound(isolate2, &source,
1202 v8::ScriptCompiler::kConsumeCodeCache);
1203 CHECK(cache->rejected);
1204 }
1205 isolate2->Dispose();
1206}
1207
1208
1209TEST(SerializeWithHarmonyScoping) {
1210 FLAG_serialize_toplevel = true;
1211 FLAG_harmony_scoping = true;
1212
1213 const char* source1 = "'use strict'; let x = 'X'";
1214 const char* source2 = "'use strict'; let y = 'Y'";
1215 const char* source3 = "'use strict'; x + y";
1216
1217 v8::ScriptCompiler::CachedData* cache;
1218
1219 v8::Isolate* isolate1 = v8::Isolate::New();
1220 {
1221 v8::Isolate::Scope iscope(isolate1);
1222 v8::HandleScope scope(isolate1);
1223 v8::Local<v8::Context> context = v8::Context::New(isolate1);
1224 v8::Context::Scope context_scope(context);
1225
1226 CompileRun(source1);
1227 CompileRun(source2);
1228
1229 v8::Local<v8::String> source_str = v8_str(source3);
1230 v8::ScriptOrigin origin(v8_str("test"));
1231 v8::ScriptCompiler::Source source(source_str, origin);
1232 v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
1233 isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
1234 const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
1235 CHECK(data);
1236 // Persist cached data.
1237 uint8_t* buffer = NewArray<uint8_t>(data->length);
1238 MemCopy(buffer, data->data, data->length);
1239 cache = new v8::ScriptCompiler::CachedData(
1240 buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
1241
1242 v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
1243 CHECK(result->ToString(isolate1)->Equals(v8_str("XY")));
1244 }
1245 isolate1->Dispose();
1246
1247 v8::Isolate* isolate2 = v8::Isolate::New();
1248 {
1249 v8::Isolate::Scope iscope(isolate2);
1250 v8::HandleScope scope(isolate2);
1251 v8::Local<v8::Context> context = v8::Context::New(isolate2);
1252 v8::Context::Scope context_scope(context);
1253
1254 // Reverse order of prior running scripts.
1255 CompileRun(source2);
1256 CompileRun(source1);
1257
1258 v8::Local<v8::String> source_str = v8_str(source3);
1259 v8::ScriptOrigin origin(v8_str("test"));
1260 v8::ScriptCompiler::Source source(source_str, origin, cache);
1261 v8::Local<v8::UnboundScript> script;
1262 {
1263 DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
1264 script = v8::ScriptCompiler::CompileUnbound(
1265 isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache);
1266 }
1267 v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
1268 CHECK(result->ToString(isolate2)->Equals(v8_str("XY")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001269 }
1270 isolate2->Dispose();
1271}