Commit e5760c08 authored by yangguo's avatar yangguo Committed by Commit bot

[snapshot] introduce SnapshotCreator API.

And use it to implement existing the existing snapshot API.

R=jochen@chromium.org, vogelheim@chromium.org
BUG=chromium:617892

Review-Url: https://codereview.chromium.org/2046423002
Cr-Commit-Position: refs/heads/master@{#36879}
parent 2619ccd1
......@@ -6769,6 +6769,48 @@ class V8_EXPORT V8 {
friend class Context;
};
/**
* Helper class to create a snapshot data blob.
*/
class SnapshotCreator {
public:
enum class FunctionCodeHandling { kClear, kKeep };
/**
* Create and enter an isolate, and set it up for serialization.
* The isolate is either created from scratch or from an existing snapshot.
* The caller keeps ownership of the argument snapshot.
*/
explicit SnapshotCreator(StartupData* existing_blob = nullptr);
~SnapshotCreator();
/**
* \returns the isolate prepared by the snapshot creator.
*/
Isolate* GetIsolate();
/**
* Add a context to be included in the snapshot blob.
*/
void AddContext(Local<Context> context);
/**
* Created a snapshot data blob.
* \param function_code_handling whether to include compiled function code
* in the snapshot.
* \returns { nullptr, 0 } on failure, and a startup snapshot on success. The
* caller acquires ownership of the data array in the return value.
*/
StartupData CreateBlob(FunctionCodeHandling function_code_handling);
private:
void* data_;
// Disallow copying and assigning.
SnapshotCreator(const SnapshotCreator&);
void operator=(const SnapshotCreator&);
};
/**
* A simple Maybe type, representing an object which may or may not have a
......
......@@ -15,6 +15,7 @@
#include "include/v8-experimental.h"
#include "include/v8-profiler.h"
#include "include/v8-testing.h"
#include "include/v8-util.h"
#include "src/accessors.h"
#include "src/api-experimental.h"
#include "src/api-natives.h"
......@@ -383,87 +384,122 @@ bool RunExtraCode(Isolate* isolate, Local<Context> context,
return true;
}
StartupData SerializeIsolateAndContext(
Isolate* isolate, Persistent<Context>* context,
i::StartupSerializer::FunctionCodeHandling function_code_handling) {
if (context->IsEmpty()) return {NULL, 0};
struct SnapshotCreatorData {
explicit SnapshotCreatorData(Isolate* isolate)
: isolate_(isolate), contexts_(isolate), created_(false) {}
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
static SnapshotCreatorData* cast(void* data) {
return reinterpret_cast<SnapshotCreatorData*>(data);
}
ArrayBufferAllocator allocator_;
Isolate* isolate_;
PersistentValueVector<Context> contexts_;
bool created_;
};
} // namespace
SnapshotCreator::SnapshotCreator(StartupData* existing_snapshot) {
i::Isolate* internal_isolate = new i::Isolate(true);
Isolate* isolate = reinterpret_cast<Isolate*>(internal_isolate);
SnapshotCreatorData* data = new SnapshotCreatorData(isolate);
data->isolate_ = isolate;
internal_isolate->set_array_buffer_allocator(&data->allocator_);
isolate->Enter();
if (existing_snapshot) {
internal_isolate->set_snapshot_blob(existing_snapshot);
i::Snapshot::Initialize(internal_isolate);
} else {
internal_isolate->Init(nullptr);
}
data_ = data;
}
SnapshotCreator::~SnapshotCreator() {
SnapshotCreatorData* data = SnapshotCreatorData::cast(data_);
DCHECK(data->created_);
Isolate* isolate = data->isolate_;
isolate->Exit();
isolate->Dispose();
delete data;
}
Isolate* SnapshotCreator::GetIsolate() {
return SnapshotCreatorData::cast(data_)->isolate_;
}
void SnapshotCreator::AddContext(Local<Context> context) {
DCHECK(!context.IsEmpty());
SnapshotCreatorData* data = SnapshotCreatorData::cast(data_);
DCHECK(!data->created_);
Isolate* isolate = data->isolate_;
CHECK_EQ(isolate, context->GetIsolate());
data->contexts_.Append(context);
}
StartupData SnapshotCreator::CreateBlob(
SnapshotCreator::FunctionCodeHandling function_code_handling) {
SnapshotCreatorData* data = SnapshotCreatorData::cast(data_);
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(data->isolate_);
DCHECK(!data->created_);
// 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>();
}
}
}
isolate->heap()->CollectAllAvailableGarbage("mksnapshot");
isolate->heap()->CompactWeakFixedArrays();
i::Object* raw_context = *v8::Utils::OpenPersistent(*context);
context->Reset();
i::DisallowHeapAllocation no_gc_from_here_on;
int num_contexts = static_cast<int>(data->contexts_.Size());
i::List<i::Object*> contexts(num_contexts);
for (int i = 0; i < num_contexts; i++) {
i::HandleScope scope(isolate);
i::Handle<i::Context> context =
v8::Utils::OpenHandle(*data->contexts_.Get(i));
contexts.Add(*context);
}
data->contexts_.Clear();
i::SnapshotByteSink snapshot_sink;
i::StartupSerializer ser(internal_isolate, &snapshot_sink,
function_code_handling);
ser.SerializeStrongReferences();
i::StartupSerializer startup_serializer(isolate, &snapshot_sink,
function_code_handling);
startup_serializer.SerializeStrongReferences();
i::SnapshotByteSink context_sink;
i::PartialSerializer context_ser(internal_isolate, &ser, &context_sink);
context_ser.Serialize(&raw_context);
ser.SerializeWeakReferencesAndDeferred();
i::PartialSerializer context_serializer(isolate, &startup_serializer,
&context_sink);
// TODO(yangguo): support multiple contexts in the snapshot.
DCHECK_EQ(1, contexts.length());
context_serializer.Serialize(&contexts[0]);
startup_serializer.SerializeWeakReferencesAndDeferred();
return i::Snapshot::CreateSnapshotBlob(ser, context_ser);
data->created_ = true;
return i::Snapshot::CreateSnapshotBlob(startup_serializer,
context_serializer);
}
} // 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};
StartupData result = {nullptr, 0};
base::ElapsedTimer timer;
timer.Start();
ArrayBufferAllocator allocator;
i::Isolate* internal_isolate = new i::Isolate(true);
internal_isolate->set_array_buffer_allocator(&allocator);
Isolate* isolate = reinterpret_cast<Isolate*>(internal_isolate);
{
Isolate::Scope isolate_scope(isolate);
internal_isolate->Init(NULL);
Persistent<Context> context;
SnapshotCreator snapshot_creator;
Isolate* isolate = snapshot_creator.GetIsolate();
{
HandleScope handle_scope(isolate);
Local<Context> new_context = Context::New(isolate);
context.Reset(isolate, new_context);
HandleScope scope(isolate);
Local<Context> context = Context::New(isolate);
if (embedded_source != NULL &&
!RunExtraCode(isolate, new_context, embedded_source, "<embedded>")) {
context.Reset();
!RunExtraCode(isolate, context, embedded_source, "<embedded>")) {
return result;
}
snapshot_creator.AddContext(context);
}
result = SerializeIsolateAndContext(
isolate, &context, i::StartupSerializer::CLEAR_FUNCTION_CODE);
DCHECK(context.IsEmpty());
result = snapshot_creator.CreateBlob(
SnapshotCreator::FunctionCodeHandling::kClear);
}
isolate->Dispose();
if (i::FLAG_profile_deserialization) {
i::PrintF("Creating snapshot took %0.3f ms\n",
......@@ -483,39 +519,28 @@ StartupData V8::WarmUpSnapshotDataBlob(StartupData cold_snapshot_blob,
// 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};
StartupData result = {nullptr, 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;
bool success;
SnapshotCreator snapshot_creator(&cold_snapshot_blob);
Isolate* isolate = snapshot_creator.GetIsolate();
{
HandleScope handle_scope(isolate);
Local<Context> new_context = Context::New(isolate);
success = RunExtraCode(isolate, new_context, warmup_source, "<warm-up>");
HandleScope scope(isolate);
Local<Context> context = Context::New(isolate);
if (!RunExtraCode(isolate, context, warmup_source, "<warm-up>")) {
return result;
}
}
if (success) {
{
HandleScope handle_scope(isolate);
isolate->ContextDisposedNotification(false);
Local<Context> new_context = Context::New(isolate);
context.Reset(isolate, new_context);
Local<Context> context = Context::New(isolate);
snapshot_creator.AddContext(context);
}
result = SerializeIsolateAndContext(
isolate, &context, i::StartupSerializer::KEEP_FUNCTION_CODE);
DCHECK(context.IsEmpty());
result = snapshot_creator.CreateBlob(
SnapshotCreator::FunctionCodeHandling::kKeep);
}
isolate->Dispose();
if (i::FLAG_profile_deserialization) {
i::PrintF("Warming up snapshot took %0.3f ms\n",
......
......@@ -5609,6 +5609,25 @@ DependentCode* Heap::LookupWeakObjectToCodeDependency(Handle<HeapObject> obj) {
return DependentCode::cast(empty_fixed_array());
}
void Heap::CompactWeakFixedArrays() {
// Find known WeakFixedArrays and compact them.
i::HeapIterator iterator(this);
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>();
}
}
}
}
void Heap::AddRetainedMap(Handle<Map> map) {
Handle<WeakCell> cell = Map::WeakCellForMap(map);
......
......@@ -843,6 +843,8 @@ class Heap {
DependentCode* LookupWeakObjectToCodeDependency(Handle<HeapObject> obj);
void CompactWeakFixedArrays();
void AddRetainedMap(Handle<Map> map);
// This event is triggered after successful allocation of a new object made
......
......@@ -1419,6 +1419,7 @@ class Isolate {
friend class v8::Isolate;
friend class v8::Locker;
friend class v8::Unlocker;
friend class v8::SnapshotCreator;
friend v8::StartupData v8::V8::CreateSnapshotDataBlob(const char*);
friend v8::StartupData v8::V8::WarmUpSnapshotDataBlob(v8::StartupData,
const char*);
......
......@@ -12,9 +12,10 @@ namespace internal {
StartupSerializer::StartupSerializer(
Isolate* isolate, SnapshotByteSink* sink,
FunctionCodeHandling function_code_handling)
v8::SnapshotCreator::FunctionCodeHandling function_code_handling)
: Serializer(isolate, sink),
function_code_handling_(function_code_handling),
clear_function_code_(function_code_handling ==
v8::SnapshotCreator::FunctionCodeHandling::kClear),
serializing_builtins_(false) {
InitializeCodeAddressMap();
}
......@@ -27,7 +28,7 @@ void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
WhereToPoint where_to_point, int skip) {
DCHECK(!obj->IsJSFunction());
if (function_code_handling_ == CLEAR_FUNCTION_CODE) {
if (clear_function_code_) {
if (obj->IsCode()) {
Code* code = Code::cast(obj);
// If the function code is compiled (either as native code or bytecode),
......@@ -42,7 +43,6 @@ void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
obj = isolate()->heap()->undefined_value();
}
} else if (obj->IsCode()) {
DCHECK_EQ(KEEP_FUNCTION_CODE, function_code_handling_);
Code* code = Code::cast(obj);
if (code->kind() == Code::FUNCTION) {
code->ClearInlineCaches();
......
......@@ -6,6 +6,7 @@
#define V8_SNAPSHOT_STARTUP_SERIALIZER_H_
#include <bitset>
#include "include/v8.h"
#include "src/snapshot/serializer.h"
namespace v8 {
......@@ -13,11 +14,9 @@ namespace internal {
class StartupSerializer : public Serializer {
public:
enum FunctionCodeHandling { CLEAR_FUNCTION_CODE, KEEP_FUNCTION_CODE };
StartupSerializer(
Isolate* isolate, SnapshotByteSink* sink,
FunctionCodeHandling function_code_handling = CLEAR_FUNCTION_CODE);
v8::SnapshotCreator::FunctionCodeHandling function_code_handling);
~StartupSerializer() override;
// Serialize the current state of the heap. The order is:
......@@ -42,7 +41,7 @@ class StartupSerializer : public Serializer {
// roots. In the second pass, we serialize the rest.
bool RootShouldBeSkipped(int root_index);
FunctionCodeHandling function_code_handling_;
bool clear_function_code_;
bool serializing_builtins_;
bool serializing_immortal_immovables_roots_;
std::bitset<Heap::kStrongRootListLength> root_has_been_serialized_;
......
......@@ -93,7 +93,8 @@ static Vector<const byte> Serialize(v8::Isolate* isolate) {
Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
internal_isolate->heap()->CollectAllAvailableGarbage("serialize");
SnapshotByteSink sink;
StartupSerializer ser(internal_isolate, &sink);
StartupSerializer ser(internal_isolate, &sink,
v8::SnapshotCreator::FunctionCodeHandling::kClear);
ser.SerializeStrongReferences();
ser.SerializeWeakReferencesAndDeferred();
SnapshotData snapshot_data(ser);
......@@ -282,7 +283,9 @@ static void PartiallySerializeObject(Vector<const byte>* startup_blob_out,
env.Reset();
SnapshotByteSink startup_sink;
StartupSerializer startup_serializer(isolate, &startup_sink);
StartupSerializer startup_serializer(
isolate, &startup_sink,
v8::SnapshotCreator::FunctionCodeHandling::kClear);
startup_serializer.SerializeStrongReferences();
SnapshotByteSink partial_sink;
......@@ -381,7 +384,9 @@ static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
env.Reset();
SnapshotByteSink startup_sink;
StartupSerializer startup_serializer(isolate, &startup_sink);
StartupSerializer startup_serializer(
isolate, &startup_sink,
v8::SnapshotCreator::FunctionCodeHandling::kClear);
startup_serializer.SerializeStrongReferences();
SnapshotByteSink partial_sink;
......@@ -499,7 +504,9 @@ static void PartiallySerializeCustomContext(
env.Reset();
SnapshotByteSink startup_sink;
StartupSerializer startup_serializer(isolate, &startup_sink);
StartupSerializer startup_serializer(
isolate, &startup_sink,
v8::SnapshotCreator::FunctionCodeHandling::kClear);
startup_serializer.SerializeStrongReferences();
SnapshotByteSink partial_sink;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment