blob: 94b400e2055a67cec62e8e8a65411023e437bfd5 [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"
40#include "src/runtime.h"
41#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
Leon Clarked91b9f72010-01-27 17:25:45 +0000117class FileByteSink : public SnapshotByteSink {
118 public:
119 explicit FileByteSink(const char* snapshot_file) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120 fp_ = v8::base::OS::FOpen(snapshot_file, "wb");
Leon Clarked91b9f72010-01-27 17:25:45 +0000121 file_name_ = snapshot_file;
122 if (fp_ == NULL) {
123 PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file);
124 exit(1);
125 }
126 }
127 virtual ~FileByteSink() {
128 if (fp_ != NULL) {
129 fclose(fp_);
130 }
131 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132 virtual void Put(byte b, const char* description) {
Leon Clarked91b9f72010-01-27 17:25:45 +0000133 if (fp_ != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000134 fputc(b, fp_);
Leon Clarked91b9f72010-01-27 17:25:45 +0000135 }
136 }
137 virtual int Position() {
138 return ftell(fp_);
139 }
140 void WriteSpaceUsed(
141 int new_space_used,
142 int pointer_space_used,
143 int data_space_used,
144 int code_space_used,
145 int map_space_used,
146 int cell_space_used,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000147 int property_cell_space_used);
Leon Clarked91b9f72010-01-27 17:25:45 +0000148
149 private:
150 FILE* fp_;
151 const char* file_name_;
152};
153
154
155void FileByteSink::WriteSpaceUsed(
156 int new_space_used,
157 int pointer_space_used,
158 int data_space_used,
159 int code_space_used,
160 int map_space_used,
161 int cell_space_used,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000162 int property_cell_space_used) {
Leon Clarked91b9f72010-01-27 17:25:45 +0000163 int file_name_length = StrLength(file_name_) + 10;
164 Vector<char> name = Vector<char>::New(file_name_length + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165 SNPrintF(name, "%s.size", file_name_);
166 FILE* fp = v8::base::OS::FOpen(name.start(), "w");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800167 name.Dispose();
Leon Clarked91b9f72010-01-27 17:25:45 +0000168 fprintf(fp, "new %d\n", new_space_used);
169 fprintf(fp, "pointer %d\n", pointer_space_used);
170 fprintf(fp, "data %d\n", data_space_used);
171 fprintf(fp, "code %d\n", code_space_used);
172 fprintf(fp, "map %d\n", map_space_used);
173 fprintf(fp, "cell %d\n", cell_space_used);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000174 fprintf(fp, "property cell %d\n", property_cell_space_used);
Leon Clarked91b9f72010-01-27 17:25:45 +0000175 fclose(fp);
176}
177
178
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000179static bool WriteToFile(Isolate* isolate, const char* snapshot_file) {
Leon Clarked91b9f72010-01-27 17:25:45 +0000180 FileByteSink file(snapshot_file);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000181 StartupSerializer ser(isolate, &file);
Leon Clarked91b9f72010-01-27 17:25:45 +0000182 ser.Serialize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000183
184 file.WriteSpaceUsed(
185 ser.CurrentAllocationAddress(NEW_SPACE),
186 ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
187 ser.CurrentAllocationAddress(OLD_DATA_SPACE),
188 ser.CurrentAllocationAddress(CODE_SPACE),
189 ser.CurrentAllocationAddress(MAP_SPACE),
190 ser.CurrentAllocationAddress(CELL_SPACE),
191 ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
192
Leon Clarked91b9f72010-01-27 17:25:45 +0000193 return true;
194}
195
196
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000197static void Serialize(v8::Isolate* isolate) {
Steve Blockd0582a62009-12-15 09:54:21 +0000198 // We have to create one context. One reason for this is so that the builtins
199 // can be loaded from v8natives.js and their addresses can be processed. This
200 // will clear the pending fixups array, which would otherwise contain GC roots
201 // that would confuse the serialization/deserialization process.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000202 v8::Isolate::Scope isolate_scope(isolate);
203 {
204 v8::HandleScope scope(isolate);
205 v8::Context::New(isolate);
206 }
207
208 Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
209 internal_isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "serialize");
210 WriteToFile(internal_isolate, FLAG_testing_serialization_file);
Steve Blocka7e24c12009-10-30 11:49:00 +0000211}
212
213
Steve Blockd0582a62009-12-15 09:54:21 +0000214// Test that the whole heap can be serialized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215UNINITIALIZED_TEST(Serialize) {
216 if (!Snapshot::HaveASnapshotToStartFrom()) {
217 v8::Isolate::CreateParams params;
218 params.enable_serializer = true;
219 v8::Isolate* isolate = v8::Isolate::New(params);
220 Serialize(isolate);
221 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000222}
223
224
Steve Blockd0582a62009-12-15 09:54:21 +0000225// Test that heap serialization is non-destructive.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000226UNINITIALIZED_TEST(SerializeTwice) {
227 if (!Snapshot::HaveASnapshotToStartFrom()) {
228 v8::Isolate::CreateParams params;
229 params.enable_serializer = true;
230 v8::Isolate* isolate = v8::Isolate::New(params);
231 Serialize(isolate);
232 Serialize(isolate);
233 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000234}
235
Steve Blockd0582a62009-12-15 09:54:21 +0000236
Steve Blocka7e24c12009-10-30 11:49:00 +0000237//----------------------------------------------------------------------------
238// Tests that the heap can be deserialized.
239
Steve Blocka7e24c12009-10-30 11:49:00 +0000240
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000241static void ReserveSpaceForSnapshot(Deserializer* deserializer,
242 const char* file_name) {
Andrei Popescu31002712010-02-23 13:46:05 +0000243 int file_name_length = StrLength(file_name) + 10;
Leon Clarkee46be812010-01-19 14:06:41 +0000244 Vector<char> name = Vector<char>::New(file_name_length + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000245 SNPrintF(name, "%s.size", file_name);
246 FILE* fp = v8::base::OS::FOpen(name.start(), "r");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800247 name.Dispose();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248 int new_size, pointer_size, data_size, code_size, map_size, cell_size,
249 property_cell_size;
Leon Clarkee46be812010-01-19 14:06:41 +0000250#ifdef _MSC_VER
251 // Avoid warning about unsafe fscanf from MSVC.
252 // Please note that this is only fine if %c and %s are not being used.
253#define fscanf fscanf_s
254#endif
255 CHECK_EQ(1, fscanf(fp, "new %d\n", &new_size));
256 CHECK_EQ(1, fscanf(fp, "pointer %d\n", &pointer_size));
257 CHECK_EQ(1, fscanf(fp, "data %d\n", &data_size));
258 CHECK_EQ(1, fscanf(fp, "code %d\n", &code_size));
259 CHECK_EQ(1, fscanf(fp, "map %d\n", &map_size));
260 CHECK_EQ(1, fscanf(fp, "cell %d\n", &cell_size));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000261 CHECK_EQ(1, fscanf(fp, "property cell %d\n", &property_cell_size));
Leon Clarkee46be812010-01-19 14:06:41 +0000262#ifdef _MSC_VER
263#undef fscanf
264#endif
265 fclose(fp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000266 deserializer->set_reservation(NEW_SPACE, new_size);
267 deserializer->set_reservation(OLD_POINTER_SPACE, pointer_size);
268 deserializer->set_reservation(OLD_DATA_SPACE, data_size);
269 deserializer->set_reservation(CODE_SPACE, code_size);
270 deserializer->set_reservation(MAP_SPACE, map_size);
271 deserializer->set_reservation(CELL_SPACE, cell_size);
272 deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_size);
Andrei Popescu31002712010-02-23 13:46:05 +0000273}
Leon Clarked91b9f72010-01-27 17:25:45 +0000274
Andrei Popescu31002712010-02-23 13:46:05 +0000275
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000276v8::Isolate* InitializeFromFile(const char* snapshot_file) {
277 int len;
278 byte* str = ReadBytes(snapshot_file, &len);
279 if (!str) return NULL;
280 v8::Isolate* v8_isolate = NULL;
281 {
282 SnapshotByteSource source(str, len);
283 Deserializer deserializer(&source);
284 ReserveSpaceForSnapshot(&deserializer, snapshot_file);
285 Isolate* isolate = Isolate::NewForTesting();
286 v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
287 v8::Isolate::Scope isolate_scope(v8_isolate);
288 isolate->Init(&deserializer);
289 }
290 DeleteArray(str);
291 return v8_isolate;
292}
293
294
295static v8::Isolate* Deserialize() {
296 v8::Isolate* isolate = InitializeFromFile(FLAG_testing_serialization_file);
297 CHECK(isolate);
298 return isolate;
299}
300
301
302static void SanityCheck(v8::Isolate* v8_isolate) {
303 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
304 v8::HandleScope scope(v8_isolate);
305#ifdef VERIFY_HEAP
306 isolate->heap()->Verify();
307#endif
308 CHECK(isolate->global_object()->IsJSObject());
309 CHECK(isolate->native_context()->IsContext());
310 CHECK(isolate->heap()->string_table()->IsStringTable());
311 isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("Empty"));
312}
313
314
315UNINITIALIZED_DEPENDENT_TEST(Deserialize, Serialize) {
316 // The serialize-deserialize tests only work if the VM is built without
317 // serialization. That doesn't matter. We don't need to be able to
318 // serialize a snapshot in a VM that is booted from a snapshot.
319 if (!Snapshot::HaveASnapshotToStartFrom()) {
320 v8::Isolate* isolate = Deserialize();
321 {
322 v8::HandleScope handle_scope(isolate);
323 v8::Isolate::Scope isolate_scope(isolate);
324
325 v8::Local<v8::Context> env = v8::Context::New(isolate);
326 env->Enter();
327
328 SanityCheck(isolate);
329 }
330 isolate->Dispose();
331 }
332}
333
334
335UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerialization,
336 SerializeTwice) {
337 if (!Snapshot::HaveASnapshotToStartFrom()) {
338 v8::Isolate* isolate = Deserialize();
339 {
340 v8::Isolate::Scope isolate_scope(isolate);
341 v8::HandleScope handle_scope(isolate);
342
343 v8::Local<v8::Context> env = v8::Context::New(isolate);
344 env->Enter();
345
346 SanityCheck(isolate);
347 }
348 isolate->Dispose();
349 }
350}
351
352
353UNINITIALIZED_DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
354 if (!Snapshot::HaveASnapshotToStartFrom()) {
355 v8::Isolate* isolate = Deserialize();
356 {
357 v8::Isolate::Scope isolate_scope(isolate);
358 v8::HandleScope handle_scope(isolate);
359
360
361 v8::Local<v8::Context> env = v8::Context::New(isolate);
362 env->Enter();
363
364 const char* c_source = "\"1234\".length";
365 v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
366 v8::Local<v8::Script> script = v8::Script::Compile(source);
367 CHECK_EQ(4, script->Run()->Int32Value());
368 }
369 isolate->Dispose();
370 }
371}
372
373
374UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
375 SerializeTwice) {
376 if (!Snapshot::HaveASnapshotToStartFrom()) {
377 v8::Isolate* isolate = Deserialize();
378 {
379 v8::Isolate::Scope isolate_scope(isolate);
380 v8::HandleScope handle_scope(isolate);
381
382 v8::Local<v8::Context> env = v8::Context::New(isolate);
383 env->Enter();
384
385 const char* c_source = "\"1234\".length";
386 v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
387 v8::Local<v8::Script> script = v8::Script::Compile(source);
388 CHECK_EQ(4, script->Run()->Int32Value());
389 }
390 isolate->Dispose();
391 }
392}
393
394
395UNINITIALIZED_TEST(PartialSerialization) {
396 if (!Snapshot::HaveASnapshotToStartFrom()) {
397 v8::Isolate::CreateParams params;
398 params.enable_serializer = true;
399 v8::Isolate* v8_isolate = v8::Isolate::New(params);
400 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
401 v8_isolate->Enter();
402 {
403 Heap* heap = isolate->heap();
404
405 v8::Persistent<v8::Context> env;
406 {
407 HandleScope scope(isolate);
408 env.Reset(v8_isolate, v8::Context::New(v8_isolate));
409 }
410 DCHECK(!env.IsEmpty());
411 {
412 v8::HandleScope handle_scope(v8_isolate);
413 v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
414 }
415 // Make sure all builtin scripts are cached.
416 {
417 HandleScope scope(isolate);
418 for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
419 isolate->bootstrapper()->NativesSourceLookup(i);
420 }
421 }
422 heap->CollectAllGarbage(Heap::kNoGCFlags);
423 heap->CollectAllGarbage(Heap::kNoGCFlags);
424
425 Object* raw_foo;
426 {
427 v8::HandleScope handle_scope(v8_isolate);
428 v8::Local<v8::String> foo = v8::String::NewFromUtf8(v8_isolate, "foo");
429 DCHECK(!foo.IsEmpty());
430 raw_foo = *(v8::Utils::OpenHandle(*foo));
431 }
432
433 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
434 Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
435 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
436
437 {
438 v8::HandleScope handle_scope(v8_isolate);
439 v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
440 }
441 env.Reset();
442
443 FileByteSink startup_sink(startup_name.start());
444 StartupSerializer startup_serializer(isolate, &startup_sink);
445 startup_serializer.SerializeStrongReferences();
446
447 FileByteSink partial_sink(FLAG_testing_serialization_file);
448 PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
449 p_ser.Serialize(&raw_foo);
450 startup_serializer.SerializeWeakReferences();
451
452 partial_sink.WriteSpaceUsed(
453 p_ser.CurrentAllocationAddress(NEW_SPACE),
454 p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
455 p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
456 p_ser.CurrentAllocationAddress(CODE_SPACE),
457 p_ser.CurrentAllocationAddress(MAP_SPACE),
458 p_ser.CurrentAllocationAddress(CELL_SPACE),
459 p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
460
461 startup_sink.WriteSpaceUsed(
462 startup_serializer.CurrentAllocationAddress(NEW_SPACE),
463 startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
464 startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
465 startup_serializer.CurrentAllocationAddress(CODE_SPACE),
466 startup_serializer.CurrentAllocationAddress(MAP_SPACE),
467 startup_serializer.CurrentAllocationAddress(CELL_SPACE),
468 startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
469 startup_name.Dispose();
470 }
471 v8_isolate->Exit();
472 v8_isolate->Dispose();
473 }
474}
475
476
477UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
478 if (!Snapshot::HaveASnapshotToStartFrom()) {
Andrei Popescu31002712010-02-23 13:46:05 +0000479 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
480 Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000481 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
Andrei Popescu31002712010-02-23 13:46:05 +0000482
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000483 v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
484 CHECK(v8_isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800485 startup_name.Dispose();
Andrei Popescu31002712010-02-23 13:46:05 +0000486 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000487 v8::Isolate::Scope isolate_scope(v8_isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000488
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000489 const char* file_name = FLAG_testing_serialization_file;
Andrei Popescu31002712010-02-23 13:46:05 +0000490
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000491 int snapshot_size = 0;
492 byte* snapshot = ReadBytes(file_name, &snapshot_size);
493
494 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
495 Object* root;
496 {
497 SnapshotByteSource source(snapshot, snapshot_size);
498 Deserializer deserializer(&source);
499 ReserveSpaceForSnapshot(&deserializer, file_name);
500 deserializer.DeserializePartial(isolate, &root);
501 CHECK(root->IsString());
502 }
503 HandleScope handle_scope(isolate);
504 Handle<Object> root_handle(root, isolate);
505
506
507 Object* root2;
508 {
509 SnapshotByteSource source(snapshot, snapshot_size);
510 Deserializer deserializer(&source);
511 ReserveSpaceForSnapshot(&deserializer, file_name);
512 deserializer.DeserializePartial(isolate, &root2);
513 CHECK(root2->IsString());
514 CHECK(*root_handle == root2);
515 }
Andrei Popescu31002712010-02-23 13:46:05 +0000516 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000517 v8_isolate->Dispose();
Leon Clarked91b9f72010-01-27 17:25:45 +0000518 }
Andrei Popescu31002712010-02-23 13:46:05 +0000519}
Leon Clarked91b9f72010-01-27 17:25:45 +0000520
Andrei Popescu31002712010-02-23 13:46:05 +0000521
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000522UNINITIALIZED_TEST(ContextSerialization) {
523 if (!Snapshot::HaveASnapshotToStartFrom()) {
524 v8::Isolate::CreateParams params;
525 params.enable_serializer = true;
526 v8::Isolate* v8_isolate = v8::Isolate::New(params);
527 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
528 Heap* heap = isolate->heap();
529 {
530 v8::Isolate::Scope isolate_scope(v8_isolate);
Andrei Popescu31002712010-02-23 13:46:05 +0000531
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000532 v8::Persistent<v8::Context> env;
533 {
534 HandleScope scope(isolate);
535 env.Reset(v8_isolate, v8::Context::New(v8_isolate));
536 }
537 DCHECK(!env.IsEmpty());
538 {
539 v8::HandleScope handle_scope(v8_isolate);
540 v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
541 }
542 // Make sure all builtin scripts are cached.
543 {
544 HandleScope scope(isolate);
545 for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
546 isolate->bootstrapper()->NativesSourceLookup(i);
547 }
548 }
549 // If we don't do this then we end up with a stray root pointing at the
550 // context even after we have disposed of env.
551 heap->CollectAllGarbage(Heap::kNoGCFlags);
552
553 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
554 Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
555 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
556
557 {
558 v8::HandleScope handle_scope(v8_isolate);
559 v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
560 }
561
562 i::Object* raw_context = *v8::Utils::OpenPersistent(env);
563
564 env.Reset();
565
566 FileByteSink startup_sink(startup_name.start());
567 StartupSerializer startup_serializer(isolate, &startup_sink);
568 startup_serializer.SerializeStrongReferences();
569
570 FileByteSink partial_sink(FLAG_testing_serialization_file);
571 PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
572 p_ser.Serialize(&raw_context);
573 startup_serializer.SerializeWeakReferences();
574
575 partial_sink.WriteSpaceUsed(
576 p_ser.CurrentAllocationAddress(NEW_SPACE),
577 p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
578 p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
579 p_ser.CurrentAllocationAddress(CODE_SPACE),
580 p_ser.CurrentAllocationAddress(MAP_SPACE),
581 p_ser.CurrentAllocationAddress(CELL_SPACE),
582 p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
583
584 startup_sink.WriteSpaceUsed(
585 startup_serializer.CurrentAllocationAddress(NEW_SPACE),
586 startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
587 startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
588 startup_serializer.CurrentAllocationAddress(CODE_SPACE),
589 startup_serializer.CurrentAllocationAddress(MAP_SPACE),
590 startup_serializer.CurrentAllocationAddress(CELL_SPACE),
591 startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
592 startup_name.Dispose();
Andrei Popescu31002712010-02-23 13:46:05 +0000593 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000594 v8_isolate->Dispose();
Andrei Popescu31002712010-02-23 13:46:05 +0000595 }
Andrei Popescu31002712010-02-23 13:46:05 +0000596}
597
598
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000599UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization, ContextSerialization) {
600 if (!Snapshot::HaveASnapshotToStartFrom()) {
Andrei Popescu31002712010-02-23 13:46:05 +0000601 int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
602 Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000603 SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
Andrei Popescu31002712010-02-23 13:46:05 +0000604
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000605 v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
606 CHECK(v8_isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800607 startup_name.Dispose();
Andrei Popescu31002712010-02-23 13:46:05 +0000608 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000609 v8::Isolate::Scope isolate_scope(v8_isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000610
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000611 const char* file_name = FLAG_testing_serialization_file;
Andrei Popescu31002712010-02-23 13:46:05 +0000612
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613 int snapshot_size = 0;
614 byte* snapshot = ReadBytes(file_name, &snapshot_size);
Leon Clarkee46be812010-01-19 14:06:41 +0000615
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000616 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
617 Object* root;
618 {
619 SnapshotByteSource source(snapshot, snapshot_size);
620 Deserializer deserializer(&source);
621 ReserveSpaceForSnapshot(&deserializer, file_name);
622 deserializer.DeserializePartial(isolate, &root);
623 CHECK(root->IsContext());
Leon Clarkee46be812010-01-19 14:06:41 +0000624 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000625 HandleScope handle_scope(isolate);
626 Handle<Object> root_handle(root, isolate);
Leon Clarkee46be812010-01-19 14:06:41 +0000627
Leon Clarkee46be812010-01-19 14:06:41 +0000628
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000629 Object* root2;
630 {
631 SnapshotByteSource source(snapshot, snapshot_size);
632 Deserializer deserializer(&source);
633 ReserveSpaceForSnapshot(&deserializer, file_name);
634 deserializer.DeserializePartial(isolate, &root2);
635 CHECK(root2->IsContext());
636 CHECK(*root_handle != root2);
Leon Clarkee46be812010-01-19 14:06:41 +0000637 }
Leon Clarkee46be812010-01-19 14:06:41 +0000638 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000639 v8_isolate->Dispose();
Leon Clarkee46be812010-01-19 14:06:41 +0000640 }
641}
642
643
Steve Block3ce2e202009-11-05 08:53:23 +0000644TEST(TestThatAlwaysSucceeds) {
645}
646
647
648TEST(TestThatAlwaysFails) {
649 bool ArtificialFailure = false;
650 CHECK(ArtificialFailure);
651}
652
653
654DEPENDENT_TEST(DependentTestThatAlwaysFails, TestThatAlwaysSucceeds) {
655 bool ArtificialFailure2 = false;
656 CHECK(ArtificialFailure2);
657}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000658
659
660int CountBuiltins() {
661 // Check that we have not deserialized any additional builtin.
662 HeapIterator iterator(CcTest::heap());
663 DisallowHeapAllocation no_allocation;
664 int counter = 0;
665 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
666 if (obj->IsCode() && Code::cast(obj)->kind() == Code::BUILTIN) counter++;
667 }
668 return counter;
669}
670
671
672TEST(SerializeToplevelOnePlusOne) {
673 FLAG_serialize_toplevel = true;
674 LocalContext context;
675 Isolate* isolate = CcTest::i_isolate();
676 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
677
678 v8::HandleScope scope(CcTest::isolate());
679
680 const char* source = "1 + 1";
681
682 Handle<String> orig_source = isolate->factory()
683 ->NewStringFromUtf8(CStrVector(source))
684 .ToHandleChecked();
685 Handle<String> copy_source = isolate->factory()
686 ->NewStringFromUtf8(CStrVector(source))
687 .ToHandleChecked();
688 CHECK(!orig_source.is_identical_to(copy_source));
689 CHECK(orig_source->Equals(*copy_source));
690
691 ScriptData* cache = NULL;
692
693 Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
694 orig_source, Handle<String>(), 0, 0, false,
695 Handle<Context>(isolate->native_context()), NULL, &cache,
696 v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
697
698 int builtins_count = CountBuiltins();
699
700 Handle<SharedFunctionInfo> copy;
701 {
702 DisallowCompilation no_compile_expected(isolate);
703 copy = Compiler::CompileScript(
704 copy_source, Handle<String>(), 0, 0, false,
705 Handle<Context>(isolate->native_context()), NULL, &cache,
706 v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
707 }
708
709 CHECK_NE(*orig, *copy);
710 CHECK(Script::cast(copy->script())->source() == *copy_source);
711
712 Handle<JSFunction> copy_fun =
713 isolate->factory()->NewFunctionFromSharedFunctionInfo(
714 copy, isolate->native_context());
715 Handle<JSObject> global(isolate->context()->global_object());
716 Handle<Object> copy_result =
717 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
718 CHECK_EQ(2, Handle<Smi>::cast(copy_result)->value());
719
720 CHECK_EQ(builtins_count, CountBuiltins());
721
722 delete cache;
723}
724
725
726TEST(SerializeToplevelInternalizedString) {
727 FLAG_serialize_toplevel = true;
728 LocalContext context;
729 Isolate* isolate = CcTest::i_isolate();
730 isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
731
732 v8::HandleScope scope(CcTest::isolate());
733
734 const char* source = "'string1'";
735
736 Handle<String> orig_source = isolate->factory()
737 ->NewStringFromUtf8(CStrVector(source))
738 .ToHandleChecked();
739 Handle<String> copy_source = isolate->factory()
740 ->NewStringFromUtf8(CStrVector(source))
741 .ToHandleChecked();
742 CHECK(!orig_source.is_identical_to(copy_source));
743 CHECK(orig_source->Equals(*copy_source));
744
745 Handle<JSObject> global(isolate->context()->global_object());
746 ScriptData* cache = NULL;
747
748 Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
749 orig_source, Handle<String>(), 0, 0, false,
750 Handle<Context>(isolate->native_context()), NULL, &cache,
751 v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
752 Handle<JSFunction> orig_fun =
753 isolate->factory()->NewFunctionFromSharedFunctionInfo(
754 orig, isolate->native_context());
755 Handle<Object> orig_result =
756 Execution::Call(isolate, orig_fun, global, 0, NULL).ToHandleChecked();
757 CHECK(orig_result->IsInternalizedString());
758
759 int builtins_count = CountBuiltins();
760
761 Handle<SharedFunctionInfo> copy;
762 {
763 DisallowCompilation no_compile_expected(isolate);
764 copy = Compiler::CompileScript(
765 copy_source, Handle<String>(), 0, 0, false,
766 Handle<Context>(isolate->native_context()), NULL, &cache,
767 v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
768 }
769 CHECK_NE(*orig, *copy);
770 CHECK(Script::cast(copy->script())->source() == *copy_source);
771
772 Handle<JSFunction> copy_fun =
773 isolate->factory()->NewFunctionFromSharedFunctionInfo(
774 copy, isolate->native_context());
775 CHECK_NE(*orig_fun, *copy_fun);
776 Handle<Object> copy_result =
777 Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
778 CHECK(orig_result.is_identical_to(copy_result));
779 Handle<String> expected =
780 isolate->factory()->NewStringFromAsciiChecked("string1");
781
782 CHECK(Handle<String>::cast(copy_result)->Equals(*expected));
783 CHECK_EQ(builtins_count, CountBuiltins());
784
785 delete cache;
786}
787
788
789TEST(SerializeToplevelIsolates) {
790 FLAG_serialize_toplevel = true;
791
792 const char* source = "function f() { return 'abc'; }; f() + 'def'";
793 v8::ScriptCompiler::CachedData* cache;
794
795 v8::Isolate* isolate1 = v8::Isolate::New();
796 {
797 v8::Isolate::Scope iscope(isolate1);
798 v8::HandleScope scope(isolate1);
799 v8::Local<v8::Context> context = v8::Context::New(isolate1);
800 v8::Context::Scope context_scope(context);
801
802 v8::Local<v8::String> source_str = v8_str(source);
803 v8::ScriptOrigin origin(v8_str("test"));
804 v8::ScriptCompiler::Source source(source_str, origin);
805 v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
806 isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
807 const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
808 // Persist cached data.
809 uint8_t* buffer = NewArray<uint8_t>(data->length);
810 MemCopy(buffer, data->data, data->length);
811 cache = new v8::ScriptCompiler::CachedData(
812 buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
813
814 v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
815 CHECK(result->ToString()->Equals(v8_str("abcdef")));
816 }
817 isolate1->Dispose();
818
819 v8::Isolate* isolate2 = v8::Isolate::New();
820 {
821 v8::Isolate::Scope iscope(isolate2);
822 v8::HandleScope scope(isolate2);
823 v8::Local<v8::Context> context = v8::Context::New(isolate2);
824 v8::Context::Scope context_scope(context);
825
826 v8::Local<v8::String> source_str = v8_str(source);
827 v8::ScriptOrigin origin(v8_str("test"));
828 v8::ScriptCompiler::Source source(source_str, origin, cache);
829 v8::Local<v8::UnboundScript> script;
830 {
831 DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
832 script = v8::ScriptCompiler::CompileUnbound(
833 isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache);
834 }
835 v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
836 CHECK(result->ToString()->Equals(v8_str("abcdef")));
837 }
838 isolate2->Dispose();
839}