Correctly reference global proxy in the partial snapshot.

R=verwaest@chromium.org

Review URL: https://codereview.chromium.org/853493003

Cr-Commit-Position: refs/heads/master@{#26061}
This commit is contained in:
yangguo 2015-01-14 08:42:15 -08:00 committed by Commit bot
parent 2ebe24c9cb
commit fe82e03bb6
9 changed files with 117 additions and 69 deletions

View File

@ -183,16 +183,15 @@ class Genesis BASE_EMBEDDED {
// Make the "arguments" and "caller" properties throw a TypeError on access.
void PoisonArgumentsAndCaller(Handle<Map> map);
// Creates the global objects using the global and the template passed in
// through the API. We call this regardless of whether we are building a
// Creates the global objects using the global proxy and the template passed
// 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.
Handle<JSGlobalProxy> CreateNewGlobals(
Handle<GlobalObject> CreateNewGlobals(
v8::Handle<v8::ObjectTemplate> global_proxy_template,
MaybeHandle<JSGlobalProxy> maybe_global_proxy,
Handle<GlobalObject>* global_object_out);
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.
@ -757,14 +756,13 @@ void Genesis::CreateRoots() {
}
Handle<JSGlobalProxy> Genesis::CreateNewGlobals(
Handle<GlobalObject> Genesis::CreateNewGlobals(
v8::Handle<v8::ObjectTemplate> global_proxy_template,
MaybeHandle<JSGlobalProxy> maybe_global_proxy,
Handle<GlobalObject>* global_object_out) {
Handle<JSGlobalProxy> global_proxy) {
// The argument global_proxy_template aka data is an ObjectTemplateInfo.
// It has a constructor pointer that points at global_constructor which is a
// FunctionTemplateInfo.
// The global_proxy_constructor is used to create or reinitialize the
// The global_proxy_constructor is used to (re)initialize the
// global_proxy. The global_proxy_constructor also has a prototype_template
// pointer that points at js_global_object_template which is an
// ObjectTemplateInfo.
@ -820,11 +818,8 @@ Handle<JSGlobalProxy> Genesis::CreateNewGlobals(
js_global_object_function->initial_map()->set_dictionary_map(true);
Handle<GlobalObject> global_object =
factory()->NewGlobalObject(js_global_object_function);
if (global_object_out != NULL) {
*global_object_out = global_object;
}
// Step 2: create or re-initialize the global proxy object.
// Step 2: (re)initialize the global proxy object.
Handle<JSFunction> global_proxy_function;
if (global_proxy_template.IsEmpty()) {
Handle<String> name = Handle<String>(heap()->empty_string());
@ -850,15 +845,8 @@ Handle<JSGlobalProxy> Genesis::CreateNewGlobals(
// Set global_proxy.__proto__ to js_global after ConfigureGlobalObjects
// Return the global proxy.
Handle<JSGlobalProxy> global_proxy;
if (maybe_global_proxy.ToHandle(&global_proxy)) {
factory()->ReinitializeJSGlobalProxy(global_proxy, global_proxy_function);
} else {
global_proxy = Handle<JSGlobalProxy>::cast(
factory()->NewJSObject(global_proxy_function, TENURED));
global_proxy->set_hash(heap()->undefined_value());
}
return global_proxy;
factory()->ReinitializeJSGlobalProxy(global_proxy, global_proxy_function);
return global_object;
}
@ -868,6 +856,10 @@ void Genesis::HookUpGlobalProxy(Handle<GlobalObject> global_object,
global_object->set_native_context(*native_context());
global_object->set_global_proxy(*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.
DCHECK(native_context()->get(Context::GLOBAL_PROXY_INDEX)->IsUndefined() ||
native_context()->global_proxy() == *global_proxy);
native_context()->set_global_proxy(*global_proxy);
}
@ -2736,11 +2728,20 @@ Genesis::Genesis(Isolate* isolate,
StackLimitCheck check(isolate);
if (check.HasOverflowed()) return;
// The deserializer needs to hook up references to the global proxy.
// 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)) {
global_proxy = isolate->factory()->NewUninitializedJSGlobalProxy();
}
// We can only de-serialize a context if the isolate was initialized from
// a snapshot. Otherwise we have to build the context from scratch.
Handle<FixedArray> outdated_contexts;
if (!isolate->initialized_from_snapshot() ||
!Snapshot::NewContextFromSnapshot(isolate, &outdated_contexts)
!Snapshot::NewContextFromSnapshot(isolate, global_proxy,
&outdated_contexts)
.ToHandle(&native_context_)) {
native_context_ = Handle<Context>();
}
@ -2758,9 +2759,8 @@ Genesis::Genesis(Isolate* isolate,
Map::TraceAllTransitions(object_fun->initial_map());
}
#endif
Handle<GlobalObject> global_object;
Handle<JSGlobalProxy> global_proxy = CreateNewGlobals(
global_proxy_template, maybe_global_proxy, &global_object);
Handle<GlobalObject> global_object =
CreateNewGlobals(global_proxy_template, global_proxy);
HookUpGlobalProxy(global_object, global_proxy);
HookUpGlobalObject(global_object, outdated_contexts);
@ -2773,9 +2773,8 @@ Genesis::Genesis(Isolate* isolate,
CreateRoots();
Handle<JSFunction> empty_function = CreateEmptyFunction(isolate);
CreateStrictModeFunctionMaps(empty_function);
Handle<GlobalObject> global_object;
Handle<JSGlobalProxy> global_proxy = CreateNewGlobals(
global_proxy_template, maybe_global_proxy, &global_object);
Handle<GlobalObject> global_object =
CreateNewGlobals(global_proxy_template, global_proxy);
HookUpGlobalProxy(global_object, global_proxy);
InitializeGlobal(global_object, empty_function);
InstallJSFunctionResultCaches();

View File

@ -1958,6 +1958,18 @@ void Factory::ReinitializeJSProxy(Handle<JSProxy> proxy, InstanceType type,
}
Handle<JSGlobalProxy> Factory::NewUninitializedJSGlobalProxy() {
// Create an empty shell of a JSGlobalProxy that needs to be reinitialized
// via ReinitializeJSGlobalProxy later.
Handle<Map> map = NewMap(JS_GLOBAL_PROXY_TYPE, JSGlobalProxy::kSize);
// Maintain invariant expected from any JSGlobalProxy.
map->set_is_access_check_needed(true);
CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->AllocateJSObjectFromMap(
*map, NOT_TENURED, false),
JSGlobalProxy);
}
void Factory::ReinitializeJSGlobalProxy(Handle<JSGlobalProxy> object,
Handle<JSFunction> constructor) {
DCHECK(constructor->has_initial_map());

View File

@ -465,6 +465,8 @@ class Factory FINAL {
void ReinitializeJSGlobalProxy(Handle<JSGlobalProxy> global,
Handle<JSFunction> constructor);
Handle<JSGlobalProxy> NewUninitializedJSGlobalProxy();
// Change the type of the argument into a JS object/function and reinitialize.
void BecomeJSObject(Handle<JSProxy> object);
void BecomeJSFunction(Handle<JSProxy> object);

View File

@ -567,7 +567,6 @@ void JSGlobalProxy::JSGlobalProxyVerify() {
VerifyObjectField(JSGlobalProxy::kNativeContextOffset);
// Make sure that this object has no properties, elements.
CHECK_EQ(0, properties()->length());
CHECK_EQ(FAST_HOLEY_SMI_ELEMENTS, GetElementsKind());
CHECK_EQ(0, FixedArray::cast(elements())->length());
}

View File

@ -700,13 +700,18 @@ void Deserializer::Deserialize(Isolate* isolate) {
MaybeHandle<Object> Deserializer::DeserializePartial(
Isolate* isolate, Handle<FixedArray>* outdated_contexts_out) {
Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
Handle<FixedArray>* outdated_contexts_out) {
Initialize(isolate);
if (!ReserveSpace()) {
FatalProcessOutOfMemory("deserialize context");
return MaybeHandle<Object>();
}
Vector<Handle<Object> > attached_objects = Vector<Handle<Object> >::New(1);
attached_objects[kGlobalProxyReference] = global_proxy;
SetAttachedObjects(attached_objects);
DisallowHeapAllocation no_gc;
// Keep track of the code space start and end pointers in case new
// code objects were unserialized
@ -734,6 +739,7 @@ MaybeHandle<SharedFunctionInfo> Deserializer::DeserializeCode(
if (!ReserveSpace()) {
return Handle<SharedFunctionInfo>();
} else {
deserializing_user_code_ = true;
DisallowHeapAllocation no_gc;
Object* root;
VisitPointer(&root);
@ -749,7 +755,7 @@ Deserializer::~Deserializer() {
delete external_reference_decoder_;
external_reference_decoder_ = NULL;
}
if (attached_objects_) attached_objects_->Dispose();
attached_objects_.Dispose();
}
@ -997,9 +1003,9 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
new_object = isolate->builtins()->builtin(name); \
emit_write_barrier = false; \
} else if (where == kAttachedReference) { \
DCHECK(deserializing_user_code()); \
int index = source_.GetInt(); \
new_object = *attached_objects_->at(index); \
DCHECK(deserializing_user_code() || index == kGlobalProxyReference); \
new_object = *attached_objects_[index]; \
emit_write_barrier = isolate->heap()->InNewSpace(new_object); \
} else { \
DCHECK(where == kBackrefWithSkip); \
@ -1396,7 +1402,11 @@ void StartupSerializer::VisitPointers(Object** start, Object** end) {
void PartialSerializer::Serialize(Object** o) {
if ((*o)->IsContext()) global_object_ = Context::cast(*o)->global_object();
if ((*o)->IsContext()) {
Context* context = Context::cast(*o);
global_object_ = context->global_object();
global_proxy_ = context->global_proxy();
}
VisitPointer(o);
SerializeOutdatedContextsAsFixedArray();
Pad();
@ -1683,6 +1693,14 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
FlushSkip(skip);
if (obj == global_proxy_) {
FlushSkip(skip);
DCHECK(how_to_code == kPlain && where_to_point == kStartOfObject);
sink_->Put(kAttachedReference + how_to_code + where_to_point, "Reference");
sink_->PutInt(kGlobalProxyReference, "kGlobalProxyReferenceIndex");
return;
}
// Object has not yet been serialized. Serialize it here.
ObjectSerializer serializer(this, obj, sink_, how_to_code, where_to_point);
serializer.Serialize();
@ -2323,16 +2341,6 @@ int CodeSerializer::AddCodeStubKey(uint32_t stub_key) {
}
void CodeSerializer::SerializeSourceObject(HowToCode how_to_code,
WhereToPoint where_to_point) {
if (FLAG_trace_serializer) PrintF(" Encoding source object\n");
DCHECK(how_to_code == kPlain && where_to_point == kStartOfObject);
sink_->Put(kAttachedReference + how_to_code + where_to_point, "Source");
sink_->PutInt(kSourceObjectIndex, "kSourceObjectIndex");
}
MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
Isolate* isolate, ScriptData* cached_data, Handle<String> source) {
base::ElapsedTimer timer;
@ -2363,7 +2371,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
}
Deserializer deserializer(scd.get());
deserializer.SetAttachedObjects(&attached_objects);
deserializer.SetAttachedObjects(attached_objects);
// Deserialize.
Handle<SharedFunctionInfo> result;

View File

@ -449,6 +449,9 @@ class SerializerDeserializer: public ObjectVisitor {
// Used as index for the attached reference representing the source object.
static const int kSourceObjectReference = 0;
// Used as index for the attached reference representing the global proxy.
static const int kGlobalProxyReference = 0;
HotObjectsList hot_objects_;
};
@ -506,10 +509,10 @@ class Deserializer: public SerializerDeserializer {
template <class Data>
explicit Deserializer(Data* data)
: isolate_(NULL),
attached_objects_(NULL),
source_(data->Payload()),
external_reference_decoder_(NULL),
deserialized_large_objects_(0) {
deserialized_large_objects_(0),
deserializing_user_code_(false) {
DecodeReservation(data->Reservations());
}
@ -519,22 +522,21 @@ class Deserializer: public SerializerDeserializer {
void Deserialize(Isolate* isolate);
// Deserialize a single object and the objects reachable from it.
// We may want to abort gracefully even if deserialization fails.
MaybeHandle<Object> DeserializePartial(
Isolate* isolate, Handle<FixedArray>* outdated_contexts_out);
Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
Handle<FixedArray>* outdated_contexts_out);
// Deserialize a shared function info. Fail gracefully.
MaybeHandle<SharedFunctionInfo> DeserializeCode(Isolate* isolate);
void FlushICacheForNewCodeObjects();
// Serialized user code reference certain objects that are provided in a list
// By calling this method, we assume that we are deserializing user code.
void SetAttachedObjects(Vector<Handle<Object> >* attached_objects) {
// Pass a vector of externally-provided objects referenced by the snapshot.
// The ownership to its backing store is handed over as well.
void SetAttachedObjects(Vector<Handle<Object> > attached_objects) {
attached_objects_ = attached_objects;
}
bool deserializing_user_code() { return attached_objects_ != NULL; }
private:
virtual void VisitPointers(Object** start, Object** end);
@ -544,6 +546,8 @@ class Deserializer: public SerializerDeserializer {
void Initialize(Isolate* isolate);
bool deserializing_user_code() { return deserializing_user_code_; }
void DecodeReservation(Vector<const SerializedData::Reservation> res);
bool ReserveSpace();
@ -577,7 +581,7 @@ class Deserializer: public SerializerDeserializer {
Isolate* isolate_;
// Objects from the attached object descriptions in the serialized user code.
Vector<Handle<Object> >* attached_objects_;
Vector<Handle<Object> > attached_objects_;
SnapshotByteSource source_;
// The address of the next object that will be allocated in each space.
@ -592,6 +596,8 @@ class Deserializer: public SerializerDeserializer {
List<HeapObject*> deserialized_large_objects_;
bool deserializing_user_code_;
DISALLOW_COPY_AND_ASSIGN(Deserializer);
};
@ -745,7 +751,8 @@ class PartialSerializer : public Serializer {
: Serializer(isolate, sink),
startup_serializer_(startup_snapshot_serializer),
outdated_contexts_(0),
global_object_(NULL) {
global_object_(NULL),
global_proxy_(NULL) {
InitializeCodeAddressMap();
}
@ -774,6 +781,7 @@ class PartialSerializer : public Serializer {
Serializer* startup_serializer_;
List<BackReference> outdated_contexts_;
Object* global_object_;
Object* global_proxy_;
DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
};
@ -855,8 +863,6 @@ class CodeSerializer : public Serializer {
WhereToPoint where_to_point);
void SerializeCodeStub(uint32_t stub_key, HowToCode how_to_code,
WhereToPoint where_to_point);
void SerializeSourceObject(HowToCode how_to_code,
WhereToPoint where_to_point);
void SerializeGeneric(HeapObject* heap_object, HowToCode how_to_code,
WhereToPoint where_to_point);
int AddCodeStubKey(uint32_t stub_key);

View File

@ -54,7 +54,8 @@ bool Snapshot::Initialize(Isolate* isolate) {
MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
Isolate* isolate, Handle<FixedArray>* outdated_contexts_out) {
Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
Handle<FixedArray>* outdated_contexts_out) {
if (!HaveASnapshotToStartFrom()) return Handle<Context>();
base::ElapsedTimer timer;
if (FLAG_profile_deserialization) timer.Start();
@ -64,8 +65,8 @@ MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
SnapshotData snapshot_data(context_data);
Deserializer deserializer(&snapshot_data);
MaybeHandle<Object> maybe_context =
deserializer.DeserializePartial(isolate, outdated_contexts_out);
MaybeHandle<Object> maybe_context = deserializer.DeserializePartial(
isolate, global_proxy, outdated_contexts_out);
Handle<Object> result;
if (!maybe_context.ToHandle(&result)) return MaybeHandle<Context>();
CHECK(result->IsContext());

View File

@ -32,7 +32,8 @@ class Snapshot : public AllStatic {
static bool Initialize(Isolate* isolate);
// Create a new context using the internal partial snapshot.
static MaybeHandle<Context> NewContextFromSnapshot(
Isolate* isolate, Handle<FixedArray>* outdated_contexts_out);
Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
Handle<FixedArray>* outdated_contexts_out);
static bool HaveASnapshotToStartFrom();

View File

@ -394,10 +394,14 @@ UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
HandleScope handle_scope(isolate);
Handle<Object> root;
Handle<FixedArray> outdated_contexts;
// Intentionally empty handle. The deserializer should not come across
// any references to the global proxy in this test.
Handle<JSGlobalProxy> global_proxy = Handle<JSGlobalProxy>::null();
{
SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
Deserializer deserializer(&snapshot_data);
root = deserializer.DeserializePartial(isolate, &outdated_contexts)
root = deserializer.DeserializePartial(isolate, global_proxy,
&outdated_contexts)
.ToHandleChecked();
CHECK_EQ(0, outdated_contexts->length());
CHECK(root->IsString());
@ -407,7 +411,8 @@ UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
{
SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
Deserializer deserializer(&snapshot_data);
root2 = deserializer.DeserializePartial(isolate, &outdated_contexts)
root2 = deserializer.DeserializePartial(isolate, global_proxy,
&outdated_contexts)
.ToHandleChecked();
CHECK(root2->IsString());
CHECK(root.is_identical_to(root2));
@ -506,12 +511,16 @@ UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization, ContextSerialization) {
HandleScope handle_scope(isolate);
Handle<Object> root;
Handle<FixedArray> outdated_contexts;
Handle<JSGlobalProxy> global_proxy =
isolate->factory()->NewUninitializedJSGlobalProxy();
{
SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
Deserializer deserializer(&snapshot_data);
root = deserializer.DeserializePartial(isolate, &outdated_contexts)
root = deserializer.DeserializePartial(isolate, global_proxy,
&outdated_contexts)
.ToHandleChecked();
CHECK(root->IsContext());
CHECK(Handle<Context>::cast(root)->global_proxy() == *global_proxy);
CHECK_EQ(1, outdated_contexts->length());
}
@ -519,7 +528,8 @@ UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization, ContextSerialization) {
{
SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
Deserializer deserializer(&snapshot_data);
root2 = deserializer.DeserializePartial(isolate, &outdated_contexts)
root2 = deserializer.DeserializePartial(isolate, global_proxy,
&outdated_contexts)
.ToHandleChecked();
CHECK(root2->IsContext());
CHECK(!root.is_identical_to(root2));
@ -554,7 +564,8 @@ UNINITIALIZED_TEST(CustomContextSerialization) {
"var e;"
"(function() {"
" e = function(s) { eval (s); }"
"})();");
"})();"
"var o = this;");
}
// Make sure all builtin scripts are cached.
{
@ -625,13 +636,22 @@ UNINITIALIZED_DEPENDENT_TEST(CustomContextDeSerialization,
HandleScope handle_scope(isolate);
Handle<Object> root;
Handle<FixedArray> outdated_contexts;
Handle<JSGlobalProxy> global_proxy =
isolate->factory()->NewUninitializedJSGlobalProxy();
{
SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
Deserializer deserializer(&snapshot_data);
root = deserializer.DeserializePartial(isolate, &outdated_contexts)
root = deserializer.DeserializePartial(isolate, global_proxy,
&outdated_contexts)
.ToHandleChecked();
CHECK_EQ(2, outdated_contexts->length());
CHECK(root->IsContext());
Handle<Context> context = Handle<Context>::cast(root);
CHECK(context->global_proxy() == *global_proxy);
Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o");
Handle<JSObject> global_object(context->global_object(), isolate);
Handle<Object> property = JSObject::GetDataProperty(global_object, o);
CHECK(property.is_identical_to(global_proxy));
}
}
v8_isolate->Dispose();