[runtime] Mark old JSGlobalProxy's map as unstable when an iframe navigates away.

This CL also introduces Realm.navigate(i).

BUG=chromium:683667

Change-Id: I9227292ea3a575f34367e82fc6297d234d3eecae
Reviewed-on: https://chromium-review.googlesource.com/447638
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43494}
This commit is contained in:
Igor Sheludko 2017-02-28 17:38:04 +01:00 committed by Commit Bot
parent 497dff7809
commit 1c7f83980e
5 changed files with 69 additions and 21 deletions

View File

@ -857,20 +857,24 @@ void Shell::RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
} }
MaybeLocal<Context> Shell::CreateRealm( MaybeLocal<Context> Shell::CreateRealm(
const v8::FunctionCallbackInfo<v8::Value>& args) { const v8::FunctionCallbackInfo<v8::Value>& args, int index,
v8::MaybeLocal<Value> global_object) {
Isolate* isolate = args.GetIsolate(); Isolate* isolate = args.GetIsolate();
TryCatch try_catch(isolate); TryCatch try_catch(isolate);
PerIsolateData* data = PerIsolateData::Get(isolate); PerIsolateData* data = PerIsolateData::Get(isolate);
if (index < 0) {
Global<Context>* old_realms = data->realms_; Global<Context>* old_realms = data->realms_;
int index = data->realm_count_; index = data->realm_count_;
data->realms_ = new Global<Context>[++data->realm_count_]; data->realms_ = new Global<Context>[++data->realm_count_];
for (int i = 0; i < index; ++i) { for (int i = 0; i < index; ++i) {
data->realms_[i].Reset(isolate, old_realms[i]); data->realms_[i].Reset(isolate, old_realms[i]);
old_realms[i].Reset(); old_realms[i].Reset();
} }
delete[] old_realms; delete[] old_realms;
}
Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate); Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
Local<Context> context = Context::New(isolate, NULL, global_template); Local<Context> context =
Context::New(isolate, NULL, global_template, global_object);
if (context.IsEmpty()) { if (context.IsEmpty()) {
DCHECK(try_catch.HasCaught()); DCHECK(try_catch.HasCaught());
try_catch.ReThrow(); try_catch.ReThrow();
@ -882,10 +886,20 @@ MaybeLocal<Context> Shell::CreateRealm(
return context; return context;
} }
void Shell::DisposeRealm(const v8::FunctionCallbackInfo<v8::Value>& args,
int index) {
Isolate* isolate = args.GetIsolate();
PerIsolateData* data = PerIsolateData::Get(isolate);
DisposeModuleEmbedderData(data->realms_[index].Get(isolate));
data->realms_[index].Reset();
isolate->ContextDisposedNotification();
isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime());
}
// Realm.create() creates a new realm with a distinct security token // Realm.create() creates a new realm with a distinct security token
// and returns its index. // and returns its index.
void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) { void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
CreateRealm(args); CreateRealm(args, -1, v8::MaybeLocal<Value>());
} }
// Realm.createAllowCrossRealmAccess() creates a new realm with the same // Realm.createAllowCrossRealmAccess() creates a new realm with the same
@ -893,12 +907,26 @@ void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
void Shell::RealmCreateAllowCrossRealmAccess( void Shell::RealmCreateAllowCrossRealmAccess(
const v8::FunctionCallbackInfo<v8::Value>& args) { const v8::FunctionCallbackInfo<v8::Value>& args) {
Local<Context> context; Local<Context> context;
if (CreateRealm(args).ToLocal(&context)) { if (CreateRealm(args, -1, v8::MaybeLocal<Value>()).ToLocal(&context)) {
context->SetSecurityToken( context->SetSecurityToken(
args.GetIsolate()->GetEnteredContext()->GetSecurityToken()); args.GetIsolate()->GetEnteredContext()->GetSecurityToken());
} }
} }
// Realm.navigate(i) creates a new realm with a distinct security token
// in place of realm i.
void Shell::RealmNavigate(const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
PerIsolateData* data = PerIsolateData::Get(isolate);
int index = data->RealmIndexOrThrow(args, 0);
if (index == -1) return;
Local<Context> context = Local<Context>::New(isolate, data->realms_[index]);
v8::MaybeLocal<Value> global_object = context->Global();
DisposeRealm(args, index);
CreateRealm(args, index, global_object);
}
// Realm.dispose(i) disposes the reference to the realm i. // Realm.dispose(i) disposes the reference to the realm i.
void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) { void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate(); Isolate* isolate = args.GetIsolate();
@ -910,10 +938,7 @@ void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
Throw(args.GetIsolate(), "Invalid realm index"); Throw(args.GetIsolate(), "Invalid realm index");
return; return;
} }
DisposeModuleEmbedderData(data->realms_[index].Get(isolate)); DisposeRealm(args, index);
data->realms_[index].Reset();
isolate->ContextDisposedNotification();
isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime());
} }
@ -1480,6 +1505,10 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
NewStringType::kNormal) NewStringType::kNormal)
.ToLocalChecked(), .ToLocalChecked(),
FunctionTemplate::New(isolate, RealmCreateAllowCrossRealmAccess)); FunctionTemplate::New(isolate, RealmCreateAllowCrossRealmAccess));
realm_template->Set(
String::NewFromUtf8(isolate, "navigate", NewStringType::kNormal)
.ToLocalChecked(),
FunctionTemplate::New(isolate, RealmNavigate));
realm_template->Set( realm_template->Set(
String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal) String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal)
.ToLocalChecked(), .ToLocalChecked(),

View File

@ -377,6 +377,7 @@ class Shell : public i::AllStatic {
static void RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args); static void RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args);
static void RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args); static void RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args);
static void RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args); static void RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void RealmNavigate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void RealmCreateAllowCrossRealmAccess( static void RealmCreateAllowCrossRealmAccess(
const v8::FunctionCallbackInfo<v8::Value>& args); const v8::FunctionCallbackInfo<v8::Value>& args);
static void RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args); static void RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args);
@ -475,7 +476,10 @@ class Shell : public i::AllStatic {
static bool SetOptions(int argc, char* argv[]); static bool SetOptions(int argc, char* argv[]);
static Local<ObjectTemplate> CreateGlobalTemplate(Isolate* isolate); static Local<ObjectTemplate> CreateGlobalTemplate(Isolate* isolate);
static MaybeLocal<Context> CreateRealm( static MaybeLocal<Context> CreateRealm(
const v8::FunctionCallbackInfo<v8::Value>& args); const v8::FunctionCallbackInfo<v8::Value>& args, int index,
v8::MaybeLocal<Value> global_object);
static void DisposeRealm(const v8::FunctionCallbackInfo<v8::Value>& args,
int index);
static MaybeLocal<Module> FetchModuleTree(v8::Local<v8::Context> context, static MaybeLocal<Module> FetchModuleTree(v8::Local<v8::Context> context,
const std::string& file_name); const std::string& file_name);
}; };

View File

@ -2330,6 +2330,7 @@ void Factory::ReinitializeJSGlobalProxy(Handle<JSGlobalProxy> object,
map->set_is_prototype_map(true); map->set_is_prototype_map(true);
} }
JSObject::NotifyMapChange(old_map, map, isolate()); JSObject::NotifyMapChange(old_map, map, isolate());
old_map->NotifyLeafMapLayoutChange();
// Check that the already allocated object has the same size and type as // Check that the already allocated object has the same size and type as
// objects allocated using the constructor. // objects allocated using the constructor.

View File

@ -6270,6 +6270,11 @@ class Map: public HeapObject {
Handle<Map> split_map, Handle<DescriptorArray> descriptors, Handle<Map> split_map, Handle<DescriptorArray> descriptors,
Handle<LayoutDescriptor> full_layout_descriptor); Handle<LayoutDescriptor> full_layout_descriptor);
// Fires when the layout of an object with a leaf map changes.
// This includes adding transitions to the leaf map or changing
// the descriptor array.
inline void NotifyLeafMapLayoutChange();
private: private:
// Returns the map that this (root) map transitions to if its elements_kind // Returns the map that this (root) map transitions to if its elements_kind
// is changed to |elements_kind|, or |nullptr| if no such map is cached yet. // is changed to |elements_kind|, or |nullptr| if no such map is cached yet.
@ -6323,11 +6328,6 @@ class Map: public HeapObject {
Handle<Map> map, ElementsKind elements_kind, int modify_index, Handle<Map> map, ElementsKind elements_kind, int modify_index,
PropertyKind kind, PropertyAttributes attributes, const char* reason); PropertyKind kind, PropertyAttributes attributes, const char* reason);
// Fires when the layout of an object with a leaf map changes.
// This includes adding transitions to the leaf map or changing
// the descriptor array.
inline void NotifyLeafMapLayoutChange();
void DeprecateTransitionTree(); void DeprecateTransitionTree();
void ReplaceDescriptors(DescriptorArray* new_descriptors, void ReplaceDescriptors(DescriptorArray* new_descriptors,

View File

@ -0,0 +1,14 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-gc --verify-heap
var realm = Realm.create();
var g = Realm.global(realm);
var obj = {x: 0, g: g};
// Navigation will replace JSGlobalObject behind the JSGlobalProxy g and
// therefore will change the g's map. The old map must be marked as non-stable.
Realm.navigate(realm);
gc();