Index: src/api.cc |
diff --git a/src/api.cc b/src/api.cc |
index 647bd6e21bca049e94c62ce8cea89a8605acbe71..f933540ba3b1698528c7fee65b3aaa6941c6057c 100644 |
--- a/src/api.cc |
+++ b/src/api.cc |
@@ -341,12 +341,23 @@ void V8::SetSnapshotDataBlob(StartupData* snapshot_blob) { |
i::V8::SetSnapshotBlob(snapshot_blob); |
} |
+namespace { |
+ |
+class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { |
+ public: |
+ virtual void* Allocate(size_t length) { |
+ void* data = AllocateUninitialized(length); |
+ return data == NULL ? data : memset(data, 0, length); |
+ } |
+ virtual void* AllocateUninitialized(size_t length) { return malloc(length); } |
+ virtual void Free(void* data, size_t) { free(data); } |
+}; |
bool RunExtraCode(Isolate* isolate, Local<Context> context, |
- const char* utf8_source) { |
- // Run custom script if provided. |
+ const char* utf8_source, const char* name) { |
base::ElapsedTimer timer; |
timer.Start(); |
+ Context::Scope context_scope(context); |
TryCatch try_catch(isolate); |
Local<String> source_string; |
if (!String::NewFromUtf8(isolate, utf8_source, NewStringType::kNormal) |
@@ -354,7 +365,7 @@ bool RunExtraCode(Isolate* isolate, Local<Context> context, |
return false; |
} |
Local<String> resource_name = |
- String::NewFromUtf8(isolate, "<embedded script>", NewStringType::kNormal) |
+ String::NewFromUtf8(isolate, name, NewStringType::kNormal) |
.ToLocalChecked(); |
ScriptOrigin origin(resource_name); |
ScriptCompiler::Source source(source_string, origin); |
@@ -362,7 +373,7 @@ bool RunExtraCode(Isolate* isolate, Local<Context> context, |
if (!ScriptCompiler::Compile(context, &source).ToLocal(&script)) return false; |
if (script->Run(context).IsEmpty()) return false; |
if (i::FLAG_profile_deserialization) { |
- i::PrintF("Executing custom snapshot script took %0.3f ms\n", |
+ i::PrintF("Executing custom snapshot script %s took %0.3f ms\n", name, |
timer.Elapsed().InMillisecondsF()); |
} |
timer.Stop(); |
@@ -370,92 +381,148 @@ bool RunExtraCode(Isolate* isolate, Local<Context> context, |
return true; |
} |
+StartupData SerializeIsolateAndContext( |
+ Isolate* isolate, Persistent<Context>* context, |
+ i::Snapshot::Metadata metadata, |
+ i::StartupSerializer::FunctionCodeHandling function_code_handling) { |
+ if (context->IsEmpty()) return {NULL, 0}; |
-namespace { |
+ i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); |
-class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { |
- public: |
- virtual void* Allocate(size_t length) { |
- void* data = AllocateUninitialized(length); |
- return data == NULL ? data : memset(data, 0, length); |
+ // If we don't do this then we end up with a stray root pointing at the |
+ // context even after we have disposed of the context. |
+ internal_isolate->heap()->CollectAllAvailableGarbage("mksnapshot"); |
+ |
+ // GC may have cleared weak cells, so compact any WeakFixedArrays |
+ // found on the heap. |
+ i::HeapIterator iterator(internal_isolate->heap(), |
+ i::HeapIterator::kFilterUnreachable); |
+ for (i::HeapObject* o = iterator.next(); o != NULL; o = iterator.next()) { |
+ if (o->IsPrototypeInfo()) { |
+ i::Object* prototype_users = i::PrototypeInfo::cast(o)->prototype_users(); |
+ if (prototype_users->IsWeakFixedArray()) { |
+ i::WeakFixedArray* array = i::WeakFixedArray::cast(prototype_users); |
+ array->Compact<i::JSObject::PrototypeRegistryCompactionCallback>(); |
+ } |
+ } else if (o->IsScript()) { |
+ i::Object* shared_list = i::Script::cast(o)->shared_function_infos(); |
+ if (shared_list->IsWeakFixedArray()) { |
+ i::WeakFixedArray* array = i::WeakFixedArray::cast(shared_list); |
+ array->Compact<i::WeakFixedArray::NullCallback>(); |
+ } |
+ } |
} |
- virtual void* AllocateUninitialized(size_t length) { return malloc(length); } |
- virtual void Free(void* data, size_t) { free(data); } |
-}; |
+ |
+ i::Object* raw_context = *v8::Utils::OpenPersistent(*context); |
+ context->Reset(); |
+ |
+ i::SnapshotByteSink snapshot_sink; |
+ i::StartupSerializer ser(internal_isolate, &snapshot_sink, |
+ function_code_handling); |
+ ser.SerializeStrongReferences(); |
+ |
+ i::SnapshotByteSink context_sink; |
+ i::PartialSerializer context_ser(internal_isolate, &ser, &context_sink); |
+ context_ser.Serialize(&raw_context); |
+ ser.SerializeWeakReferencesAndDeferred(); |
+ |
+ return i::Snapshot::CreateSnapshotBlob(ser, context_ser, metadata); |
+} |
} // namespace |
+StartupData V8::CreateSnapshotDataBlob(const char* embedded_source) { |
+ // Create a new isolate and a new context from scratch, optionally run |
+ // a script to embed, and serialize to create a snapshot blob. |
+ StartupData result = {NULL, 0}; |
+ |
+ base::ElapsedTimer timer; |
+ timer.Start(); |
-StartupData V8::CreateSnapshotDataBlob(const char* custom_source) { |
- i::Isolate* internal_isolate = new i::Isolate(true); |
ArrayBufferAllocator allocator; |
+ i::Isolate* internal_isolate = new i::Isolate(true); |
internal_isolate->set_array_buffer_allocator(&allocator); |
Isolate* isolate = reinterpret_cast<Isolate*>(internal_isolate); |
- StartupData result = {NULL, 0}; |
+ |
{ |
- base::ElapsedTimer timer; |
- timer.Start(); |
Isolate::Scope isolate_scope(isolate); |
internal_isolate->Init(NULL); |
Persistent<Context> context; |
- i::Snapshot::Metadata metadata; |
{ |
HandleScope handle_scope(isolate); |
Local<Context> new_context = Context::New(isolate); |
context.Reset(isolate, new_context); |
- if (custom_source != NULL) { |
- metadata.set_embeds_script(true); |
- Context::Scope context_scope(new_context); |
- if (!RunExtraCode(isolate, new_context, custom_source)) context.Reset(); |
+ if (embedded_source != NULL && |
+ !RunExtraCode(isolate, new_context, embedded_source, "<embedded>")) { |
+ context.Reset(); |
} |
} |
- if (!context.IsEmpty()) { |
- // If we don't do this then we end up with a stray root pointing at the |
- // context even after we have disposed of the context. |
- internal_isolate->heap()->CollectAllAvailableGarbage("mksnapshot"); |
- |
- // GC may have cleared weak cells, so compact any WeakFixedArrays |
- // found on the heap. |
- i::HeapIterator iterator(internal_isolate->heap(), |
- i::HeapIterator::kFilterUnreachable); |
- for (i::HeapObject* o = iterator.next(); o != NULL; o = iterator.next()) { |
- if (o->IsPrototypeInfo()) { |
- i::Object* prototype_users = |
- i::PrototypeInfo::cast(o)->prototype_users(); |
- if (prototype_users->IsWeakFixedArray()) { |
- i::WeakFixedArray* array = i::WeakFixedArray::cast(prototype_users); |
- array->Compact<i::JSObject::PrototypeRegistryCompactionCallback>(); |
- } |
- } else if (o->IsScript()) { |
- i::Object* shared_list = i::Script::cast(o)->shared_function_infos(); |
- if (shared_list->IsWeakFixedArray()) { |
- i::WeakFixedArray* array = i::WeakFixedArray::cast(shared_list); |
- array->Compact<i::WeakFixedArray::NullCallback>(); |
- } |
- } |
- } |
- i::Object* raw_context = *v8::Utils::OpenPersistent(context); |
- context.Reset(); |
+ i::Snapshot::Metadata metadata; |
+ metadata.set_embeds_script(embedded_source != NULL); |
- i::SnapshotByteSink snapshot_sink; |
- i::StartupSerializer ser(internal_isolate, &snapshot_sink); |
- ser.SerializeStrongReferences(); |
+ result = SerializeIsolateAndContext( |
+ isolate, &context, metadata, i::StartupSerializer::CLEAR_FUNCTION_CODE); |
+ DCHECK(context.IsEmpty()); |
+ } |
+ isolate->Dispose(); |
- i::SnapshotByteSink context_sink; |
- i::PartialSerializer context_ser(internal_isolate, &ser, &context_sink); |
- context_ser.Serialize(&raw_context); |
- ser.SerializeWeakReferencesAndDeferred(); |
+ if (i::FLAG_profile_deserialization) { |
+ i::PrintF("Creating snapshot took %0.3f ms\n", |
+ timer.Elapsed().InMillisecondsF()); |
+ } |
+ timer.Stop(); |
+ return result; |
+} |
- result = i::Snapshot::CreateSnapshotBlob(ser, context_ser, metadata); |
- } |
- if (i::FLAG_profile_deserialization) { |
- i::PrintF("Creating snapshot took %0.3f ms\n", |
- timer.Elapsed().InMillisecondsF()); |
+StartupData V8::WarmUpSnapshotDataBlob(StartupData cold_snapshot_blob, |
+ const char* warmup_source) { |
+ CHECK(cold_snapshot_blob.raw_size > 0 && cold_snapshot_blob.data != NULL); |
+ CHECK(warmup_source != NULL); |
+ // Use following steps to create a warmed up snapshot blob from a cold one: |
+ // - Create a new isolate from the cold snapshot. |
+ // - Create a new context to run the warmup script. This will trigger |
+ // compilation of executed functions. |
+ // - Create a new context. This context will be unpolluted. |
+ // - Serialize the isolate and the second context into a new snapshot blob. |
+ StartupData result = {NULL, 0}; |
+ |
+ base::ElapsedTimer timer; |
+ timer.Start(); |
+ |
+ ArrayBufferAllocator allocator; |
+ i::Isolate* internal_isolate = new i::Isolate(true); |
+ internal_isolate->set_array_buffer_allocator(&allocator); |
+ internal_isolate->set_snapshot_blob(&cold_snapshot_blob); |
+ Isolate* isolate = reinterpret_cast<Isolate*>(internal_isolate); |
+ |
+ { |
+ Isolate::Scope isolate_scope(isolate); |
+ i::Snapshot::Initialize(internal_isolate); |
+ Persistent<Context> context; |
+ { |
+ HandleScope handle_scope(isolate); |
+ Local<Context> warmup_context = Context::New(isolate); |
+ if (RunExtraCode(isolate, warmup_context, warmup_source, "<warm-up>")) { |
+ Local<Context> fresh_context = Context::New(isolate); |
+ context.Reset(isolate, fresh_context); |
+ } |
} |
- timer.Stop(); |
+ |
+ i::Snapshot::Metadata metadata; |
+ metadata.set_embeds_script(i::Snapshot::EmbedsScript(internal_isolate)); |
+ |
+ result = SerializeIsolateAndContext( |
+ isolate, &context, metadata, i::StartupSerializer::KEEP_FUNCTION_CODE); |
+ DCHECK(context.IsEmpty()); |
} |
isolate->Dispose(); |
+ |
+ if (i::FLAG_profile_deserialization) { |
+ i::PrintF("Warming up snapshot took %0.3f ms\n", |
+ timer.Elapsed().InMillisecondsF()); |
+ } |
+ timer.Stop(); |
return result; |
} |