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);
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();
}
#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(&contexts[i]);
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], 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,6 +4499,8 @@ Genesis::Genesis(Isolate* isolate,
Map::TraceAllTransitions(object_fun->initial_map());
}
#endif
if (create_new_global_proxy) {
Handle<JSGlobalObject> global_object =
CreateNewGlobals(global_proxy_template, global_proxy);
......@@ -4508,6 +4508,7 @@ Genesis::Genesis(Isolate* isolate,
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);
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();
}
......
......@@ -286,7 +286,7 @@ static void PartiallySerializeObject(Vector<const byte>* startup_blob_out,
startup_serializer.SerializeStrongReferences();
PartialSerializer partial_serializer(isolate, &startup_serializer, nullptr);
partial_serializer.Serialize(&raw_foo);
partial_serializer.Serialize(&raw_foo, false);
startup_serializer.SerializeWeakReferencesAndDeferred();
......@@ -386,7 +386,7 @@ static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
SnapshotByteSink partial_sink;
PartialSerializer partial_serializer(isolate, &startup_serializer, nullptr);
partial_serializer.Serialize(&raw_context);
partial_serializer.Serialize(&raw_context, false);
startup_serializer.SerializeWeakReferencesAndDeferred();
SnapshotData startup_snapshot(&startup_serializer);
......@@ -506,7 +506,7 @@ static void PartiallySerializeCustomContext(
SnapshotByteSink partial_sink;
PartialSerializer partial_serializer(isolate, &startup_serializer, nullptr);
partial_serializer.Serialize(&raw_context);
partial_serializer.Serialize(&raw_context, false);
startup_serializer.SerializeWeakReferencesAndDeferred();
SnapshotData startup_snapshot(&startup_serializer);
......@@ -1962,19 +1962,19 @@ TEST(SnapshotCreatorMultipleContexts) {
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
CompileRun("var f = function() { return 1; }");
CHECK_EQ(0u, creator.AddContext(context));
creator.SetDefaultContext(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(1u, creator.AddContext(context));
CHECK_EQ(0u, creator.AddContext(context));
}
{
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
CHECK_EQ(2u, creator.AddContext(context));
CHECK_EQ(1u, creator.AddContext(context));
}
blob =
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
......@@ -1988,22 +1988,21 @@ TEST(SnapshotCreatorMultipleContexts) {
v8::Isolate::Scope isolate_scope(isolate);
{
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
ExpectInt32("f()", 1);
}
{
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Context::FromSnapshot(isolate, 1).ToLocalChecked();
v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
v8::Context::Scope context_scope(context);
ExpectInt32("f()", 2);
}
{
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Context::FromSnapshot(isolate, 2).ToLocalChecked();
v8::Context::FromSnapshot(isolate, 1).ToLocalChecked();
v8::Context::Scope context_scope(context);
ExpectUndefined("this.f");
}
......@@ -2013,24 +2012,68 @@ TEST(SnapshotCreatorMultipleContexts) {
delete[] blob.data;
}
void SerializedCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
static void SerializedCallback(
const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(v8_num(42));
}
void SerializedCallbackReplacement(
static void SerializedCallbackReplacement(
const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(v8_num(1337));
}
static void NamedPropertyGetterForSerialization(
v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
if (name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("x"))
.FromJust()) {
info.GetReturnValue().Set(v8_num(2016));
}
}
static void AccessorForSerialization(
v8::Local<v8::String> property,
const v8::PropertyCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(v8_num(2017));
}
static int serialized_static_field = 314;
class SerializedExtension : public v8::Extension {
public:
SerializedExtension()
: v8::Extension("serialized extension",
"native function g();"
"function h() { return 13; };"
"function i() { return 14; };"
"var o = { p: 7 };") {}
virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
v8::Isolate* isolate, v8::Local<v8::String> name) {
CHECK(name->Equals(isolate->GetCurrentContext(), v8_str("g")).FromJust());
return v8::FunctionTemplate::New(isolate, FunctionCallback);
}
static void FunctionCallback(
const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(v8_num(12));
}
};
intptr_t original_external_references[] = {
reinterpret_cast<intptr_t>(SerializedCallback),
reinterpret_cast<intptr_t>(&serialized_static_field), 0};
reinterpret_cast<intptr_t>(&serialized_static_field),
reinterpret_cast<intptr_t>(&NamedPropertyGetterForSerialization),
reinterpret_cast<intptr_t>(&AccessorForSerialization),
reinterpret_cast<intptr_t>(&SerializedExtension::FunctionCallback),
0};
intptr_t replaced_external_references[] = {
reinterpret_cast<intptr_t>(SerializedCallbackReplacement),
reinterpret_cast<intptr_t>(&serialized_static_field), 0};
reinterpret_cast<intptr_t>(&serialized_static_field),
reinterpret_cast<intptr_t>(&NamedPropertyGetterForSerialization),
reinterpret_cast<intptr_t>(&AccessorForSerialization),
reinterpret_cast<intptr_t>(&SerializedExtension::FunctionCallback),
0};
TEST(SnapshotCreatorExternalReferences) {
DisableAlwaysOpt();
......@@ -2048,7 +2091,7 @@ TEST(SnapshotCreatorExternalReferences) {
callback->GetFunction(context).ToLocalChecked();
CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
ExpectInt32("f()", 42);
CHECK_EQ(0u, creator.AddContext(context));
creator.SetDefaultContext(context);
}
blob =
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
......@@ -2064,8 +2107,7 @@ TEST(SnapshotCreatorExternalReferences) {
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
ExpectInt32("f()", 42);
}
......@@ -2082,8 +2124,7 @@ TEST(SnapshotCreatorExternalReferences) {
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
ExpectInt32("f()", 1337);
}
......@@ -2108,7 +2149,7 @@ TEST(SnapshotCreatorUnknownExternalReferences) {
CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
ExpectInt32("f()", 42);
CHECK_EQ(0u, creator.AddContext(context));
creator.SetDefaultContext(context);
}
v8::StartupData blob =
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
......@@ -2185,7 +2226,7 @@ TEST(SnapshotCreatorTemplates) {
c->SetInternalField(2, field_external);
CHECK(context->Global()->Set(context, v8_str("a"), a).FromJust());
CHECK_EQ(0u, creator.AddContext(context));
creator.SetDefaultContext(context);
CHECK_EQ(0u, creator.AddTemplate(callback));
CHECK_EQ(1u, creator.AddTemplate(global_template));
}
......@@ -2209,8 +2250,7 @@ TEST(SnapshotCreatorTemplates) {
{
// Create a new context without a new object template.
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
ExpectInt32("f()", 42);
......@@ -2272,7 +2312,7 @@ TEST(SnapshotCreatorTemplates) {
// Accessing out of bound returns empty MaybeHandle.
CHECK(v8::ObjectTemplate::FromSnapshot(isolate, 2).IsEmpty());
CHECK(v8::FunctionTemplate::FromSnapshot(isolate, 2).IsEmpty());
CHECK(v8::Context::FromSnapshot(isolate, 2).IsEmpty());
CHECK(v8::Context::FromSnapshot(isolate, 1).IsEmpty());
delete a1;
delete b0;
......@@ -2290,8 +2330,7 @@ TEST(SnapshotCreatorTemplates) {
v8_str("g"),
v8::FunctionTemplate::New(isolate, SerializedCallbackReplacement));
v8::Local<v8::Context> context =
v8::Context::FromSnapshot(isolate, 0, no_extension, global_template)
.ToLocalChecked();
v8::Context::New(isolate, no_extension, global_template);
v8::Context::Scope context_scope(context);
ExpectInt32("g()", 1337);
ExpectInt32("f()", 42);
......@@ -2302,6 +2341,124 @@ TEST(SnapshotCreatorTemplates) {
delete[] blob.data;
}
TEST(SnapshotCreatorIncludeGlobalProxy) {
DisableAlwaysOpt();
v8::StartupData blob;
{
v8::SnapshotCreator creator(original_external_references);
v8::Isolate* isolate = creator.GetIsolate();
v8::RegisterExtension(new SerializedExtension);
const char* extension_names[] = {"serialized extension"};
v8::ExtensionConfiguration extensions(1, extension_names);
{
// Set default context. This context implicitly does *not* serialize
// the global proxy, and upon deserialization one has to be created
// in the bootstrapper from the global object template.
// Side effects from extensions are persisted though.
v8::HandleScope handle_scope(isolate);
v8::Local<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New(isolate);
v8::Local<v8::FunctionTemplate> callback =
v8::FunctionTemplate::New(isolate, SerializedCallback);
global_template->Set(v8_str("f"), callback);
global_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
NamedPropertyGetterForSerialization));
v8::Local<v8::Context> context =
v8::Context::New(isolate, &extensions, global_template);
v8::Context::Scope context_scope(context);
ExpectInt32("f()", 42);
ExpectInt32("g()", 12);
ExpectInt32("h()", 13);
ExpectInt32("o.p", 7);
ExpectInt32("x", 2016);
creator.SetDefaultContext(context);
}
{
// Add additional context. This context implicitly *does* serialize
// the global proxy, and upon deserialization one has to be created
// in the bootstrapper from the global object template.
// Side effects from extensions are persisted.
v8::HandleScope handle_scope(isolate);
v8::Local<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New(isolate);
v8::Local<v8::FunctionTemplate> callback =
v8::FunctionTemplate::New(isolate, SerializedCallback);
global_template->Set(v8_str("f"), callback);
global_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
NamedPropertyGetterForSerialization));
global_template->SetAccessor(v8_str("y"), AccessorForSerialization);
v8::Local<v8::Context> context =
v8::Context::New(isolate, &extensions, global_template);
v8::Context::Scope context_scope(context);
ExpectInt32("f()", 42);
ExpectInt32("g()", 12);
ExpectInt32("h()", 13);
ExpectInt32("o.p", 7);
ExpectInt32("x", 2016);
ExpectInt32("y", 2017);
CHECK_EQ(0u, creator.AddContext(context));
}
blob = creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear,
SerializeInternalFields);
}
{
v8::Isolate::CreateParams params;
params.snapshot_blob = &blob;
params.array_buffer_allocator = CcTest::array_buffer_allocator();
params.external_references = original_external_references;
params.deserialize_internal_fields_callback = DeserializeInternalFields;
v8::Isolate* isolate = v8::Isolate::New(params);
{
v8::Isolate::Scope isolate_scope(isolate);
// We can introduce new extensions, which could override the already
// snapshotted extension.
v8::Extension* extension = new v8::Extension("new extension",
"function i() { return 24; }"
"function j() { return 25; }"
"if (o.p == 7) o.p++;");
extension->set_auto_enable(true);
v8::RegisterExtension(extension);
{
// Create a new context from default context snapshot. This will
// create a new global object from a new global object template
// without the interceptor.
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
ExpectInt32("f()", 42);
ExpectInt32("g()", 12);
ExpectInt32("h()", 13);
ExpectInt32("i()", 24);
ExpectInt32("j()", 25);
ExpectInt32("o.p", 8);
v8::TryCatch try_catch(isolate);
CHECK(CompileRun("x").IsEmpty());
CHECK(try_catch.HasCaught());
}
{
// Create a new context from first additional context snapshot. This
// will use the global object from the snapshot, including interceptor.
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
v8::Context::Scope context_scope(context);
ExpectInt32("f()", 42);
ExpectInt32("g()", 12);
ExpectInt32("h()", 13);
ExpectInt32("i()", 24);
ExpectInt32("j()", 25);
ExpectInt32("o.p", 8);
ExpectInt32("x", 2016);
ExpectInt32("y", 2017);
}
}
isolate->Dispose();
}
delete[] blob.data;
}
TEST(SerializationMemoryStats) {
FLAG_profile_deserialization = true;
FLAG_always_opt = false;
......
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