| 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;
|
| }
|
|
|
|
|