зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
959db43a2d
Коммит
41fde75dc8
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Загрузка…
Ссылка в новой задаче