Commit 533453f9 authored by yangguo's avatar yangguo Committed by Commit bot

[snapshot] support multiple contexts in the same snapshot.

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

Review-Url: https://codereview.chromium.org/2055203002
Cr-Commit-Position: refs/heads/master@{#37008}
parent 85bef237
...@@ -6787,8 +6787,9 @@ class SnapshotCreator { ...@@ -6787,8 +6787,9 @@ class SnapshotCreator {
/** /**
* Add a context to be included in the snapshot blob. * Add a context to be included in the snapshot blob.
* \returns the index of the context in the snapshot blob.
*/ */
void AddContext(Local<Context> context); size_t AddContext(Local<Context> context);
/** /**
* Created a snapshot data blob. * Created a snapshot data blob.
...@@ -7092,7 +7093,8 @@ class V8_EXPORT Context { ...@@ -7092,7 +7093,8 @@ class V8_EXPORT Context {
static Local<Context> New( static Local<Context> New(
Isolate* isolate, ExtensionConfiguration* extensions = NULL, Isolate* isolate, ExtensionConfiguration* extensions = NULL,
Local<ObjectTemplate> global_template = Local<ObjectTemplate>(), Local<ObjectTemplate> global_template = Local<ObjectTemplate>(),
Local<Value> global_object = Local<Value>()); Local<Value> global_object = Local<Value>(),
size_t context_snapshot_index = 0);
/** /**
* Sets the security token for the context. To access an object in * Sets the security token for the context. To access an object in
......
...@@ -429,13 +429,15 @@ Isolate* SnapshotCreator::GetIsolate() { ...@@ -429,13 +429,15 @@ Isolate* SnapshotCreator::GetIsolate() {
return SnapshotCreatorData::cast(data_)->isolate_; return SnapshotCreatorData::cast(data_)->isolate_;
} }
void SnapshotCreator::AddContext(Local<Context> context) { size_t SnapshotCreator::AddContext(Local<Context> context) {
DCHECK(!context.IsEmpty()); DCHECK(!context.IsEmpty());
SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); SnapshotCreatorData* data = SnapshotCreatorData::cast(data_);
DCHECK(!data->created_); DCHECK(!data->created_);
Isolate* isolate = data->isolate_; Isolate* isolate = data->isolate_;
CHECK_EQ(isolate, context->GetIsolate()); CHECK_EQ(isolate, context->GetIsolate());
size_t index = static_cast<int>(data->contexts_.Size());
data->contexts_.Append(context); data->contexts_.Append(context);
return index;
} }
StartupData SnapshotCreator::CreateBlob( StartupData SnapshotCreator::CreateBlob(
...@@ -464,13 +466,25 @@ StartupData SnapshotCreator::CreateBlob( ...@@ -464,13 +466,25 @@ StartupData SnapshotCreator::CreateBlob(
i::StartupSerializer startup_serializer(isolate, function_code_handling); i::StartupSerializer startup_serializer(isolate, function_code_handling);
startup_serializer.SerializeStrongReferences(); startup_serializer.SerializeStrongReferences();
i::PartialSerializer context_serializer(isolate, &startup_serializer); // Serialize each context with a new partial serializer.
context_serializer.Serialize(&contexts[0]); i::List<i::SnapshotData*> context_snapshots(num_contexts);
for (int i = 0; i < num_contexts; i++) {
i::PartialSerializer partial_serializer(isolate, &startup_serializer);
partial_serializer.Serialize(&contexts[i]);
context_snapshots.Add(new i::SnapshotData(&partial_serializer));
}
startup_serializer.SerializeWeakReferencesAndDeferred(); startup_serializer.SerializeWeakReferencesAndDeferred();
i::SnapshotData startup_snapshot(&startup_serializer);
StartupData result =
i::Snapshot::CreateSnapshotBlob(&startup_snapshot, &context_snapshots);
// Delete heap-allocated context snapshot instances.
for (const auto& context_snapshot : context_snapshots) {
delete context_snapshot;
}
data->created_ = true; data->created_ = true;
return i::Snapshot::CreateSnapshotBlob(&startup_serializer, return result;
&context_serializer);
} }
StartupData V8::CreateSnapshotDataBlob(const char* embedded_source) { StartupData V8::CreateSnapshotDataBlob(const char* embedded_source) {
...@@ -5532,11 +5546,10 @@ const char* v8::V8::GetVersion() { ...@@ -5532,11 +5546,10 @@ const char* v8::V8::GetVersion() {
return i::Version::GetVersion(); return i::Version::GetVersion();
} }
static i::Handle<i::Context> CreateEnvironment( static i::Handle<i::Context> CreateEnvironment(
i::Isolate* isolate, v8::ExtensionConfiguration* extensions, i::Isolate* isolate, v8::ExtensionConfiguration* extensions,
v8::Local<ObjectTemplate> global_template, v8::Local<ObjectTemplate> global_template,
v8::Local<Value> maybe_global_proxy) { v8::Local<Value> maybe_global_proxy, size_t context_snapshot_index) {
i::Handle<i::Context> env; i::Handle<i::Context> env;
// Enter V8 via an ENTER_V8 scope. // Enter V8 via an ENTER_V8 scope.
...@@ -5581,7 +5594,7 @@ static i::Handle<i::Context> CreateEnvironment( ...@@ -5581,7 +5594,7 @@ static i::Handle<i::Context> CreateEnvironment(
} }
// Create the environment. // Create the environment.
env = isolate->bootstrapper()->CreateEnvironment( env = isolate->bootstrapper()->CreateEnvironment(
maybe_proxy, proxy_template, extensions); maybe_proxy, proxy_template, extensions, context_snapshot_index);
// Restore the access check info on the global template. // Restore the access check info on the global template.
if (!global_template.IsEmpty()) { if (!global_template.IsEmpty()) {
...@@ -5601,14 +5614,16 @@ static i::Handle<i::Context> CreateEnvironment( ...@@ -5601,14 +5614,16 @@ static i::Handle<i::Context> CreateEnvironment(
Local<Context> v8::Context::New(v8::Isolate* external_isolate, Local<Context> v8::Context::New(v8::Isolate* external_isolate,
v8::ExtensionConfiguration* extensions, v8::ExtensionConfiguration* extensions,
v8::Local<ObjectTemplate> global_template, v8::Local<ObjectTemplate> global_template,
v8::Local<Value> global_object) { v8::Local<Value> global_object,
size_t context_snapshot_index) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external_isolate); i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external_isolate);
LOG_API(isolate, Context, New); LOG_API(isolate, Context, New);
i::HandleScope scope(isolate); i::HandleScope scope(isolate);
ExtensionConfiguration no_extensions; ExtensionConfiguration no_extensions;
if (extensions == NULL) extensions = &no_extensions; if (extensions == NULL) extensions = &no_extensions;
i::Handle<i::Context> env = i::Handle<i::Context> env =
CreateEnvironment(isolate, extensions, global_template, global_object); CreateEnvironment(isolate, extensions, global_template, global_object,
context_snapshot_index);
if (env.is_null()) { if (env.is_null()) {
if (isolate->has_pending_exception()) { if (isolate->has_pending_exception()) {
isolate->OptionalRescheduleException(true); isolate->OptionalRescheduleException(true);
......
...@@ -138,7 +138,7 @@ class Genesis BASE_EMBEDDED { ...@@ -138,7 +138,7 @@ class Genesis BASE_EMBEDDED {
public: public:
Genesis(Isolate* isolate, MaybeHandle<JSGlobalProxy> maybe_global_proxy, Genesis(Isolate* isolate, MaybeHandle<JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_proxy_template, v8::Local<v8::ObjectTemplate> global_proxy_template,
v8::ExtensionConfiguration* extensions, v8::ExtensionConfiguration* extensions, size_t context_snapshot_index,
GlobalContextType context_type); GlobalContextType context_type);
~Genesis() { } ~Genesis() { }
...@@ -324,10 +324,11 @@ void Bootstrapper::Iterate(ObjectVisitor* v) { ...@@ -324,10 +324,11 @@ void Bootstrapper::Iterate(ObjectVisitor* v) {
Handle<Context> Bootstrapper::CreateEnvironment( Handle<Context> Bootstrapper::CreateEnvironment(
MaybeHandle<JSGlobalProxy> maybe_global_proxy, MaybeHandle<JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_proxy_template, v8::Local<v8::ObjectTemplate> global_proxy_template,
v8::ExtensionConfiguration* extensions, GlobalContextType context_type) { v8::ExtensionConfiguration* extensions, size_t context_snapshot_index,
GlobalContextType context_type) {
HandleScope scope(isolate_); HandleScope scope(isolate_);
Genesis genesis(isolate_, maybe_global_proxy, global_proxy_template, Genesis genesis(isolate_, maybe_global_proxy, global_proxy_template,
extensions, context_type); extensions, context_snapshot_index, context_type);
Handle<Context> env = genesis.result(); Handle<Context> env = genesis.result();
if (env.is_null() || if (env.is_null() ||
(context_type != THIN_CONTEXT && !InstallExtensions(env, extensions))) { (context_type != THIN_CONTEXT && !InstallExtensions(env, extensions))) {
...@@ -3800,7 +3801,7 @@ Genesis::Genesis(Isolate* isolate, ...@@ -3800,7 +3801,7 @@ Genesis::Genesis(Isolate* isolate,
MaybeHandle<JSGlobalProxy> maybe_global_proxy, MaybeHandle<JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_proxy_template, v8::Local<v8::ObjectTemplate> global_proxy_template,
v8::ExtensionConfiguration* extensions, v8::ExtensionConfiguration* extensions,
GlobalContextType context_type) size_t context_snapshot_index, GlobalContextType context_type)
: isolate_(isolate), active_(isolate->bootstrapper()) { : isolate_(isolate), active_(isolate->bootstrapper()) {
NoTrackDoubleFieldsForSerializerScope disable_scope(isolate); NoTrackDoubleFieldsForSerializerScope disable_scope(isolate);
result_ = Handle<Context>::null(); result_ = Handle<Context>::null();
...@@ -3829,7 +3830,8 @@ Genesis::Genesis(Isolate* isolate, ...@@ -3829,7 +3830,8 @@ Genesis::Genesis(Isolate* isolate,
// a snapshot. Otherwise we have to build the context from scratch. // a snapshot. Otherwise we have to build the context from scratch.
// Also create a context from scratch to expose natives, if required by flag. // Also create a context from scratch to expose natives, if required by flag.
if (!isolate->initialized_from_snapshot() || if (!isolate->initialized_from_snapshot() ||
!Snapshot::NewContextFromSnapshot(isolate, global_proxy) !Snapshot::NewContextFromSnapshot(isolate, global_proxy,
context_snapshot_index)
.ToHandle(&native_context_)) { .ToHandle(&native_context_)) {
native_context_ = Handle<Context>(); native_context_ = Handle<Context>();
} }
......
...@@ -79,7 +79,7 @@ class Bootstrapper final { ...@@ -79,7 +79,7 @@ class Bootstrapper final {
Handle<Context> CreateEnvironment( Handle<Context> CreateEnvironment(
MaybeHandle<JSGlobalProxy> maybe_global_proxy, MaybeHandle<JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_object_template, v8::Local<v8::ObjectTemplate> global_object_template,
v8::ExtensionConfiguration* extensions, v8::ExtensionConfiguration* extensions, size_t context_snapshot_index,
GlobalContextType context_type = FULL_CONTEXT); GlobalContextType context_type = FULL_CONTEXT);
// Detach the environment from its outer global object. // Detach the environment from its outer global object.
......
...@@ -536,9 +536,13 @@ bool Debug::Load() { ...@@ -536,9 +536,13 @@ bool Debug::Load() {
// Create the debugger context. // Create the debugger context.
HandleScope scope(isolate_); HandleScope scope(isolate_);
ExtensionConfiguration no_extensions; ExtensionConfiguration no_extensions;
// TODO(yangguo): we rely on the fact that first context snapshot is usable
// as debug context. This dependency is gone once we remove
// debug context completely.
static const int kFirstContextSnapshotIndex = 0;
Handle<Context> context = isolate_->bootstrapper()->CreateEnvironment( Handle<Context> context = isolate_->bootstrapper()->CreateEnvironment(
MaybeHandle<JSGlobalProxy>(), v8::Local<ObjectTemplate>(), &no_extensions, MaybeHandle<JSGlobalProxy>(), v8::Local<ObjectTemplate>(), &no_extensions,
DEBUG_CONTEXT); kFirstContextSnapshotIndex, DEBUG_CONTEXT);
// Fail if no context could be created. // Fail if no context could be created.
if (context.is_null()) return false; if (context.is_null()) return false;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "src/snapshot/partial-serializer.h" #include "src/snapshot/partial-serializer.h"
#include "src/snapshot/startup-serializer.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
...@@ -10,10 +11,8 @@ namespace v8 { ...@@ -10,10 +11,8 @@ namespace v8 {
namespace internal { namespace internal {
PartialSerializer::PartialSerializer(Isolate* isolate, PartialSerializer::PartialSerializer(Isolate* isolate,
Serializer* startup_snapshot_serializer) StartupSerializer* startup_serializer)
: Serializer(isolate), : Serializer(isolate), startup_serializer_(startup_serializer) {
startup_serializer_(startup_snapshot_serializer),
next_partial_cache_index_(0) {
InitializeCodeAddressMap(); InitializeCodeAddressMap();
} }
...@@ -61,7 +60,7 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code, ...@@ -61,7 +60,7 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
if (ShouldBeInThePartialSnapshotCache(obj)) { if (ShouldBeInThePartialSnapshotCache(obj)) {
FlushSkip(skip); FlushSkip(skip);
int cache_index = PartialSnapshotCacheIndex(obj); int cache_index = startup_serializer_->PartialSnapshotCacheIndex(obj);
sink_.Put(kPartialSnapshotCache + how_to_code + where_to_point, sink_.Put(kPartialSnapshotCache + how_to_code + where_to_point,
"PartialSnapshotCache"); "PartialSnapshotCache");
sink_.PutInt(cache_index, "partial_snapshot_cache_index"); sink_.PutInt(cache_index, "partial_snapshot_cache_index");
...@@ -93,19 +92,6 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code, ...@@ -93,19 +92,6 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
serializer.Serialize(); serializer.Serialize();
} }
int PartialSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) {
int index = partial_cache_index_map_.LookupOrInsert(
heap_object, next_partial_cache_index_);
if (index == PartialCacheIndexMap::kInvalidIndex) {
// This object is not part of the partial snapshot cache yet. Add it to the
// startup snapshot so we can refer to it via partial snapshot index from
// the partial snapshot.
startup_serializer_->VisitPointer(reinterpret_cast<Object**>(&heap_object));
return next_partial_cache_index_++;
}
return index;
}
bool PartialSerializer::ShouldBeInThePartialSnapshotCache(HeapObject* o) { bool PartialSerializer::ShouldBeInThePartialSnapshotCache(HeapObject* o) {
// Scripts should be referred only through shared function infos. We can't // Scripts should be referred only through shared function infos. We can't
// allow them to be part of the partial snapshot because they contain a // allow them to be part of the partial snapshot because they contain a
......
...@@ -11,9 +11,11 @@ ...@@ -11,9 +11,11 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class StartupSerializer;
class PartialSerializer : public Serializer { class PartialSerializer : public Serializer {
public: public:
PartialSerializer(Isolate* isolate, Serializer* startup_snapshot_serializer); PartialSerializer(Isolate* isolate, StartupSerializer* startup_serializer);
~PartialSerializer() override; ~PartialSerializer() override;
...@@ -21,36 +23,12 @@ class PartialSerializer : public Serializer { ...@@ -21,36 +23,12 @@ class PartialSerializer : public Serializer {
void Serialize(Object** o); void Serialize(Object** o);
private: private:
class PartialCacheIndexMap : public AddressMapBase {
public:
PartialCacheIndexMap() : map_(base::HashMap::PointersMatch) {}
static const int kInvalidIndex = -1;
// Lookup object in the map. Return its index if found, or create
// a new entry with new_index as value, and return kInvalidIndex.
int LookupOrInsert(HeapObject* obj, int new_index) {
base::HashMap::Entry* entry = LookupEntry(&map_, obj, false);
if (entry != NULL) return GetValue(entry);
SetValue(LookupEntry(&map_, obj, true), static_cast<uint32_t>(new_index));
return kInvalidIndex;
}
private:
base::HashMap map_;
DISALLOW_COPY_AND_ASSIGN(PartialCacheIndexMap);
};
void SerializeObject(HeapObject* o, HowToCode how_to_code, void SerializeObject(HeapObject* o, HowToCode how_to_code,
WhereToPoint where_to_point, int skip) override; WhereToPoint where_to_point, int skip) override;
int PartialSnapshotCacheIndex(HeapObject* o);
bool ShouldBeInThePartialSnapshotCache(HeapObject* o); bool ShouldBeInThePartialSnapshotCache(HeapObject* o);
Serializer* startup_serializer_; StartupSerializer* startup_serializer_;
PartialCacheIndexMap partial_cache_index_map_;
int next_partial_cache_index_;
DISALLOW_COPY_AND_ASSIGN(PartialSerializer); DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
}; };
......
This diff is collapsed.
...@@ -16,6 +16,41 @@ class Isolate; ...@@ -16,6 +16,41 @@ class Isolate;
class PartialSerializer; class PartialSerializer;
class StartupSerializer; class StartupSerializer;
// Wrapper around reservation sizes and the serialization payload.
class SnapshotData : public SerializedData {
public:
// Used when producing.
explicit SnapshotData(const Serializer* serializer);
// Used when consuming.
explicit SnapshotData(const Vector<const byte> snapshot)
: SerializedData(const_cast<byte*>(snapshot.begin()), snapshot.length()) {
CHECK(IsSane());
}
Vector<const Reservation> Reservations() const;
Vector<const byte> Payload() const;
Vector<const byte> RawData() const {
return Vector<const byte>(data_, size_);
}
private:
bool IsSane();
// The data header consists of uint32_t-sized entries:
// [0] magic number and external reference count
// [1] version hash
// [2] number of reservation size entries
// [3] payload length
// ... reservations
// ... serialized payload
static const int kCheckSumOffset = kMagicNumberOffset + kInt32Size;
static const int kNumReservationsOffset = kCheckSumOffset + kInt32Size;
static const int kPayloadLengthOffset = kNumReservationsOffset + kInt32Size;
static const int kHeaderSize = kPayloadLengthOffset + kInt32Size;
};
class Snapshot : public AllStatic { class Snapshot : public AllStatic {
public: public:
// Initialize the Isolate from the internal snapshot. Returns false if no // Initialize the Isolate from the internal snapshot. Returns false if no
...@@ -23,7 +58,8 @@ class Snapshot : public AllStatic { ...@@ -23,7 +58,8 @@ class Snapshot : public AllStatic {
static bool Initialize(Isolate* isolate); static bool Initialize(Isolate* isolate);
// Create a new context using the internal partial snapshot. // Create a new context using the internal partial snapshot.
static MaybeHandle<Context> NewContextFromSnapshot( static MaybeHandle<Context> NewContextFromSnapshot(
Isolate* isolate, Handle<JSGlobalProxy> global_proxy); Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
size_t context_index);
static bool HaveASnapshotToStartFrom(Isolate* isolate); static bool HaveASnapshotToStartFrom(Isolate* isolate);
...@@ -36,32 +72,44 @@ class Snapshot : public AllStatic { ...@@ -36,32 +72,44 @@ class Snapshot : public AllStatic {
static const v8::StartupData* DefaultSnapshotBlob(); static const v8::StartupData* DefaultSnapshotBlob();
static v8::StartupData CreateSnapshotBlob( static v8::StartupData CreateSnapshotBlob(
const StartupSerializer* startup_serializer, const SnapshotData* startup_snapshot,
const PartialSerializer* context_serializer); const List<SnapshotData*>* context_snapshots);
#ifdef DEBUG #ifdef DEBUG
static bool SnapshotIsValid(v8::StartupData* snapshot_blob); static bool SnapshotIsValid(v8::StartupData* snapshot_blob);
#endif // DEBUG #endif // DEBUG
private: private:
static int ExtractNumContexts(const v8::StartupData* data);
static Vector<const byte> ExtractStartupData(const v8::StartupData* data); static Vector<const byte> ExtractStartupData(const v8::StartupData* data);
static Vector<const byte> ExtractContextData(const v8::StartupData* data); static Vector<const byte> ExtractContextData(const v8::StartupData* data,
int index);
// Snapshot blob layout: // Snapshot blob layout:
// [0 - 5] pre-calculated first page sizes for paged spaces // [0 - 5] pre-calculated first page sizes for paged spaces
// [6] serialized start up data length // [6] number of contexts N
// ... serialized start up data // [7] offset to context 0
// ... serialized context data // [8] offset to context 1
// ...
// ... offset to context N - 1
// ... startup snapshot data
// ... context 0 snapshot data
// ... context 1 snapshot data
static const int kNumPagedSpaces = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1; static const int kNumPagedSpaces = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1;
static const int kFirstPageSizesOffset = 0; static const int kFirstPageSizesOffset = 0;
static const int kStartupLengthOffset = static const int kNumberOfContextsOffset =
kFirstPageSizesOffset + kNumPagedSpaces * kInt32Size; kFirstPageSizesOffset + kNumPagedSpaces * kInt32Size;
static const int kStartupDataOffset = kStartupLengthOffset + kInt32Size; static const int kFirstContextOffsetOffset =
kNumberOfContextsOffset + kInt32Size;
static int StartupSnapshotOffset(int num_contexts) {
return kFirstContextOffsetOffset + num_contexts * kInt32Size;
}
static int ContextOffset(int startup_length) { static int ContextSnapshotOffsetOffset(int index) {
return kStartupDataOffset + startup_length; return kFirstContextOffsetOffset + index * kInt32Size;
} }
DISALLOW_IMPLICIT_CONSTRUCTORS(Snapshot); DISALLOW_IMPLICIT_CONSTRUCTORS(Snapshot);
...@@ -71,41 +119,6 @@ class Snapshot : public AllStatic { ...@@ -71,41 +119,6 @@ class Snapshot : public AllStatic {
void SetSnapshotFromFile(StartupData* snapshot_blob); void SetSnapshotFromFile(StartupData* snapshot_blob);
#endif #endif
// Wrapper around reservation sizes and the serialization payload.
class SnapshotData : public SerializedData {
public:
// Used when producing.
explicit SnapshotData(const Serializer* serializer);
// Used when consuming.
explicit SnapshotData(const Vector<const byte> snapshot)
: SerializedData(const_cast<byte*>(snapshot.begin()), snapshot.length()) {
CHECK(IsSane());
}
Vector<const Reservation> Reservations() const;
Vector<const byte> Payload() const;
Vector<const byte> RawData() const {
return Vector<const byte>(data_, size_);
}
private:
bool IsSane();
// The data header consists of uint32_t-sized entries:
// [0] magic number and external reference count
// [1] version hash
// [2] number of reservation size entries
// [3] payload length
// ... reservations
// ... serialized payload
static const int kCheckSumOffset = kMagicNumberOffset + kInt32Size;
static const int kNumReservationsOffset = kCheckSumOffset + kInt32Size;
static const int kPayloadLengthOffset = kNumReservationsOffset + kInt32Size;
static const int kHeaderSize = kPayloadLengthOffset + kInt32Size;
};
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -90,6 +90,17 @@ void StartupSerializer::SerializeWeakReferencesAndDeferred() { ...@@ -90,6 +90,17 @@ void StartupSerializer::SerializeWeakReferencesAndDeferred() {
Pad(); Pad();
} }
int StartupSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) {
int index;
if (!partial_cache_index_map_.LookupOrInsert(heap_object, &index)) {
// This object is not part of the partial snapshot cache yet. Add it to the
// startup snapshot so we can refer to it via partial snapshot index from
// the partial snapshot.
VisitPointer(reinterpret_cast<Object**>(&heap_object));
}
return index;
}
void StartupSerializer::Synchronize(VisitorSynchronization::SyncTag tag) { void StartupSerializer::Synchronize(VisitorSynchronization::SyncTag tag) {
// We expect the builtins tag after builtins have been serialized. // We expect the builtins tag after builtins have been serialized.
DCHECK(!serializing_builtins_ || tag == VisitorSynchronization::kBuiltins); DCHECK(!serializing_builtins_ || tag == VisitorSynchronization::kBuiltins);
......
...@@ -27,7 +27,34 @@ class StartupSerializer : public Serializer { ...@@ -27,7 +27,34 @@ class StartupSerializer : public Serializer {
void SerializeStrongReferences(); void SerializeStrongReferences();
void SerializeWeakReferencesAndDeferred(); void SerializeWeakReferencesAndDeferred();
int PartialSnapshotCacheIndex(HeapObject* o);
private: private:
class PartialCacheIndexMap : public AddressMapBase {
public:
PartialCacheIndexMap()
: map_(base::HashMap::PointersMatch), next_index_(0) {}
// Lookup object in the map. Return its index if found, or create
// a new entry with new_index as value, and return kInvalidIndex.
bool LookupOrInsert(HeapObject* obj, int* index_out) {
base::HashMap::Entry* entry = LookupEntry(&map_, obj, false);
if (entry != NULL) {
*index_out = GetValue(entry);
return true;
}
*index_out = next_index_;
SetValue(LookupEntry(&map_, obj, true), next_index_++);
return false;
}
private:
base::HashMap map_;
int next_index_;
DISALLOW_COPY_AND_ASSIGN(PartialCacheIndexMap);
};
// The StartupSerializer has to serialize the root array, which is slightly // The StartupSerializer has to serialize the root array, which is slightly
// different. // different.
void VisitPointers(Object** start, Object** end) override; void VisitPointers(Object** start, Object** end) override;
...@@ -45,6 +72,7 @@ class StartupSerializer : public Serializer { ...@@ -45,6 +72,7 @@ class StartupSerializer : public Serializer {
bool serializing_builtins_; bool serializing_builtins_;
bool serializing_immortal_immovables_roots_; bool serializing_immortal_immovables_roots_;
std::bitset<Heap::kStrongRootListLength> root_has_been_serialized_; std::bitset<Heap::kStrongRootListLength> root_has_been_serialized_;
PartialCacheIndexMap partial_cache_index_map_;
DISALLOW_COPY_AND_ASSIGN(StartupSerializer); DISALLOW_COPY_AND_ASSIGN(StartupSerializer);
}; };
......
...@@ -1882,6 +1882,71 @@ TEST(CodeSerializerCell) { ...@@ -1882,6 +1882,71 @@ TEST(CodeSerializerCell) {
} }
#endif // V8_TARGET_ARCH_X64 #endif // V8_TARGET_ARCH_X64
TEST(SnapshotCreatorMultipleContexts) {
DisableTurbofan();
v8::StartupData blob;
{
v8::SnapshotCreator creator;
v8::Isolate* isolate = creator.GetIsolate();
{
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
CompileRun("var f = function() { return 1; }");
CHECK_EQ(0, creator.AddContext(context));
}
{
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
CompileRun("var f = function() { return 2; }");
CHECK_EQ(1, creator.AddContext(context));
}
{
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
CHECK_EQ(2, creator.AddContext(context));
}
blob =
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
}
v8::Isolate::CreateParams params;
params.snapshot_blob = &blob;
params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(params);
{
v8::Isolate::Scope isolate_scope(isolate);
v8::ExtensionConfiguration* no_extension = nullptr;
v8::Local<v8::ObjectTemplate> no_template = v8::Local<v8::ObjectTemplate>();
v8::Local<v8::Value> no_object = v8::Local<v8::Value>();
{
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Context::New(isolate, no_extension, no_template, no_object, 0);
v8::Context::Scope context_scope(context);
ExpectInt32("f()", 1);
}
{
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Context::New(isolate, no_extension, no_template, no_object, 1);
v8::Context::Scope context_scope(context);
ExpectInt32("f()", 2);
}
{
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Context::New(isolate, no_extension, no_template, no_object, 2);
v8::Context::Scope context_scope(context);
ExpectUndefined("this.f");
}
}
isolate->Dispose();
delete[] blob.data;
}
TEST(SerializationMemoryStats) { TEST(SerializationMemoryStats) {
FLAG_profile_deserialization = true; FLAG_profile_deserialization = true;
FLAG_always_opt = false; FLAG_always_opt = false;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
}, },
{ {
"name": "ReservedMemoryContext", "name": "ReservedMemoryContext",
"results_regexp": "(\\d+) bytes per context$" "results_regexp": "(\\d+) bytes per context #0$"
}, },
{ {
"name": "SnapshotSizeStartup", "name": "SnapshotSizeStartup",
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
}, },
{ {
"name": "SnapshotSizeContext", "name": "SnapshotSizeContext",
"results_regexp": "(\\d+) bytes for context$" "results_regexp": "(\\d+) bytes for context #0$"
} }
] ]
} }
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