Commit 98b563eb authored by yangguo's avatar yangguo Committed by Commit bot

[serializer] include global proxy in additional context snapshots.

Aside from the default snapshot, there is no need for additional context
snapshots to have the ability to replace the global proxy and global object
after deserialization. Changes include:
 - Changes to the API to better distinguish default context snapshot from
   additional context snapshots.
 - Disallow global handles when creating snapshots.
 - Allow extensions when creating snapshots.

This solves the issue of not being able to having accessors and interceptors on
the global object of contexts to be serialized.

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

Review-Url: https://codereview.chromium.org/2557743003
Cr-Commit-Position: refs/heads/master@{#41588}
parent 1416c6c9
......@@ -7560,7 +7560,16 @@ class V8_EXPORT SnapshotCreator {
Isolate* GetIsolate();
/**
* Add a context to be included in the snapshot blob.
* Set the default context to be included in the snapshot blob.
* The snapshot will not contain the global proxy, and we expect one or a
* global object template to create one, to be provided upon deserialization.
*/
void SetDefaultContext(Local<Context> context);
/**
* Add additional context to be included in the snapshot blob.
* The snapshot will include the global proxy.
*
* \returns the index of the context in the snapshot blob.
*/
size_t AddContext(Local<Context> context);
......@@ -7884,11 +7893,22 @@ class V8_EXPORT Context {
MaybeLocal<ObjectTemplate> global_template = MaybeLocal<ObjectTemplate>(),
MaybeLocal<Value> global_object = MaybeLocal<Value>());
/**
* Create a new context from a (non-default) context snapshot. There
* is no way to provide a global template or global proxy since the
* context snapshot already contains a global proxy.
*
* \param isolate See v8::Context::New.
*
* \param context_snapshot_index The index of the context snapshot to
* deserialize from. Use v8::Context::New for the default snapshot.
*
* \param extensions See v8::Context::New.
*/
static MaybeLocal<Context> FromSnapshot(
Isolate* isolate, size_t context_snapshot_index,
ExtensionConfiguration* extensions = nullptr,
MaybeLocal<ObjectTemplate> global_template = MaybeLocal<ObjectTemplate>(),
MaybeLocal<Value> global_object = MaybeLocal<Value>());
ExtensionConfiguration* extensions = nullptr);
/**
* Returns an global object that isn't backed by an actual context.
......
......@@ -460,6 +460,7 @@ bool RunExtraCode(Isolate* isolate, Local<Context> context,
struct SnapshotCreatorData {
explicit SnapshotCreatorData(Isolate* isolate)
: isolate_(isolate),
default_context_(),
contexts_(isolate),
templates_(isolate),
created_(false) {}
......@@ -470,6 +471,7 @@ struct SnapshotCreatorData {
ArrayBufferAllocator allocator_;
Isolate* isolate_;
Persistent<Context> default_context_;
PersistentValueVector<Context> contexts_;
PersistentValueVector<Template> templates_;
bool created_;
......@@ -508,6 +510,16 @@ Isolate* SnapshotCreator::GetIsolate() {
return SnapshotCreatorData::cast(data_)->isolate_;
}
void SnapshotCreator::SetDefaultContext(Local<Context> context) {
DCHECK(!context.IsEmpty());
SnapshotCreatorData* data = SnapshotCreatorData::cast(data_);
DCHECK(!data->created_);
DCHECK(data->default_context_.IsEmpty());
Isolate* isolate = data->isolate_;
CHECK_EQ(isolate, context->GetIsolate());
data->default_context_.Reset(isolate, context);
}
size_t SnapshotCreator::AddContext(Local<Context> context) {
DCHECK(!context.IsEmpty());
SnapshotCreatorData* data = SnapshotCreatorData::cast(data_);
......@@ -536,6 +548,7 @@ StartupData SnapshotCreator::CreateBlob(
SnapshotCreatorData* data = SnapshotCreatorData::cast(data_);
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(data->isolate_);
DCHECK(!data->created_);
DCHECK(!data->default_context_.IsEmpty());
{
int num_templates = static_cast<int>(data->templates_.Size());
......@@ -557,15 +570,21 @@ StartupData SnapshotCreator::CreateBlob(
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++) {
int num_additional_contexts = static_cast<int>(data->contexts_.Size());
i::List<i::Object*> contexts(num_additional_contexts);
i::Object* default_context;
{
i::HandleScope scope(isolate);
i::Handle<i::Context> context =
v8::Utils::OpenHandle(*data->contexts_.Get(i));
contexts.Add(*context);
default_context =
*v8::Utils::OpenHandle(*data->default_context_.Get(data->isolate_));
data->default_context_.Reset();
for (int i = 0; i < num_additional_contexts; i++) {
i::Handle<i::Context> context =
v8::Utils::OpenHandle(*data->contexts_.Get(i));
contexts.Add(*context);
}
data->contexts_.Clear();
}
data->contexts_.Clear();
#ifdef DEBUG
i::ExternalReferenceTable::instance(isolate)->ResetCount();
......@@ -575,11 +594,19 @@ StartupData SnapshotCreator::CreateBlob(
startup_serializer.SerializeStrongReferences();
// Serialize each context with a new partial serializer.
i::List<i::SnapshotData*> context_snapshots(num_contexts);
for (int i = 0; i < num_contexts; i++) {
i::List<i::SnapshotData*> context_snapshots(num_additional_contexts + 1);
{
i::PartialSerializer partial_serializer(isolate, &startup_serializer,
callback);
partial_serializer.Serialize(&default_context, false);
context_snapshots.Add(new i::SnapshotData(&partial_serializer));
}
for (int i = 0; i < num_additional_contexts; i++) {
i::PartialSerializer partial_serializer(isolate, &startup_serializer,
callback);
partial_serializer.Serialize(&contexts[i]);
partial_serializer.Serialize(&contexts[i], true);
context_snapshots.Add(new i::SnapshotData(&partial_serializer));
}
......@@ -619,7 +646,7 @@ StartupData V8::CreateSnapshotDataBlob(const char* embedded_source) {
!RunExtraCode(isolate, context, embedded_source, "<embedded>")) {
return result;
}
snapshot_creator.AddContext(context);
snapshot_creator.SetDefaultContext(context);
}
result = snapshot_creator.CreateBlob(
SnapshotCreator::FunctionCodeHandling::kClear);
......@@ -660,7 +687,7 @@ StartupData V8::WarmUpSnapshotDataBlob(StartupData cold_snapshot_blob,
HandleScope handle_scope(isolate);
isolate->ContextDisposedNotification(false);
Local<Context> context = Context::New(isolate);
snapshot_creator.AddContext(context);
snapshot_creator.SetDefaultContext(context);
}
result = snapshot_creator.CreateBlob(
SnapshotCreator::FunctionCodeHandling::kKeep);
......@@ -6213,16 +6240,15 @@ Local<Context> v8::Context::New(v8::Isolate* external_isolate,
MaybeLocal<Context> v8::Context::FromSnapshot(
v8::Isolate* external_isolate, size_t context_snapshot_index,
v8::ExtensionConfiguration* extensions,
v8::MaybeLocal<ObjectTemplate> global_template,
v8::MaybeLocal<Value> global_object) {
v8::ExtensionConfiguration* extensions) {
size_t index_including_default_context = context_snapshot_index + 1;
if (!i::Snapshot::HasContextSnapshot(
reinterpret_cast<i::Isolate*>(external_isolate),
context_snapshot_index)) {
index_including_default_context)) {
return MaybeLocal<Context>();
}
return NewContext(external_isolate, extensions, global_template,
global_object, context_snapshot_index);
return NewContext(external_isolate, extensions, MaybeLocal<ObjectTemplate>(),
MaybeLocal<Value>(), index_including_default_context);
}
MaybeLocal<Object> v8::Context::NewRemoteContext(
......
......@@ -140,8 +140,7 @@ class Genesis BASE_EMBEDDED {
public:
Genesis(Isolate* isolate, MaybeHandle<JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_proxy_template,
v8::ExtensionConfiguration* extensions, size_t context_snapshot_index,
GlobalContextType context_type);
size_t context_snapshot_index, GlobalContextType context_type);
Genesis(Isolate* isolate, MaybeHandle<JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_proxy_template);
~Genesis() { }
......@@ -314,7 +313,7 @@ Handle<Context> Bootstrapper::CreateEnvironment(
GlobalContextType context_type) {
HandleScope scope(isolate_);
Genesis genesis(isolate_, maybe_global_proxy, global_proxy_template,
extensions, context_snapshot_index, context_type);
context_snapshot_index, context_type);
Handle<Context> env = genesis.result();
if (env.is_null() || !InstallExtensions(env, extensions)) {
return Handle<Context>();
......@@ -4213,7 +4212,6 @@ bool Genesis::InstallExtension(Isolate* isolate,
isolate->clear_pending_exception();
}
extension_states->set_state(current, INSTALLED);
isolate->NotifyExtensionInstalled();
return result;
}
......@@ -4347,7 +4345,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
Handle<Object> value(cell->value(), isolate());
if (value->IsTheHole(isolate())) continue;
PropertyDetails details = cell->property_details();
DCHECK_EQ(kData, details.kind());
if (details.kind() != kData) continue;
JSObject::AddProperty(to, key, value, details.attributes());
}
} else {
......@@ -4445,12 +4443,12 @@ class NoTrackDoubleFieldsForSerializerScope {
Genesis::Genesis(Isolate* isolate,
MaybeHandle<JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_proxy_template,
v8::ExtensionConfiguration* extensions,
size_t context_snapshot_index, GlobalContextType context_type)
: isolate_(isolate), active_(isolate->bootstrapper()) {
NoTrackDoubleFieldsForSerializerScope disable_scope(isolate);
result_ = Handle<Context>::null();
global_proxy_ = Handle<JSGlobalProxy>::null();
bool create_new_global_proxy = context_snapshot_index == 0;
// Before creating the roots we must save the context and restore it
// on all function exits.
......@@ -4469,7 +4467,7 @@ Genesis::Genesis(Isolate* isolate,
// Create an uninitialized global proxy now if we don't have one
// and initialize it later in CreateNewGlobals.
Handle<JSGlobalProxy> global_proxy;
if (!maybe_global_proxy.ToHandle(&global_proxy)) {
if (!maybe_global_proxy.ToHandle(&global_proxy) && create_new_global_proxy) {
const int internal_field_count =
!global_proxy_template.IsEmpty()
? global_proxy_template->InternalFieldCount()
......@@ -4501,13 +4499,16 @@ Genesis::Genesis(Isolate* isolate,
Map::TraceAllTransitions(object_fun->initial_map());
}
#endif
Handle<JSGlobalObject> global_object =
CreateNewGlobals(global_proxy_template, global_proxy);
HookUpGlobalProxy(global_object, global_proxy);
HookUpGlobalObject(global_object);
if (create_new_global_proxy) {
Handle<JSGlobalObject> global_object =
CreateNewGlobals(global_proxy_template, global_proxy);
if (!ConfigureGlobalObjects(global_proxy_template)) return;
HookUpGlobalProxy(global_object, global_proxy);
HookUpGlobalObject(global_object);
if (!ConfigureGlobalObjects(global_proxy_template)) return;
}
} else {
// We get here if there was no context snapshot.
CreateRoots();
......@@ -4529,9 +4530,6 @@ Genesis::Genesis(Isolate* isolate,
if (!ConfigureGlobalObjects(global_proxy_template)) return;
isolate->counters()->contexts_created_from_scratch()->Increment();
// Re-initialize the counter because it got incremented during snapshot
// creation.
isolate->native_context()->set_errors_thrown(Smi::kZero);
}
// Install experimental natives. Do not include them into the
......@@ -4560,6 +4558,7 @@ Genesis::Genesis(Isolate* isolate,
// We do not need script contexts for native scripts.
DCHECK_EQ(1, native_context()->script_context_table()->used());
native_context()->ResetErrorsThrown();
result_ = native_context();
}
......
......@@ -758,6 +758,10 @@ bool Context::IsBootstrappingOrValidParentContext(
#endif
void Context::ResetErrorsThrown() {
DCHECK(IsNativeContext());
set_errors_thrown(Smi::FromInt(0));
}
void Context::IncrementErrorsThrown() {
DCHECK(IsNativeContext());
......
......@@ -499,6 +499,7 @@ class Context: public FixedArray {
WHITE_LIST_INDEX = MIN_CONTEXT_SLOTS + 1
};
void ResetErrorsThrown();
void IncrementErrorsThrown();
int GetErrorsThrown();
......
......@@ -4926,8 +4926,9 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
case VISIT_ONLY_STRONG_ROOT_LIST:
UNREACHABLE();
break;
case VISIT_ONLY_STRONG:
case VISIT_ONLY_STRONG_FOR_SERIALIZATION:
break;
case VISIT_ONLY_STRONG:
isolate_->global_handles()->IterateStrongRoots(v);
break;
case VISIT_ALL_IN_SCAVENGE:
......
......@@ -2119,7 +2119,6 @@ Isolate::Isolate(bool enable_serializer)
global_handles_(NULL),
eternal_handles_(NULL),
thread_manager_(NULL),
has_installed_extensions_(false),
regexp_stack_(NULL),
date_cache_(NULL),
call_descriptor_data_(NULL),
......
......@@ -907,12 +907,6 @@ class Isolate {
Builtins* builtins() { return &builtins_; }
void NotifyExtensionInstalled() {
has_installed_extensions_ = true;
}
bool has_installed_extensions() { return has_installed_extensions_; }
unibrow::Mapping<unibrow::Ecma262Canonicalize>*
regexp_macro_assembler_canonicalize() {
return &regexp_macro_assembler_canonicalize_;
......@@ -1348,7 +1342,6 @@ class Isolate {
ThreadManager* thread_manager_;
RuntimeState runtime_state_;
Builtins builtins_;
bool has_installed_extensions_;
unibrow::Mapping<unibrow::Ecma262UnCanonicalize> jsregexp_uncanonicalize_;
unibrow::Mapping<unibrow::CanonicalizationRange> jsregexp_canonrange_;
unibrow::Mapping<unibrow::Ecma262Canonicalize>
......
......@@ -23,10 +23,12 @@ PartialSerializer::~PartialSerializer() {
OutputStatistics("PartialSerializer");
}
void PartialSerializer::Serialize(Object** o) {
void PartialSerializer::Serialize(Object** o, bool include_global_proxy) {
if ((*o)->IsContext()) {
Context* context = Context::cast(*o);
reference_map()->AddAttachedReference(context->global_proxy());
if (!include_global_proxy) {
reference_map()->AddAttachedReference(context->global_proxy());
}
// The bootstrap snapshot has a code-stub context. When serializing the
// partial snapshot, it is chained into the weak context list on the isolate
// and it's next context pointer may point to the code-stub context. Clear
......
......@@ -21,7 +21,7 @@ class PartialSerializer : public Serializer {
~PartialSerializer() override;
// Serialize the objects reachable from a single object pointer.
void Serialize(Object** o);
void Serialize(Object** o, bool include_global_proxy);
private:
void SerializeObject(HeapObject* o, HowToCode how_to_code,
......
......@@ -62,6 +62,11 @@ MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
SnapshotData snapshot_data(context_data);
Deserializer deserializer(&snapshot_data);
if (context_index > 0) {
// A non-default context uses the global proxy from the snapshot.
DCHECK(global_proxy.is_null());
}
MaybeHandle<Object> maybe_context =
deserializer.DeserializePartial(isolate, global_proxy);
Handle<Object> result;
......
......@@ -125,10 +125,8 @@ void StartupSerializer::SerializeStrongReferences() {
CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
// No active or weak handles.
CHECK(isolate->handle_scope_implementer()->blocks()->is_empty());
CHECK_EQ(0, isolate->global_handles()->NumberOfWeakHandles());
CHECK_EQ(0, isolate->global_handles()->global_handles_count());
CHECK_EQ(0, isolate->eternal_handles()->NumberOfHandles());
// We don't support serializing installed extensions.
CHECK(!isolate->has_installed_extensions());
// First visit immortal immovables to make sure they end up in the first page.
serializing_immortal_immovables_roots_ = true;
isolate->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG_ROOT_LIST);
......
......@@ -686,12 +686,9 @@ class IsolateGenesisThread : public JoinableThread {
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
v8::Isolate::Scope isolate_scope(isolate);
CHECK(
!reinterpret_cast<i::Isolate*>(isolate)->has_installed_extensions());
v8::ExtensionConfiguration extensions(count_, extension_names_);
v8::HandleScope handle_scope(isolate);
v8::Context::New(isolate, &extensions);
CHECK(reinterpret_cast<i::Isolate*>(isolate)->has_installed_extensions());
}
isolate->Dispose();
}
......
This diff is collapsed.
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