Commit 449829b8 authored by yangguo's avatar yangguo Committed by Commit bot

[serializer] API to re-use global proxy in v8::Context::FromSnapshot.

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

Review-Url: https://codereview.chromium.org/2571743002
Cr-Commit-Position: refs/heads/master@{#41668}
parent 397a09af
......@@ -7927,8 +7927,8 @@ class V8_EXPORT Context {
/**
* 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.
* is no way to provide a global object template since we do not create
* a new global object from template, but we can reuse a global object.
*
* \param isolate See v8::Context::New.
*
......@@ -7936,11 +7936,14 @@ class V8_EXPORT Context {
* deserialize from. Use v8::Context::New for the default snapshot.
*
* \param extensions See v8::Context::New.
*
* \param global_object See v8::Context::New.
*/
static MaybeLocal<Context> FromSnapshot(
Isolate* isolate, size_t context_snapshot_index,
ExtensionConfiguration* extensions = nullptr);
ExtensionConfiguration* extensions = nullptr,
MaybeLocal<Value> global_object = MaybeLocal<Value>());
/**
* Returns an global object that isn't backed by an actual context.
......
......@@ -6245,7 +6245,7 @@ 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::ExtensionConfiguration* extensions, MaybeLocal<Value> global_object) {
size_t index_including_default_context = context_snapshot_index + 1;
if (!i::Snapshot::HasContextSnapshot(
reinterpret_cast<i::Isolate*>(external_isolate),
......@@ -6253,7 +6253,7 @@ MaybeLocal<Context> v8::Context::FromSnapshot(
return MaybeLocal<Context>();
}
return NewContext(external_isolate, extensions, MaybeLocal<ObjectTemplate>(),
MaybeLocal<Value>(), index_including_default_context);
global_object, index_including_default_context);
}
MaybeLocal<Object> v8::Context::NewRemoteContext(
......
......@@ -177,20 +177,19 @@ class Genesis BASE_EMBEDDED {
// in through the API. We call this regardless of whether we are building a
// context from scratch or using a deserialized one from the partial snapshot
// but in the latter case we don't use the objects it produces directly, as
// we have to used the deserialized ones that are linked together with the
// rest of the context snapshot.
// we have to use the deserialized ones that are linked together with the
// rest of the context snapshot. At the end we link the global proxy and the
// context to each other.
Handle<JSGlobalObject> CreateNewGlobals(
v8::Local<v8::ObjectTemplate> global_proxy_template,
Handle<JSGlobalProxy> global_proxy);
// Hooks the given global proxy into the context. If the context was created
// by deserialization then this will unhook the global proxy that was
// deserialized, leaving the GC to pick it up.
void HookUpGlobalProxy(Handle<JSGlobalObject> global_object,
Handle<JSGlobalProxy> global_proxy);
// Similarly, we want to use the global that has been created by the templates
// passed through the API. The global from the snapshot is detached from the
// other objects in the snapshot.
void HookUpGlobalObject(Handle<JSGlobalObject> global_object);
// Hooks the given global proxy into the context in the case we do not
// replace the global object from the deserialized native context.
void HookUpGlobalProxy(Handle<JSGlobalProxy> global_proxy);
// The native context has a ScriptContextTable that store declarative bindings
// made in script scopes. Add a "this" binding to that table pointing to the
// global proxy.
......@@ -990,30 +989,42 @@ Handle<JSGlobalObject> Genesis::CreateNewGlobals(
global_proxy_function->shared()->set_instance_class_name(*global_name);
global_proxy_function->initial_map()->set_is_access_check_needed(true);
global_proxy_function->initial_map()->set_has_hidden_prototype(true);
native_context()->set_global_proxy_function(*global_proxy_function);
// Set global_proxy.__proto__ to js_global after ConfigureGlobalObjects
// Return the global proxy.
factory()->ReinitializeJSGlobalProxy(global_proxy, global_proxy_function);
return global_object;
}
void Genesis::HookUpGlobalProxy(Handle<JSGlobalObject> global_object,
Handle<JSGlobalProxy> global_proxy) {
// Set the native context for the global object.
global_object->set_native_context(*native_context());
global_object->set_global_proxy(*global_proxy);
// Set the native context of the global proxy.
global_proxy->set_native_context(*native_context());
// If we deserialized the context, the global proxy is already
// correctly set up. Otherwise it's undefined.
// Set the global proxy of the native context. If the native context has been
// deserialized, the global proxy is already correctly set up by the
// deserializer. Otherwise it's undefined.
DCHECK(native_context()
->get(Context::GLOBAL_PROXY_INDEX)
->IsUndefined(isolate()) ||
native_context()->global_proxy() == *global_proxy);
native_context()->set_global_proxy(*global_proxy);
return global_object;
}
void Genesis::HookUpGlobalProxy(Handle<JSGlobalProxy> global_proxy) {
// Re-initialize the global proxy with the global proxy function from the
// snapshot, and then set up the link to the native context.
Handle<JSFunction> global_proxy_function(
native_context()->global_proxy_function());
factory()->ReinitializeJSGlobalProxy(global_proxy, global_proxy_function);
Handle<JSObject> global_object(
JSObject::cast(native_context()->global_object()));
JSObject::ForceSetPrototype(global_proxy, global_object);
global_proxy->set_native_context(*native_context());
DCHECK(native_context()->global_proxy() == *global_proxy);
}
void Genesis::HookUpGlobalObject(Handle<JSGlobalObject> global_object) {
Handle<JSGlobalObject> global_object_from_snapshot(
......@@ -4451,7 +4462,6 @@ Genesis::Genesis(Isolate* isolate,
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.
......@@ -4470,7 +4480,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) && create_new_global_proxy) {
if (!maybe_global_proxy.ToHandle(&global_proxy)) {
const int internal_field_count =
!global_proxy_template.IsEmpty()
? global_proxy_template->InternalFieldCount()
......@@ -4503,16 +4513,19 @@ Genesis::Genesis(Isolate* isolate,
}
#endif
if (create_new_global_proxy) {
if (context_snapshot_index == 0) {
Handle<JSGlobalObject> global_object =
CreateNewGlobals(global_proxy_template, global_proxy);
HookUpGlobalProxy(global_object, global_proxy);
HookUpGlobalObject(global_object);
if (!ConfigureGlobalObjects(global_proxy_template)) return;
} else {
// The global proxy needs to be integrated into the native context.
HookUpGlobalProxy(global_proxy);
}
DCHECK(!global_proxy->IsDetachedFrom(native_context()->global_object()));
} else {
DCHECK_EQ(0u, context_snapshot_index);
// We get here if there was no context snapshot.
CreateRoots();
Handle<JSFunction> empty_function = CreateEmptyFunction(isolate);
......@@ -4521,7 +4534,6 @@ Genesis::Genesis(Isolate* isolate,
CreateAsyncFunctionMaps(empty_function);
Handle<JSGlobalObject> global_object =
CreateNewGlobals(global_proxy_template, global_proxy);
HookUpGlobalProxy(global_object, global_proxy);
InitializeGlobal(global_object, empty_function, context_type);
InitializeNormalizedMapCaches();
......@@ -4622,7 +4634,7 @@ Genesis::Genesis(Isolate* isolate,
global_proxy_function->shared()->set_instance_class_name(*global_name);
factory()->ReinitializeJSGlobalProxy(global_proxy, global_proxy_function);
// HookUpGlobalProxy.
// GlobalProxy.
global_proxy->set_native_context(heap()->null_value());
// DetachGlobal.
......
......@@ -91,6 +91,7 @@ enum ContextLookupFlags {
V(ERROR_TO_STRING, JSFunction, error_to_string) \
V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \
V(GLOBAL_EVAL_FUN_INDEX, JSFunction, global_eval_fun) \
V(GLOBAL_PROXY_FUNCTION_INDEX, JSFunction, global_proxy_function) \
V(MAP_DELETE_METHOD_INDEX, JSFunction, map_delete) \
V(MAP_GET_METHOD_INDEX, JSFunction, map_get) \
V(MAP_HAS_METHOD_INDEX, JSFunction, map_has) \
......
......@@ -26,9 +26,7 @@ PartialSerializer::~PartialSerializer() {
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());
}
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
......
......@@ -62,11 +62,6 @@ 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;
......
......@@ -2443,15 +2443,37 @@ TEST(SnapshotCreatorIncludeGlobalProxy) {
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);
{
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);
}
v8::Local<v8::Object> global = context->Global();
context->DetachGlobal();
// New context, but reuse global proxy.
v8::ExtensionConfiguration* no_extensions = nullptr;
v8::Local<v8::Context> context2 =
v8::Context::FromSnapshot(isolate, 0, no_extensions, global)
.ToLocalChecked();
{
v8::Context::Scope context_scope(context2);
ExpectInt32("f()", 42);
ExpectInt32("g()", 12);
ExpectInt32("h()", 13);
ExpectInt32("i()", 24);
ExpectInt32("j()", 25);
ExpectInt32("o.p", 8);
ExpectInt32("x", 2016);
}
CHECK(context2->Global()->Equals(context2, global).FromJust());
}
}
isolate->Dispose();
......
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