diff options
Diffstat (limited to 'deps/v8/test/cctest/test-serialize.cc')
-rw-r--r-- | deps/v8/test/cctest/test-serialize.cc | 502 |
1 files changed, 285 insertions, 217 deletions
diff --git a/deps/v8/test/cctest/test-serialize.cc b/deps/v8/test/cctest/test-serialize.cc index 2f29b25fab..cd349f9d73 100644 --- a/deps/v8/test/cctest/test-serialize.cc +++ b/deps/v8/test/cctest/test-serialize.cc @@ -39,20 +39,17 @@ #include "src/objects.h" #include "src/parsing/parser.h" #include "src/runtime/runtime.h" +#include "src/snapshot/code-serializer.h" +#include "src/snapshot/deserializer.h" #include "src/snapshot/natives.h" -#include "src/snapshot/serialize.h" +#include "src/snapshot/partial-serializer.h" #include "src/snapshot/snapshot.h" +#include "src/snapshot/startup-serializer.h" #include "test/cctest/cctest.h" #include "test/cctest/heap/utils-inl.h" using namespace v8::internal; - -bool DefaultSnapshotAvailable() { - return i::Snapshot::DefaultSnapshotBlob() != NULL; -} - - void DisableTurbofan() { const char* flag = "--turbo-filter=\"\""; FlagList::SetFlagsFromString(flag, StrLength(flag)); @@ -74,34 +71,14 @@ class TestIsolate : public Isolate { } }; - -void WritePayload(const Vector<const byte>& payload, const char* file_name) { - FILE* file = v8::base::OS::FOpen(file_name, "wb"); - if (file == NULL) { - PrintF("Unable to write to snapshot file \"%s\"\n", file_name); - exit(1); - } - size_t written = fwrite(payload.begin(), 1, payload.length(), file); - if (written != static_cast<size_t>(payload.length())) { - i::PrintF("Writing snapshot file failed.. Aborting.\n"); - exit(1); - } - fclose(file); -} - - -static bool WriteToFile(Isolate* isolate, const char* snapshot_file) { - SnapshotByteSink sink; - StartupSerializer ser(isolate, &sink); - ser.SerializeStrongReferences(); - ser.SerializeWeakReferencesAndDeferred(); - SnapshotData snapshot_data(ser); - WritePayload(snapshot_data.RawData(), snapshot_file); - return true; +static Vector<const byte> WritePayload(const Vector<const byte>& payload) { + int length = payload.length(); + byte* blob = NewArray<byte>(length); + memcpy(blob, payload.begin(), length); + return Vector<const byte>(const_cast<const byte*>(blob), length); } - -static void Serialize(v8::Isolate* isolate) { +static Vector<const byte> Serialize(v8::Isolate* isolate) { // We have to create one context. One reason for this is so that the builtins // can be loaded from v8natives.js and their addresses can be processed. This // will clear the pending fixups array, which would otherwise contain GC roots @@ -114,7 +91,12 @@ static void Serialize(v8::Isolate* isolate) { Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate); internal_isolate->heap()->CollectAllAvailableGarbage("serialize"); - WriteToFile(internal_isolate, FLAG_testing_serialization_file); + SnapshotByteSink sink; + StartupSerializer ser(internal_isolate, &sink); + ser.SerializeStrongReferences(); + ser.SerializeWeakReferencesAndDeferred(); + SnapshotData snapshot_data(ser); + return WritePayload(snapshot_data.RawData()); } @@ -134,49 +116,21 @@ Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head, source_length); } - -// Test that the whole heap can be serialized. -UNINITIALIZED_TEST(Serialize) { - DisableTurbofan(); - if (DefaultSnapshotAvailable()) return; - v8::Isolate* isolate = TestIsolate::NewInitialized(true); - Serialize(isolate); -} - - -// Test that heap serialization is non-destructive. -UNINITIALIZED_TEST(SerializeTwice) { - DisableTurbofan(); - if (DefaultSnapshotAvailable()) return; - v8::Isolate* isolate = TestIsolate::NewInitialized(true); - Serialize(isolate); - Serialize(isolate); -} - - -//---------------------------------------------------------------------------- -// Tests that the heap can be deserialized. - -v8::Isolate* InitializeFromFile(const char* snapshot_file) { - int len; - byte* str = ReadBytes(snapshot_file, &len); - if (!str) return NULL; +v8::Isolate* InitializeFromBlob(Vector<const byte> blob) { v8::Isolate* v8_isolate = NULL; { - SnapshotData snapshot_data(Vector<const byte>(str, len)); + SnapshotData snapshot_data(blob); Deserializer deserializer(&snapshot_data); Isolate* isolate = new TestIsolate(false); v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); v8::Isolate::Scope isolate_scope(v8_isolate); isolate->Init(&deserializer); } - DeleteArray(str); return v8_isolate; } - -static v8::Isolate* Deserialize() { - v8::Isolate* isolate = InitializeFromFile(FLAG_testing_serialization_file); +static v8::Isolate* Deserialize(Vector<const byte> blob) { + v8::Isolate* isolate = InitializeFromBlob(blob); CHECK(isolate); return isolate; } @@ -194,14 +148,15 @@ static void SanityCheck(v8::Isolate* v8_isolate) { isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("Empty")); } - -UNINITIALIZED_DEPENDENT_TEST(Deserialize, Serialize) { +UNINITIALIZED_TEST(StartupSerializerOnce) { // The serialize-deserialize tests only work if the VM is built without // serialization. That doesn't matter. We don't need to be able to // serialize a snapshot in a VM that is booted from a snapshot. DisableTurbofan(); - if (DefaultSnapshotAvailable()) return; - v8::Isolate* isolate = Deserialize(); + v8::Isolate* isolate = TestIsolate::NewInitialized(true); + Vector<const byte> blob = Serialize(isolate); + isolate = Deserialize(blob); + blob.Dispose(); { v8::HandleScope handle_scope(isolate); v8::Isolate::Scope isolate_scope(isolate); @@ -214,12 +169,14 @@ UNINITIALIZED_DEPENDENT_TEST(Deserialize, Serialize) { isolate->Dispose(); } - -UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerialization, - SerializeTwice) { +UNINITIALIZED_TEST(StartupSerializerTwice) { DisableTurbofan(); - if (DefaultSnapshotAvailable()) return; - v8::Isolate* isolate = Deserialize(); + v8::Isolate* isolate = TestIsolate::NewInitialized(true); + Vector<const byte> blob1 = Serialize(isolate); + Vector<const byte> blob2 = Serialize(isolate); + blob1.Dispose(); + isolate = Deserialize(blob2); + blob2.Dispose(); { v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); @@ -232,11 +189,12 @@ UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerialization, isolate->Dispose(); } - -UNINITIALIZED_DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) { +UNINITIALIZED_TEST(StartupSerializerOnceRunScript) { DisableTurbofan(); - if (DefaultSnapshotAvailable()) return; - v8::Isolate* isolate = Deserialize(); + v8::Isolate* isolate = TestIsolate::NewInitialized(true); + Vector<const byte> blob = Serialize(isolate); + isolate = Deserialize(blob); + blob.Dispose(); { v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); @@ -255,12 +213,14 @@ UNINITIALIZED_DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) { isolate->Dispose(); } - -UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2, - SerializeTwice) { +UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) { DisableTurbofan(); - if (DefaultSnapshotAvailable()) return; - v8::Isolate* isolate = Deserialize(); + v8::Isolate* isolate = TestIsolate::NewInitialized(true); + Vector<const byte> blob1 = Serialize(isolate); + Vector<const byte> blob2 = Serialize(isolate); + blob1.Dispose(); + isolate = Deserialize(blob2); + blob2.Dispose(); { v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); @@ -278,10 +238,8 @@ UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2, isolate->Dispose(); } - -UNINITIALIZED_TEST(PartialSerialization) { - DisableTurbofan(); - if (DefaultSnapshotAvailable()) return; +static void PartiallySerializeObject(Vector<const byte>* startup_blob_out, + Vector<const byte>* partial_blob_out) { v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); v8_isolate->Enter(); @@ -316,10 +274,6 @@ UNINITIALIZED_TEST(PartialSerialization) { raw_foo = *(v8::Utils::OpenHandle(*foo)); } - int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; - Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); - { v8::HandleScope handle_scope(v8_isolate); v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); @@ -340,34 +294,25 @@ UNINITIALIZED_TEST(PartialSerialization) { SnapshotData startup_snapshot(startup_serializer); SnapshotData partial_snapshot(partial_serializer); - WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file); - WritePayload(startup_snapshot.RawData(), startup_name.start()); - - startup_name.Dispose(); + *partial_blob_out = WritePayload(partial_snapshot.RawData()); + *startup_blob_out = WritePayload(startup_snapshot.RawData()); } v8_isolate->Exit(); v8_isolate->Dispose(); } - -UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization, PartialSerialization) { +UNINITIALIZED_TEST(PartialSerializerObject) { DisableTurbofan(); - if (DefaultSnapshotAvailable()) return; - int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; - Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + Vector<const byte> startup_blob; + Vector<const byte> partial_blob; + PartiallySerializeObject(&startup_blob, &partial_blob); - v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start()); + v8::Isolate* v8_isolate = InitializeFromBlob(startup_blob); + startup_blob.Dispose(); CHECK(v8_isolate); - startup_name.Dispose(); { v8::Isolate::Scope isolate_scope(v8_isolate); - const char* file_name = FLAG_testing_serialization_file; - - int snapshot_size = 0; - byte* snapshot = ReadBytes(file_name, &snapshot_size); - Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); HandleScope handle_scope(isolate); Handle<Object> root; @@ -375,7 +320,7 @@ UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization, PartialSerialization) { // any references to the global proxy in this test. Handle<JSGlobalProxy> global_proxy = Handle<JSGlobalProxy>::null(); { - SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); + SnapshotData snapshot_data(partial_blob); Deserializer deserializer(&snapshot_data); root = deserializer.DeserializePartial(isolate, global_proxy) .ToHandleChecked(); @@ -384,23 +329,20 @@ UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization, PartialSerialization) { Handle<Object> root2; { - SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); + SnapshotData snapshot_data(partial_blob); Deserializer deserializer(&snapshot_data); root2 = deserializer.DeserializePartial(isolate, global_proxy) .ToHandleChecked(); CHECK(root2->IsString()); CHECK(root.is_identical_to(root2)); } - - DeleteArray(snapshot); + partial_blob.Dispose(); } v8_isolate->Dispose(); } - -UNINITIALIZED_TEST(ContextSerialization) { - DisableTurbofan(); - if (DefaultSnapshotAvailable()) return; +static void PartiallySerializeContext(Vector<const byte>* startup_blob_out, + Vector<const byte>* partial_blob_out) { v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); Heap* heap = isolate->heap(); @@ -428,10 +370,6 @@ UNINITIALIZED_TEST(ContextSerialization) { // context even after we have disposed of env. heap->CollectAllGarbage(); - int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; - Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); - { v8::HandleScope handle_scope(v8_isolate); v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); @@ -454,40 +392,31 @@ UNINITIALIZED_TEST(ContextSerialization) { SnapshotData startup_snapshot(startup_serializer); SnapshotData partial_snapshot(partial_serializer); - WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file); - WritePayload(startup_snapshot.RawData(), startup_name.start()); - - startup_name.Dispose(); + *partial_blob_out = WritePayload(partial_snapshot.RawData()); + *startup_blob_out = WritePayload(startup_snapshot.RawData()); } v8_isolate->Dispose(); } - -UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization, ContextSerialization) { +UNINITIALIZED_TEST(PartialSerializerContext) { DisableTurbofan(); - if (DefaultSnapshotAvailable()) return; - int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; - Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + Vector<const byte> startup_blob; + Vector<const byte> partial_blob; + PartiallySerializeContext(&startup_blob, &partial_blob); - v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start()); + v8::Isolate* v8_isolate = InitializeFromBlob(startup_blob); CHECK(v8_isolate); - startup_name.Dispose(); + startup_blob.Dispose(); { v8::Isolate::Scope isolate_scope(v8_isolate); - const char* file_name = FLAG_testing_serialization_file; - - int snapshot_size = 0; - byte* snapshot = ReadBytes(file_name, &snapshot_size); - Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); HandleScope handle_scope(isolate); Handle<Object> root; Handle<JSGlobalProxy> global_proxy = isolate->factory()->NewUninitializedJSGlobalProxy(); { - SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); + SnapshotData snapshot_data(partial_blob); Deserializer deserializer(&snapshot_data); root = deserializer.DeserializePartial(isolate, global_proxy) .ToHandleChecked(); @@ -497,22 +426,21 @@ UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization, ContextSerialization) { Handle<Object> root2; { - SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); + SnapshotData snapshot_data(partial_blob); Deserializer deserializer(&snapshot_data); root2 = deserializer.DeserializePartial(isolate, global_proxy) .ToHandleChecked(); CHECK(root2->IsContext()); CHECK(!root.is_identical_to(root2)); } - DeleteArray(snapshot); + partial_blob.Dispose(); } v8_isolate->Dispose(); } - -UNINITIALIZED_TEST(CustomContextSerialization) { - DisableTurbofan(); - if (DefaultSnapshotAvailable()) return; +static void PartiallySerializeCustomContext( + Vector<const byte>* startup_blob_out, + Vector<const byte>* partial_blob_out) { v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); { @@ -534,7 +462,8 @@ UNINITIALIZED_TEST(CustomContextSerialization) { " e = function(s) { return eval (s); }" "})();" "var o = this;" - "var r = Math.sin(0) + Math.cos(0);" + "var r = Math.random();" + "var c = Math.sin(0) + Math.cos(0);" "var f = (function(a, b) { return a + b; }).bind(1, 2, 3);" "var s = parseInt('12345');"); @@ -559,10 +488,6 @@ UNINITIALIZED_TEST(CustomContextSerialization) { // context even after we have disposed of env. isolate->heap()->CollectAllAvailableGarbage("snapshotting"); - int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; - Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); - { v8::HandleScope handle_scope(v8_isolate); v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); @@ -585,47 +510,43 @@ UNINITIALIZED_TEST(CustomContextSerialization) { SnapshotData startup_snapshot(startup_serializer); SnapshotData partial_snapshot(partial_serializer); - WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file); - WritePayload(startup_snapshot.RawData(), startup_name.start()); - - startup_name.Dispose(); + *partial_blob_out = WritePayload(partial_snapshot.RawData()); + *startup_blob_out = WritePayload(startup_snapshot.RawData()); } v8_isolate->Dispose(); } - -UNINITIALIZED_DEPENDENT_TEST(CustomContextDeserialization, - CustomContextSerialization) { +UNINITIALIZED_TEST(PartialSerializerCustomContext) { DisableTurbofan(); - FLAG_crankshaft = false; - if (DefaultSnapshotAvailable()) return; - int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; - Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + Vector<const byte> startup_blob; + Vector<const byte> partial_blob; + PartiallySerializeCustomContext(&startup_blob, &partial_blob); - v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start()); + v8::Isolate* v8_isolate = InitializeFromBlob(startup_blob); CHECK(v8_isolate); - startup_name.Dispose(); + startup_blob.Dispose(); { v8::Isolate::Scope isolate_scope(v8_isolate); - const char* file_name = FLAG_testing_serialization_file; - - int snapshot_size = 0; - byte* snapshot = ReadBytes(file_name, &snapshot_size); - Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); HandleScope handle_scope(isolate); Handle<Object> root; Handle<JSGlobalProxy> global_proxy = isolate->factory()->NewUninitializedJSGlobalProxy(); { - SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); + SnapshotData snapshot_data(partial_blob); Deserializer deserializer(&snapshot_data); root = deserializer.DeserializePartial(isolate, global_proxy) .ToHandleChecked(); CHECK(root->IsContext()); Handle<Context> context = Handle<Context>::cast(root); + + // Add context to the weak native context list + context->set(Context::NEXT_CONTEXT_LINK, + isolate->heap()->native_contexts_list(), + UPDATE_WEAK_WRITE_BARRIER); + isolate->heap()->set_native_contexts_list(*context); + CHECK(context->global_proxy() == *global_proxy); Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o"); Handle<JSObject> global_object(context->global_object(), isolate); @@ -638,7 +559,18 @@ UNINITIALIZED_DEPENDENT_TEST(CustomContextDeserialization, ->ToNumber(v8_isolate->GetCurrentContext()) .ToLocalChecked() ->Value(); - CHECK_EQ(1, r); + CHECK(0.0 <= r && r < 1.0); + // Math.random still works. + double random = CompileRun("Math.random()") + ->ToNumber(v8_isolate->GetCurrentContext()) + .ToLocalChecked() + ->Value(); + CHECK(0.0 <= random && random < 1.0); + double c = CompileRun("c") + ->ToNumber(v8_isolate->GetCurrentContext()) + .ToLocalChecked() + ->Value(); + CHECK_EQ(1, c); int f = CompileRun("f()") ->ToNumber(v8_isolate->GetCurrentContext()) .ToLocalChecked() @@ -669,13 +601,12 @@ UNINITIALIZED_DEPENDENT_TEST(CustomContextDeserialization, .FromJust(); CHECK_EQ(100002, b); } - DeleteArray(snapshot); + partial_blob.Dispose(); } v8_isolate->Dispose(); } - -TEST(PerIsolateSnapshotBlobs) { +TEST(CustomSnapshotDataBlob) { DisableTurbofan(); const char* source1 = "function f() { return 42; }"; const char* source2 = @@ -729,8 +660,7 @@ static void SerializationFunctionTemplate( args.GetReturnValue().Set(args[0]); } - -TEST(PerIsolateSnapshotBlobsOutdatedContextWithOverflow) { +TEST(CustomSnapshotDataBlobOutdatedContextWithOverflow) { DisableTurbofan(); const char* source1 = @@ -776,8 +706,7 @@ TEST(PerIsolateSnapshotBlobsOutdatedContextWithOverflow) { isolate->Dispose(); } - -TEST(PerIsolateSnapshotBlobsWithLocker) { +TEST(CustomSnapshotDataBlobWithLocker) { DisableTurbofan(); v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); @@ -815,8 +744,7 @@ TEST(PerIsolateSnapshotBlobsWithLocker) { isolate1->Dispose(); } - -TEST(SnapshotBlobsStackOverflow) { +TEST(CustomSnapshotDataBlobStackOverflow) { DisableTurbofan(); const char* source = "var a = [0];" @@ -855,6 +783,106 @@ TEST(SnapshotBlobsStackOverflow) { isolate->Dispose(); } +bool IsCompiled(const char* name) { + return i::Handle<i::JSFunction>::cast( + v8::Utils::OpenHandle(*CompileRun(name))) + ->shared() + ->is_compiled(); +} + +TEST(SnapshotDataBlobWithWarmup) { + DisableTurbofan(); + const char* warmup = "Math.tan(1); Math.sin = 1;"; + + v8::StartupData cold = v8::V8::CreateSnapshotDataBlob(); + v8::StartupData warm = v8::V8::WarmUpSnapshotDataBlob(cold, warmup); + delete[] cold.data; + + v8::Isolate::CreateParams params; + params.snapshot_blob = &warm; + params.array_buffer_allocator = CcTest::array_buffer_allocator(); + + v8::Isolate* isolate = v8::Isolate::New(params); + { + v8::Isolate::Scope i_scope(isolate); + v8::HandleScope h_scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + delete[] warm.data; + v8::Context::Scope c_scope(context); + // Running the warmup script has effect on whether functions are + // pre-compiled, but does not pollute the context. + CHECK(IsCompiled("Math.tan")); + CHECK(!IsCompiled("Math.cos")); + CHECK(CompileRun("Math.sin")->IsFunction()); + } + isolate->Dispose(); +} + +TEST(CustomSnapshotDataBlobWithWarmup) { + DisableTurbofan(); + const char* source = + "function f() { return Math.sin(1); }\n" + "function g() { return Math.cos(1); }\n" + "Math.tan(1);" + "var a = 5"; + const char* warmup = "a = f()"; + + v8::StartupData cold = v8::V8::CreateSnapshotDataBlob(source); + v8::StartupData warm = v8::V8::WarmUpSnapshotDataBlob(cold, warmup); + delete[] cold.data; + + v8::Isolate::CreateParams params; + params.snapshot_blob = &warm; + params.array_buffer_allocator = CcTest::array_buffer_allocator(); + + v8::Isolate* isolate = v8::Isolate::New(params); + { + v8::Isolate::Scope i_scope(isolate); + v8::HandleScope h_scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + delete[] warm.data; + v8::Context::Scope c_scope(context); + // Running the warmup script has effect on whether functions are + // pre-compiled, but does not pollute the context. + CHECK(IsCompiled("f")); + CHECK(IsCompiled("Math.sin")); + CHECK(!IsCompiled("g")); + CHECK(!IsCompiled("Math.cos")); + CHECK(!IsCompiled("Math.tan")); + CHECK_EQ(5, CompileRun("a")->Int32Value(context).FromJust()); + } + isolate->Dispose(); +} + +TEST(CustomSnapshotDataBlobImmortalImmovableRoots) { + DisableTurbofan(); + // Flood the startup snapshot with shared function infos. If they are + // serialized before the immortal immovable root, the root will no longer end + // up on the first page. + Vector<const uint8_t> source = + ConstructSource(STATIC_CHAR_VECTOR("var a = [];"), + STATIC_CHAR_VECTOR("a.push(function() {return 7});"), + STATIC_CHAR_VECTOR("\0"), 10000); + + v8::StartupData data = v8::V8::CreateSnapshotDataBlob( + reinterpret_cast<const char*>(source.start())); + + v8::Isolate::CreateParams params; + params.snapshot_blob = &data; + params.array_buffer_allocator = CcTest::array_buffer_allocator(); + + v8::Isolate* isolate = v8::Isolate::New(params); + { + v8::Isolate::Scope i_scope(isolate); + v8::HandleScope h_scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + delete[] data.data; // We can dispose of the snapshot blob now. + v8::Context::Scope c_scope(context); + CHECK_EQ(7, CompileRun("a[0]()")->Int32Value(context).FromJust()); + } + isolate->Dispose(); + source.Dispose(); +} TEST(TestThatAlwaysSucceeds) { } @@ -866,12 +894,6 @@ TEST(TestThatAlwaysFails) { } -DEPENDENT_TEST(DependentTestThatAlwaysFails, TestThatAlwaysSucceeds) { - bool ArtificialFailure2 = false; - CHECK(ArtificialFailure2); -} - - int CountBuiltins() { // Check that we have not deserialized any additional builtin. HeapIterator iterator(CcTest::heap()); @@ -887,14 +909,13 @@ int CountBuiltins() { static Handle<SharedFunctionInfo> CompileScript( Isolate* isolate, Handle<String> source, Handle<String> name, ScriptData** cached_data, v8::ScriptCompiler::CompileOptions options) { - return Compiler::CompileScript( + return Compiler::GetSharedFunctionInfoForScript( source, name, 0, 0, v8::ScriptOriginOptions(), Handle<Object>(), Handle<Context>(isolate->native_context()), NULL, cached_data, options, NOT_NATIVES_CODE, false); } - -TEST(SerializeToplevelOnePlusOne) { +TEST(CodeSerializerOnePlusOne) { FLAG_serialize_toplevel = true; LocalContext context; Isolate* isolate = CcTest::i_isolate(); @@ -944,8 +965,7 @@ TEST(SerializeToplevelOnePlusOne) { delete cache; } - -TEST(CodeCachePromotedToCompilationCache) { +TEST(CodeSerializerPromotedToCompilationCache) { FLAG_serialize_toplevel = true; LocalContext context; Isolate* isolate = CcTest::i_isolate(); @@ -975,8 +995,7 @@ TEST(CodeCachePromotedToCompilationCache) { delete cache; } - -TEST(SerializeToplevelInternalizedString) { +TEST(CodeSerializerInternalizedString) { FLAG_serialize_toplevel = true; LocalContext context; Isolate* isolate = CcTest::i_isolate(); @@ -1035,8 +1054,7 @@ TEST(SerializeToplevelInternalizedString) { delete cache; } - -TEST(SerializeToplevelLargeCodeObject) { +TEST(CodeSerializerLargeCodeObject) { FLAG_serialize_toplevel = true; LocalContext context; Isolate* isolate = CcTest::i_isolate(); @@ -1083,8 +1101,7 @@ TEST(SerializeToplevelLargeCodeObject) { source.Dispose(); } - -TEST(SerializeToplevelLargeStrings) { +TEST(CodeSerializerLargeStrings) { FLAG_serialize_toplevel = true; LocalContext context; Isolate* isolate = CcTest::i_isolate(); @@ -1141,8 +1158,7 @@ TEST(SerializeToplevelLargeStrings) { source_t.Dispose(); } - -TEST(SerializeToplevelThreeBigStrings) { +TEST(CodeSerializerThreeBigStrings) { FLAG_serialize_toplevel = true; LocalContext context; Isolate* isolate = CcTest::i_isolate(); @@ -1252,8 +1268,7 @@ class SerializerTwoByteResource : public v8::String::ExternalStringResource { size_t length_; }; - -TEST(SerializeToplevelExternalString) { +TEST(CodeSerializerExternalString) { FLAG_serialize_toplevel = true; LocalContext context; Isolate* isolate = CcTest::i_isolate(); @@ -1315,8 +1330,7 @@ TEST(SerializeToplevelExternalString) { delete cache; } - -TEST(SerializeToplevelLargeExternalString) { +TEST(CodeSerializerLargeExternalString) { FLAG_serialize_toplevel = true; LocalContext context; Isolate* isolate = CcTest::i_isolate(); @@ -1374,8 +1388,7 @@ TEST(SerializeToplevelLargeExternalString) { string.Dispose(); } - -TEST(SerializeToplevelExternalScriptName) { +TEST(CodeSerializerExternalScriptName) { FLAG_serialize_toplevel = true; LocalContext context; Isolate* isolate = CcTest::i_isolate(); @@ -1474,8 +1487,7 @@ v8::ScriptCompiler::CachedData* ProduceCache(const char* source) { return cache; } - -TEST(SerializeToplevelIsolates) { +TEST(CodeSerializerIsolates) { FLAG_serialize_toplevel = true; const char* source = "function f() { return 'abc'; }; f() + 'def'"; @@ -1516,8 +1528,7 @@ TEST(SerializeToplevelIsolates) { isolate2->Dispose(); } - -TEST(SerializeToplevelFlagChange) { +TEST(CodeSerializerFlagChange) { FLAG_serialize_toplevel = true; const char* source = "function f() { return 'abc'; }; f() + 'def'"; @@ -1546,8 +1557,7 @@ TEST(SerializeToplevelFlagChange) { isolate2->Dispose(); } - -TEST(SerializeToplevelBitFlip) { +TEST(CodeSerializerBitFlip) { FLAG_serialize_toplevel = true; const char* source = "function f() { return 'abc'; }; f() + 'def'"; @@ -1576,8 +1586,7 @@ TEST(SerializeToplevelBitFlip) { isolate2->Dispose(); } - -TEST(SerializeWithHarmonyScoping) { +TEST(CodeSerializerWithHarmonyScoping) { FLAG_serialize_toplevel = true; const char* source1 = "'use strict'; let x = 'X'"; @@ -1655,11 +1664,16 @@ TEST(SerializeWithHarmonyScoping) { isolate2->Dispose(); } - -TEST(SerializeInternalReference) { +TEST(CodeSerializerInternalReference) { #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 return; #endif + // In ignition there are only relative jumps, so the following code + // would not have any internal references. This test is not relevant + // for ignition. + if (FLAG_ignition) { + return; + } // Disable experimental natives that are loaded after deserialization. FLAG_function_context_specialization = false; FLAG_always_opt = true; @@ -1740,11 +1754,65 @@ TEST(SerializeInternalReference) { isolate->Dispose(); } +TEST(CodeSerializerEagerCompilationAndPreAge) { + if (FLAG_ignition) return; + + FLAG_lazy = true; + FLAG_serialize_toplevel = true; + FLAG_serialize_age_code = true; + FLAG_serialize_eager = true; + FLAG_min_preparse_length = 1; + + static const char* source = + "function f() {" + " function g() {" + " return 1;" + " }" + " return g();" + "}" + "'abcdef';"; + + v8::ScriptCompiler::CachedData* cache = ProduceCache(source); + + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); + v8::Isolate* isolate2 = v8::Isolate::New(create_params); + { + v8::Isolate::Scope iscope(isolate2); + v8::HandleScope scope(isolate2); + v8::Local<v8::Context> context = v8::Context::New(isolate2); + v8::Context::Scope context_scope(context); + + v8::Local<v8::String> source_str = v8_str(source); + v8::ScriptOrigin origin(v8_str("test")); + v8::ScriptCompiler::Source source(source_str, origin, cache); + v8::Local<v8::UnboundScript> unbound = + v8::ScriptCompiler::CompileUnboundScript( + isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + + CHECK(!cache->rejected); + + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate2); + HandleScope i_scope(i_isolate); + Handle<SharedFunctionInfo> toplevel = v8::Utils::OpenHandle(*unbound); + Handle<Script> script(Script::cast(toplevel->script())); + WeakFixedArray::Iterator iterator(script->shared_function_infos()); + // Every function has been pre-compiled from the code cache. + int count = 0; + while (SharedFunctionInfo* shared = iterator.Next<SharedFunctionInfo>()) { + CHECK(shared->is_compiled()); + CHECK_EQ(Code::kPreAgedCodeAge, shared->code()->GetAge()); + count++; + } + CHECK_EQ(3, count); + } + isolate2->Dispose(); +} TEST(Regress503552) { // Test that the code serializer can deal with weak cells that form a linked // list during incremental marking. - CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); @@ -1752,7 +1820,7 @@ TEST(Regress503552) { Handle<String> source = isolate->factory()->NewStringFromAsciiChecked( "function f() {} function g() {}"); ScriptData* script_data = NULL; - Handle<SharedFunctionInfo> shared = Compiler::CompileScript( + Handle<SharedFunctionInfo> shared = Compiler::GetSharedFunctionInfoForScript( source, Handle<String>(), 0, 0, v8::ScriptOriginOptions(), Handle<Object>(), Handle<Context>(isolate->native_context()), NULL, &script_data, v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE, |