Bug 1518202 - Add cross-process proxies for Location. r=bzbarsky

Differential Revision: https://phabricator.services.mozilla.com/D15848

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Peter Van der Beken 2019-02-28 18:23:15 +00:00
Родитель 959db43a2d
Коммит 41fde75dc8
8 изменённых файлов: 148 добавлений и 60 удалений

Просмотреть файл

@ -28,6 +28,7 @@
#include "nsContentUtils.h"
#include "nsScriptError.h"
#include "nsThreadUtils.h"
#include "xpcprivate.h"
namespace mozilla {
namespace dom {
@ -545,9 +546,35 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(BrowsingContext)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(BrowsingContext, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(BrowsingContext, Release)
class RemoteLocationProxy
: public RemoteObjectProxy<BrowsingContext::LocationProxy,
Location_Binding::sCrossOriginAttributes,
Location_Binding::sCrossOriginMethods> {
public:
typedef RemoteObjectProxy Base;
constexpr RemoteLocationProxy()
: RemoteObjectProxy(prototypes::id::Location) {}
};
static const RemoteLocationProxy sSingleton;
// Give RemoteLocationProxy 2 reserved slots, like the other wrappers,
// so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
// malloc.
template <>
const js::Class RemoteLocationProxy::Base::sClass =
PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
void BrowsingContext::Location(JSContext* aCx,
JS::MutableHandle<JSObject*> aLocation,
OOMReporter& aError) {}
ErrorResult& aError) {
aError.MightThrowJSException();
sSingleton.GetProxyObject(aCx, &mLocation, aLocation);
if (!aLocation) {
aError.StealExceptionFromJSContext(aCx);
}
}
void BrowsingContext::Close(CallerType aCallerType, ErrorResult& aError) {
// FIXME We need to set mClosed, but only once we're sending the
@ -671,6 +698,28 @@ void BrowsingContext::Transaction::Commit(BrowsingContext* aBrowsingContext) {
Apply(aBrowsingContext);
}
void BrowsingContext::LocationProxy::SetHref(const nsAString& aHref,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) {
nsPIDOMWindowOuter* win = GetBrowsingContext()->GetDOMWindow();
if (!win || !win->GetLocation()) {
aError.Throw(NS_ERROR_FAILURE);
return;
}
win->GetLocation()->SetHref(aHref, aSubjectPrincipal, aError);
}
void BrowsingContext::LocationProxy::Replace(const nsAString& aUrl,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) {
nsPIDOMWindowOuter* win = GetBrowsingContext()->GetDOMWindow();
if (!win || !win->GetLocation()) {
aError.Throw(NS_ERROR_FAILURE);
return;
}
win->GetLocation()->Replace(aUrl, aSubjectPrincipal, aError);
}
} // namespace dom
namespace ipc {

Просмотреть файл

@ -20,6 +20,7 @@
#include "nsWrapperCache.h"
class nsGlobalWindowOuter;
class nsIPrincipal;
class nsOuterWindowProxy;
class PickleIterator;
@ -31,7 +32,6 @@ namespace mozilla {
class ErrorResult;
class LogModule;
class OOMReporter;
namespace ipc {
class IProtocol;
@ -267,7 +267,7 @@ class BrowsingContext : public nsWrapperCache,
BrowsingContext* Window() { return Self(); }
BrowsingContext* Self() { return this; }
void Location(JSContext* aCx, JS::MutableHandle<JSObject*> aLocation,
OOMReporter& aError);
ErrorResult& aError);
void Close(CallerType aCallerType, ErrorResult& aError);
bool GetClosed(ErrorResult&) { return mClosed; }
void Focus(ErrorResult& aError);
@ -329,6 +329,33 @@ class BrowsingContext : public nsWrapperCache,
BrowsingContext* TopLevelBrowsingContext();
friend class Location;
friend class RemoteLocationProxy;
/**
* LocationProxy is the class for the native object stored as a private in a
* RemoteLocationProxy proxy representing a Location object in a different
* process. It forwards all operations to its BrowsingContext and aggregates
* its refcount to that BrowsingContext.
*/
class LocationProxy {
public:
MozExternalRefCountType AddRef() { return GetBrowsingContext()->AddRef(); }
MozExternalRefCountType Release() {
return GetBrowsingContext()->Release();
}
void SetHref(const nsAString& aHref, nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError);
void Replace(const nsAString& aUrl, nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError);
private:
BrowsingContext* GetBrowsingContext() {
return reinterpret_cast<BrowsingContext*>(
uintptr_t(this) - offsetof(BrowsingContext, mLocation));
}
};
// Type of BrowsingContent
const Type mType;
@ -345,6 +372,7 @@ class BrowsingContext : public nsWrapperCache,
// nsOuterWindowProxy handler, which will update the pointer from its
// objectMoved hook and clear it from its finalize hook.
JS::Heap<JSObject*> mWindowProxy;
LocationProxy mLocation;
// This flag is only valid in the top level browsing context, it indicates
// whether the corresponding document has been activated by user gesture.

Просмотреть файл

@ -108,6 +108,7 @@ LOCAL_INCLUDES += [
'/docshell/shistory',
'/dom/base',
'/dom/bindings',
'/js/xpconnect/src',
'/layout/base',
'/layout/generic',
'/layout/style',

Просмотреть файл

@ -29,7 +29,7 @@ namespace dom {
class Location final : public nsISupports, public nsWrapperCache {
public:
typedef Location RemoteProxy;
typedef BrowsingContext::LocationProxy RemoteProxy;
Location(nsPIDOMWindowInner* aWindow, nsIDocShell* aDocShell);

Просмотреть файл

@ -32,6 +32,8 @@ class RemoteOuterWindowProxy
Window_Binding::sCrossOriginAttributes,
Window_Binding::sCrossOriginMethods> {
public:
typedef RemoteObjectProxy Base;
constexpr RemoteOuterWindowProxy()
: RemoteObjectProxy(prototypes::id::Window) {}
@ -45,17 +47,15 @@ class RemoteOuterWindowProxy
// SpiderMonkey extensions
bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::AutoIdVector& props) const final;
void finalize(JSFreeOp* aFop, JSObject* aProxy) const final;
const char* className(JSContext* aCx,
JS::Handle<JSObject*> aProxy) const final;
};
static const RemoteOuterWindowProxy sSingleton;
// Give RemoteOuterWindowProxyClass 2 reserved slots, like the other wrappers,
// Give RemoteOuterWindowProxy 2 reserved slots, like the other wrappers,
// so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
// malloc.
const js::Class RemoteOuterWindowProxyClass =
template <>
const js::Class RemoteOuterWindowProxy::Base::sClass =
PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
@ -63,30 +63,8 @@ bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
MOZ_ASSERT(!aContext->GetDocShell(),
"Why are we creating a RemoteOuterWindowProxy?");
xpc::CompartmentPrivate* priv =
xpc::CompartmentPrivate::Get(JS::CurrentGlobalOrNull(aCx));
xpc::CompartmentPrivate::RemoteProxyMap& map = priv->GetRemoteProxyMap();
auto result = map.lookupForAdd(aContext);
if (result) {
aRetVal.set(result->value());
return true;
}
JS::Rooted<JSObject*> obj(
aCx, sSingleton.CreateProxyObject(aCx, aContext,
&RemoteOuterWindowProxyClass));
if (!obj) {
return false;
}
NS_ADDREF(aContext);
if (!map.add(result, aContext, obj)) {
JS_ReportOutOfMemory(aCx);
return false;
}
aRetVal.set(obj);
return true;
sSingleton.GetProxyObject(aCx, aContext, aRetVal);
return !!aRetVal;
}
static BrowsingContext* GetBrowsingContext(JSObject* aProxy) {
@ -177,17 +155,5 @@ bool RemoteOuterWindowProxy::getOwnEnumerablePropertyKeys(
return AppendIndexedPropertyNames(aCx, GetBrowsingContext(aProxy), aProps);
}
void RemoteOuterWindowProxy::finalize(JSFreeOp* aFop, JSObject* aProxy) const {
BrowsingContext* bc = GetBrowsingContext(aProxy);
RefPtr<BrowsingContext> self(dont_AddRef(bc));
}
const char* RemoteOuterWindowProxy::className(
JSContext* aCx, JS::Handle<JSObject*> aProxy) const {
MOZ_ASSERT(js::IsProxy(aProxy));
return "Object";
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -9132,7 +9132,6 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
# We'll use a JSObject. It might make more sense to use remoteType's
# RemoteProxy, but it's not easy to construct a type for that from here.
remoteType = BuiltinTypes[IDLBuiltinType.Types.object]
extendedAttributes.append('canOOM')
extendedAttributes.remove('infallible')
prototypeID, _ = PrototypeIDAndDepth(self.descriptor)
prefix = fill("""

Просмотреть файл

@ -11,12 +11,6 @@
namespace mozilla {
namespace dom {
// Give RemoteObjectProxy 2 reserved slots, like the other wrappers, so
// JSObject::swap can swap it with CrossCompartmentWrappers without requiring
// malloc.
const js::Class RemoteObjectProxyClass =
PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
bool RemoteObjectProxyBase::getOwnPropertyDescriptor(
JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc) const {
@ -169,12 +163,41 @@ bool RemoteObjectProxyBase::getOwnEnumerablePropertyKeys(
return true;
}
JSObject* RemoteObjectProxyBase::CreateProxyObject(
JSContext* aCx, void* aNative, const js::Class* aClasp) const {
const char* RemoteObjectProxyBase::className(
JSContext* aCx, JS::Handle<JSObject*> aProxy) const {
MOZ_ASSERT(js::IsProxy(aProxy));
return "Object";
}
void RemoteObjectProxyBase::GetOrCreateProxyObject(
JSContext* aCx, void* aNative, const js::Class* aClasp,
JS::MutableHandle<JSObject*> aProxy, bool& aNewObjectCreated) const {
xpc::CompartmentPrivate* priv =
xpc::CompartmentPrivate::Get(JS::CurrentGlobalOrNull(aCx));
xpc::CompartmentPrivate::RemoteProxyMap& map = priv->GetRemoteProxyMap();
auto result = map.lookupForAdd(aNative);
if (result) {
aProxy.set(result->value());
return;
}
js::ProxyOptions options;
options.setClass(aClasp);
JS::Rooted<JS::Value> native(aCx, JS::PrivateValue(aNative));
return js::NewProxyObject(aCx, this, native, nullptr, options);
JS::Rooted<JSObject*> obj(
aCx, js::NewProxyObject(aCx, this, native, nullptr, options));
if (!obj) {
return;
}
aNewObjectCreated = true;
if (!map.add(result, aNative, obj)) {
return;
}
aProxy.set(obj);
}
const char RemoteObjectProxyBase::sCrossOriginProxyFamily = 0;

Просмотреть файл

@ -70,6 +70,8 @@ class RemoteObjectProxyBase : public js::BaseProxyHandler,
bool getOwnEnumerablePropertyKeys(JSContext* aCx,
JS::Handle<JSObject*> aProxy,
JS::AutoIdVector& aProps) const override;
const char* className(JSContext* aCx,
JS::Handle<JSObject*> aProxy) const final;
bool isCallable(JSObject* aObj) const final { return false; }
bool isConstructor(JSObject* aObj) const final { return false; }
@ -101,8 +103,17 @@ class RemoteObjectProxyBase : public js::BaseProxyHandler,
}
protected:
JSObject* CreateProxyObject(JSContext* aCx, void* aNative,
const js::Class* aClasp) const;
/**
* Gets an existing cached proxy object, or creates a new one and caches it.
* aProxy will be null on failure. aNewObjectCreated is set to true if a new
* object was created, callers probably need to addref the native in that
* case. aNewObjectCreated can be true even if aProxy is null, if something
* failed after creating the object.
*/
void GetOrCreateProxyObject(JSContext* aCx, void* aNative,
const js::Class* aClasp,
JS::MutableHandle<JSObject*> aProxy,
bool& aNewObjectCreated) const;
const prototypes::ID mPrototypeID;
@ -126,9 +137,18 @@ class RemoteObjectProxyBase : public js::BaseProxyHandler,
template <class Native, JSPropertySpec* P, JSFunctionSpec* F>
class RemoteObjectProxy : public RemoteObjectProxyBase {
public:
JSObject* CreateProxyObject(JSContext* aCx, Native* aNative,
const js::Class* aClasp) const {
return RemoteObjectProxyBase::CreateProxyObject(aCx, aNative, aClasp);
void finalize(JSFreeOp* aFop, JSObject* aProxy) const final {
auto native = static_cast<Native*>(GetNative(aProxy));
RefPtr<Native> self(dont_AddRef(native));
}
void GetProxyObject(JSContext* aCx, Native* aNative,
JS::MutableHandle<JSObject*> aProxy) const {
bool objectCreated = false;
GetOrCreateProxyObject(aCx, aNative, &sClass, aProxy, objectCreated);
if (objectCreated) {
NS_ADDREF(aNative);
}
}
protected:
@ -140,6 +160,8 @@ class RemoteObjectProxy : public RemoteObjectProxyBase {
return MaybeCrossOriginObjectMixins::EnsureHolder(
aCx, aProxy, /* slot = */ 0, P, F, aHolder);
}
static const js::Class sClass;
};
/**