author | Nika Layzell <nika@thelayzells.com> |
Wed, 08 Jul 2020 14:22:22 +0000 | |
changeset 539396 | d3c935827ef7694b50f5b2d9fc2665d27f9c27c2 |
parent 539395 | 0ad359f8308b0c853822d9033276a80827e7df47 |
child 539397 | d7810f45f0cbbf63ec61112e4d5c16433640775b |
push id | 121100 |
push user | nlayzell@mozilla.com |
push date | Wed, 08 Jul 2020 16:43:08 +0000 |
treeherder | autoland@5907260fa468 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | kmag |
bugs | 1649477 |
milestone | 80.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -2148,23 +2148,17 @@ void ContentChild::ActorDestroy(ActorDes #ifndef NS_FREE_PERMANENT_DATA // In release builds, there's no point in the content process // going through the full XPCOM shutdown path, because it doesn't // keep persistent state. ProcessChild::QuickExit(); #else // Destroy our JSProcessActors, and reject any pending queries. - nsRefPtrHashtable<nsCStringHashKey, JSProcessActorChild> processActors; - mProcessActors.SwapElements(processActors); - for (auto iter = processActors.Iter(); !iter.Done(); iter.Next()) { - iter.Data()->RejectPendingQueries(); - iter.Data()->AfterDestroy(); - } - mProcessActors.Clear(); + JSActorDidDestroy(); # if defined(XP_WIN) RefPtr<DllServices> dllSvc(DllServices::Get()); dllSvc->DisableFull(); # endif // defined(XP_WIN) if (gFirstIdleTask) { gFirstIdleTask->Cancel(); @@ -4266,48 +4260,42 @@ mozilla::ipc::IPCResult ContentChild::Re NS_IMETHODIMP ContentChild::GetChildID(uint64_t* aOut) { *aOut = mID; return NS_OK; } NS_IMETHODIMP ContentChild::GetActor(const nsACString& aName, JSProcessActorChild** retval) { - if (!CanSend()) { - return NS_ERROR_DOM_INVALID_STATE_ERR; - } - - // Check if this actor has already been created, and return it if it has. - if (mProcessActors.Contains(aName)) { - RefPtr<JSProcessActorChild> actor(mProcessActors.Get(aName)); - actor.forget(retval); - return NS_OK; - } - - // Otherwise, we want to create a new instance of this actor. - JS::RootedObject obj(RootingCx()); - ErrorResult result; - ConstructActor(aName, &obj, result); - if (result.Failed()) { - return result.StealNSResult(); - } - - // Unwrap our actor to a JSProcessActorChild object. + ErrorResult error; + RefPtr<JSProcessActorChild> actor = + JSActorManager::GetActor(aName, error).downcast<JSProcessActorChild>(); + if (error.Failed()) { + return error.StealNSResult(); + } + actor.forget(retval); + return NS_OK; +} + +already_AddRefed<JSActor> ContentChild::InitJSActor( + JS::HandleObject aMaybeActor, const nsACString& aName, ErrorResult& aRv) { RefPtr<JSProcessActorChild> actor; - nsresult rv = UNWRAP_OBJECT(JSProcessActorChild, &obj, actor); - if (NS_FAILED(rv)) { - return rv; + if (aMaybeActor.get()) { + aRv = UNWRAP_OBJECT(JSProcessActorChild, aMaybeActor.get(), actor); + if (aRv.Failed()) { + return nullptr; + } + } else { + actor = new JSProcessActorChild(); } MOZ_RELEASE_ASSERT(!actor->Manager(), "mManager was already initialized once!"); actor->Init(aName, this); - mProcessActors.Put(aName, RefPtr{actor}); - actor.forget(retval); - return NS_OK; + return actor.forget(); } IPCResult ContentChild::RecvRawMessage(const JSActorMessageMeta& aMeta, const ClonedMessageData& aData, const ClonedMessageData& aStack) { RefPtr<JSProcessActorChild> actor; GetActor(aMeta.actorName(), getter_AddRefs(actor)); if (actor) {
--- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -797,17 +797,20 @@ class ContentChild final : public PConte mozilla::ipc::IPCResult RecvStopLoad( const MaybeDiscarded<BrowsingContext>& aContext, const uint32_t aStopFlags); mozilla::ipc::IPCResult RecvRawMessage(const JSActorMessageMeta& aMeta, const ClonedMessageData& aData, const ClonedMessageData& aStack); - JSActor::Type GetSide() override { return JSActor::Type::Child; } + already_AddRefed<JSActor> InitJSActor(JS::HandleObject aMaybeActor, + const nsACString& aName, + ErrorResult& aRv) override; + mozilla::ipc::IProtocol* AsNativeActor() override { return this; } mozilla::ipc::IPCResult RecvHistoryCommitLength( const MaybeDiscarded<BrowsingContext>& aContext, uint32_t aLength); mozilla::ipc::IPCResult RecvFlushFOGData(FlushFOGDataResolver&& aResolver); private: #ifdef NIGHTLY_BUILD @@ -897,21 +900,16 @@ class ContentChild final : public PConte // off-main-thread. mozilla::Atomic<uint32_t> mPendingInputEvents; #endif uint32_t mNetworkLinkType = 0; // See `BrowsingContext::mEpochs` for an explanation of this field. uint64_t mBrowsingContextFieldEpoch = 0; - - nsRefPtrHashtable<nsCStringHashKey, JSProcessActorChild> mProcessActors; - ContentChild(const ContentChild&) = delete; - - const ContentChild& operator=(const ContentChild&) = delete; }; inline nsISupports* ToSupports(mozilla::dom::ContentChild* aContentChild) { return static_cast<nsIDOMProcessChild*>(aContentChild); } } // namespace dom } // namespace mozilla
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1828,23 +1828,17 @@ void ContentParent::ActorDestroy(ActorDe gpu->RemoveListener(this); } RecvRemoveGeolocationListener(); mConsoleService = nullptr; // Destroy our JSProcessActors, and reject any pending queries. - nsRefPtrHashtable<nsCStringHashKey, JSProcessActorParent> processActors; - mProcessActors.SwapElements(processActors); - for (auto iter = processActors.Iter(); !iter.Done(); iter.Next()) { - iter.Data()->RejectPendingQueries(); - iter.Data()->AfterDestroy(); - } - mProcessActors.Clear(); + JSActorDidDestroy(); if (obs) { RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag(); props->SetPropertyAsUint64(u"childID"_ns, mChildID); if (AbnormalShutdown == why) { Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, "content"_ns, @@ -6870,48 +6864,42 @@ IPCResult ContentParent::RecvRawMessage( stack.BorrowFromClonedMessageDataForParent(aStack); actor->ReceiveRawMessage(aMeta, std::move(data), std::move(stack)); } return IPC_OK(); } NS_IMETHODIMP ContentParent::GetActor(const nsACString& aName, JSProcessActorParent** retval) { - if (!CanSend()) { - return NS_ERROR_DOM_INVALID_STATE_ERR; - } - - // Check if this actor has already been created, and return it if it has. - if (mProcessActors.Contains(aName)) { - RefPtr<JSProcessActorParent> actor(mProcessActors.Get(aName)); - actor.forget(retval); - return NS_OK; - } - - // Otherwise, we want to create a new instance of this actor. - JS::RootedObject obj(RootingCx()); - ErrorResult result; - ConstructActor(aName, &obj, result); - if (result.Failed()) { - return result.StealNSResult(); - } - - // Unwrap our actor to a JSProcessActorParent object. + ErrorResult error; + RefPtr<JSProcessActorParent> actor = + JSActorManager::GetActor(aName, error).downcast<JSProcessActorParent>(); + if (error.Failed()) { + return error.StealNSResult(); + } + actor.forget(retval); + return NS_OK; +} + +already_AddRefed<JSActor> ContentParent::InitJSActor( + JS::HandleObject aMaybeActor, const nsACString& aName, ErrorResult& aRv) { RefPtr<JSProcessActorParent> actor; - nsresult rv = UNWRAP_OBJECT(JSProcessActorParent, &obj, actor); - if (NS_FAILED(rv)) { - return rv; + if (aMaybeActor.get()) { + aRv = UNWRAP_OBJECT(JSProcessActorParent, aMaybeActor.get(), actor); + if (aRv.Failed()) { + return nullptr; + } + } else { + actor = new JSProcessActorParent(); } MOZ_RELEASE_ASSERT(!actor->Manager(), "mManager was already initialized once!"); actor->Init(aName, this); - mProcessActors.Put(aName, RefPtr{actor}); - actor.forget(retval); - return NS_OK; + return actor.forget(); } IPCResult ContentParent::RecvFOGData(ByteBuf&& buf) { #ifdef MOZ_GLEAN glean::FOGData(std::move(buf)); #endif return IPC_OK(); }
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -1357,17 +1357,20 @@ class ContentParent final uint64_t GetBrowsingContextFieldEpoch() const { return mBrowsingContextFieldEpoch; } void UpdateNetworkLinkType(); static bool ShouldSyncPreference(const char16_t* aData); - JSActor::Type GetSide() override { return JSActor::Type::Parent; } + already_AddRefed<JSActor> InitJSActor(JS::HandleObject aMaybeActor, + const nsACString& aName, + ErrorResult& aRv) override; + mozilla::ipc::IProtocol* AsNativeActor() override { return this; } private: // Return an existing ContentParent if possible. Otherwise, `nullptr`. static already_AddRefed<ContentParent> GetUsedBrowserProcess( const nsAString& aRemoteType, nsTArray<ContentParent*>& aContentParents, uint32_t aMaxContentParents, bool aPreferUsed); void AddToPool(nsTArray<ContentParent*>&); @@ -1530,18 +1533,16 @@ class ContentParent final nsTHashtable<nsRefPtrHashKey<BrowsingContextGroup>> mGroups; // See `BrowsingContext::mEpochs` for an explanation of this field. uint64_t mBrowsingContextFieldEpoch = 0; // A preference serializer used to share preferences with the process. // Cleared once startup is complete. UniquePtr<mozilla::ipc::SharedPreferenceSerializer> mPrefSerializer; - - nsRefPtrHashtable<nsCStringHashKey, JSProcessActorParent> mProcessActors; }; NS_DEFINE_STATIC_IID_ACCESSOR(ContentParent, NS_CONTENTPARENT_IID) // This is the C++ version of remoteTypePrefix in E10SUtils.jsm. const nsDependentSubstring RemoteTypePrefix( const nsAString& aContentProcessType);
--- a/dom/ipc/InProcessChild.h +++ b/dom/ipc/InProcessChild.h @@ -41,17 +41,22 @@ class InProcessChild final : public nsID static InProcessChild* Singleton(); // Get the parent side of the in-process child actor |aActor|. If |aActor| is // not an in-process actor, or is not connected, this method will return // |nullptr|. static IProtocol* ParentActorFor(IProtocol* aActor); const nsAString& GetRemoteType() const override { return VoidString(); } - JSActor::Type GetSide() override { return JSActor::Type::Child; } + + protected: + already_AddRefed<JSActor> InitJSActor(JS::HandleObject aMaybeActor, + const nsACString& aName, + ErrorResult& aRv) override; + mozilla::ipc::IProtocol* AsNativeActor() override { return this; } private: // NOTE: PInProcess lifecycle management is declared as staic methods and // state on InProcessParent, and implemented in InProcessImpl.cpp. virtual void ActorDestroy(ActorDestroyReason aWhy) override; ~InProcessChild() = default; static StaticRefPtr<InProcessChild> sSingleton;
--- a/dom/ipc/InProcessImpl.cpp +++ b/dom/ipc/InProcessImpl.cpp @@ -106,20 +106,22 @@ NS_IMETHODIMP InProcessParent::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)); InProcessParent::Shutdown(); return NS_OK; } void InProcessParent::ActorDestroy(ActorDestroyReason aWhy) { + JSActorDidDestroy(); InProcessParent::Shutdown(); } void InProcessChild::ActorDestroy(ActorDestroyReason aWhy) { + JSActorDidDestroy(); InProcessParent::Shutdown(); } ///////////////////////// // nsIDOMProcessParent // ///////////////////////// NS_IMETHODIMP @@ -134,48 +136,42 @@ InProcessParent::GetOsPid(int32_t* aOsPi // so we can return the current process id. *aOsPid = base::GetCurrentProcId(); return NS_OK; } NS_IMETHODIMP InProcessParent::GetActor(const nsACString& aName, JSProcessActorParent** aActor) { - if (!CanSend()) { - return NS_ERROR_DOM_INVALID_STATE_ERR; + ErrorResult error; + RefPtr<JSProcessActorParent> actor = + JSActorManager::GetActor(aName, error).downcast<JSProcessActorParent>(); + if (error.Failed()) { + return error.StealNSResult(); } - - // Check if this actor has already been created, and return it if it has. - if (mProcessActors.Contains(aName)) { - RefPtr<JSProcessActorParent> actor(mProcessActors.Get(aName)); - actor.forget(aActor); - return NS_OK; - } + actor.forget(aActor); + return NS_OK; +} - // Otherwise, we want to create a new instance of this actor. - JS::RootedObject obj(RootingCx()); - ErrorResult result; - ConstructActor(aName, &obj, result); - if (result.Failed()) { - return result.StealNSResult(); - } - - // Unwrap our actor to a JSProcessActorParent object. +already_AddRefed<JSActor> InProcessParent::InitJSActor( + JS::HandleObject aMaybeActor, const nsACString& aName, ErrorResult& aRv) { RefPtr<JSProcessActorParent> actor; - nsresult rv = UNWRAP_OBJECT(JSProcessActorParent, &obj, actor); - if (NS_FAILED(rv)) { - return rv; + if (aMaybeActor.get()) { + aRv = UNWRAP_OBJECT(JSProcessActorParent, aMaybeActor.get(), actor); + if (aRv.Failed()) { + return nullptr; + } + } else { + actor = new JSProcessActorParent(); } MOZ_RELEASE_ASSERT(!actor->Manager(), "mManager was already initialized once!"); actor->Init(aName, this); - mProcessActors.Put(aName, RefPtr{actor}); - actor.forget(aActor); - return NS_OK; + return actor.forget(); } NS_IMETHODIMP InProcessParent::GetCanSend(bool* aCanSend) { *aCanSend = CanSend(); return NS_OK; } @@ -189,48 +185,42 @@ NS_IMETHODIMP InProcessChild::GetChildID(uint64_t* aChildID) { *aChildID = 0; return NS_OK; } NS_IMETHODIMP InProcessChild::GetActor(const nsACString& aName, JSProcessActorChild** aActor) { - if (!CanSend()) { - return NS_ERROR_DOM_INVALID_STATE_ERR; + ErrorResult error; + RefPtr<JSProcessActorChild> actor = + JSActorManager::GetActor(aName, error).downcast<JSProcessActorChild>(); + if (error.Failed()) { + return error.StealNSResult(); } - - // Check if this actor has already been created, and return it if it has. - if (mProcessActors.Contains(aName)) { - RefPtr<JSProcessActorChild> actor(mProcessActors.Get(aName)); - actor.forget(aActor); - return NS_OK; - } + actor.forget(aActor); + return NS_OK; +} - // Otherwise, we want to create a new instance of this actor. - JS::RootedObject obj(RootingCx()); - ErrorResult result; - ConstructActor(aName, &obj, result); - if (result.Failed()) { - return result.StealNSResult(); - } - - // Unwrap our actor to a JSProcessActorChild object. +already_AddRefed<JSActor> InProcessChild::InitJSActor( + JS::HandleObject aMaybeActor, const nsACString& aName, ErrorResult& aRv) { RefPtr<JSProcessActorChild> actor; - nsresult rv = UNWRAP_OBJECT(JSProcessActorChild, &obj, actor); - if (NS_FAILED(rv)) { - return rv; + if (aMaybeActor.get()) { + aRv = UNWRAP_OBJECT(JSProcessActorChild, aMaybeActor.get(), actor); + if (aRv.Failed()) { + return nullptr; + } + } else { + actor = new JSProcessActorChild(); } MOZ_RELEASE_ASSERT(!actor->Manager(), "mManager was already initialized once!"); actor->Init(aName, this); - mProcessActors.Put(aName, RefPtr{actor}); - actor.forget(aActor); - return NS_OK; + return actor.forget(); } NS_IMETHODIMP InProcessChild::GetCanSend(bool* aCanSend) { *aCanSend = CanSend(); return NS_OK; }
--- a/dom/ipc/InProcessParent.h +++ b/dom/ipc/InProcessParent.h @@ -43,17 +43,22 @@ class InProcessParent final : public nsI static InProcessParent* Singleton(); // Get the child side of the in-process child actor |aActor|. If |aActor| is // not an in-process actor, or is not connected, this method will return // |nullptr|. static IProtocol* ChildActorFor(IProtocol* aActor); const nsAString& GetRemoteType() const override { return VoidString(); }; - JSActor::Type GetSide() override { return JSActor::Type::Parent; } + + protected: + already_AddRefed<JSActor> InitJSActor(JS::HandleObject aMaybeActor, + const nsACString& aName, + ErrorResult& aRv) override; + mozilla::ipc::IProtocol* AsNativeActor() override { return this; } private: // Lifecycle management is implemented in InProcessImpl.cpp virtual void ActorDestroy(ActorDestroyReason aWhy) override; ~InProcessParent() = default; static void Startup(); static void Shutdown();
--- a/dom/ipc/ProcessActor.cpp +++ b/dom/ipc/ProcessActor.cpp @@ -8,115 +8,32 @@ #include "nsContentUtils.h" #include "mozJSComponentLoader.h" #include "mozilla/ContentBlockingAllowList.h" #include "mozilla/Logging.h" #include "mozilla/dom/JSActorService.h" #include "mozilla/dom/JSProcessActorParent.h" #include "mozilla/dom/JSProcessActorChild.h" +#include "mozilla/dom/JSProcessActorProtocol.h" namespace mozilla { namespace dom { -void ProcessActor::ConstructActor(const nsACString& aName, - JS::MutableHandleObject aActor, - ErrorResult& aRv) { - MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); - - JSActor::Type actorType = GetSide(); - MOZ_ASSERT_IF(actorType == JSActor::Type::Parent, XRE_IsParentProcess()); - - // Constructing an actor requires a running script, so push an AutoEntryScript - // onto the stack. - AutoEntryScript aes(xpc::PrivilegedJunkScope(), "ProcessActor construction"); - JSContext* cx = aes.cx(); - - RefPtr<JSActorService> actorSvc = JSActorService::GetSingleton(); - if (!actorSvc) { - aRv.ThrowInvalidStateError( - "While constructing JSProcessActor, could not acquire JSActorService."); - return; - } - +already_AddRefed<JSActorProtocol> ProcessActor::MatchingJSActorProtocol( + JSActorService* aActorSvc, const nsACString& aName, ErrorResult& aRv) { RefPtr<JSProcessActorProtocol> proto = - actorSvc->GetJSProcessActorProtocol(aName); + aActorSvc->GetJSProcessActorProtocol(aName); if (!proto) { aRv.ThrowNotFoundError(nsPrintfCString("No such JSProcessActor '%s'", PromiseFlatCString(aName).get())); - return; + return nullptr; } if (!proto->Matches(GetRemoteType())) { - aRv.ThrowTypeMismatchError( - nsPrintfCString("JSProcessActor '%s' does not match this process", - PromiseFlatCString(aName).get())); - return; - } - - // Load the module using mozJSComponentLoader. - RefPtr<mozJSComponentLoader> loader = mozJSComponentLoader::Get(); - MOZ_ASSERT(loader); - - JS::RootedObject global(cx); - JS::RootedObject exports(cx); - - const JSProcessActorProtocol::Sided* side; - if (actorType == JSActor::Type::Parent) { - side = &proto->Parent(); - } else { - side = &proto->Child(); + aRv.Throw(NS_ERROR_NOT_AVAILABLE); + return nullptr; } - - // Support basic functionally such as SendAsyncMessage and SendQuery for - // unspecified moduleURI. - if (!side->mModuleURI) { - RefPtr<JSActor> actor; - if (actorType == JSActor::Type::Parent) { - actor = new JSProcessActorParent(); - } else { - actor = new JSProcessActorChild(); - } - - JS::Rooted<JS::Value> wrapper(cx); - if (!ToJSValue(cx, actor, &wrapper)) { - aRv.NoteJSContextException(cx); - return; - } - - MOZ_ASSERT(wrapper.isObject()); - aActor.set(&wrapper.toObject()); - return; - } - - aRv = loader->Import(cx, side->mModuleURI.ref(), &global, &exports); - if (aRv.Failed()) { - return; - } - - MOZ_ASSERT(exports, "null exports!"); - - // Load the specific property from our module. - JS::RootedValue ctor(cx); - nsAutoCString ctorName(aName); - ctorName.Append(actorType == JSActor::Type::Parent ? "Parent"_ns - : "Child"_ns); - if (!JS_GetProperty(cx, exports, ctorName.get(), &ctor)) { - aRv.NoteJSContextException(cx); - return; - } - - if (NS_WARN_IF(!ctor.isObject())) { - nsPrintfCString message("Could not find actor constructor '%s'", - PromiseFlatCString(ctorName).get()); - aRv.ThrowNotFoundError(message); - return; - } - - // Invoke the constructor loaded from the module. - if (!JS::Construct(cx, ctor, JS::HandleValueArray::empty(), aActor)) { - aRv.NoteJSContextException(cx); - return; - } + return proto.forget(); } } // namespace dom } // namespace mozilla
--- a/dom/ipc/ProcessActor.h +++ b/dom/ipc/ProcessActor.h @@ -9,30 +9,29 @@ #include "nsWrapperCache.h" #include "nsISupports.h" #include "mozilla/dom/BrowsingContext.h" #include "mozilla/ErrorResult.h" #include "nsIURI.h" #include "nsString.h" #include "mozilla/dom/JSActor.h" +#include "mozilla/dom/JSActorManager.h" namespace mozilla { namespace dom { -// Common base class for Content{Parent, Child}. -class ProcessActor : public nsISupports { +// Common base class for Content{Parent, Child} and InProcess{Parent, Child}. +class ProcessActor : public JSActorManager { protected: virtual ~ProcessActor() = default; - // Load the module for the named Content Actor and contruct it. - // This method will not initialize the actor or set its manager, - // which is handled by callers. - void ConstructActor(const nsACString& aName, JS::MutableHandleObject aActor, - ErrorResult& aRv); + already_AddRefed<JSActorProtocol> MatchingJSActorProtocol( + JSActorService* aActorSvc, const nsACString& aName, + ErrorResult& aRv) final; + virtual const nsAString& GetRemoteType() const = 0; - virtual JSActor::Type GetSide() = 0; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_ProcessActor_h
--- a/dom/ipc/WindowGlobalActor.cpp +++ b/dom/ipc/WindowGlobalActor.cpp @@ -8,16 +8,17 @@ #include "nsContentUtils.h" #include "mozJSComponentLoader.h" #include "mozilla/ContentBlockingAllowList.h" #include "mozilla/Logging.h" #include "mozilla/dom/JSActorService.h" #include "mozilla/dom/JSWindowActorParent.h" #include "mozilla/dom/JSWindowActorChild.h" +#include "mozilla/dom/JSWindowActorProtocol.h" #include "mozilla/net/CookieJarSettings.h" namespace mozilla { namespace dom { // CORPP 3.1.3 https://mikewest.github.io/corpp/#integration-html static nsILoadInfo::CrossOriginEmbedderPolicy InheritedPolicy( dom::BrowsingContext* aBrowsingContext) { @@ -130,110 +131,27 @@ WindowGlobalInit WindowGlobalActor::Wind // Most data here is specific to the Document, which can change without // creating a new WindowGlobal. Anything new added here which fits that // description should also be synchronized in // WindowGlobalChild::OnNewDocument. return init; } -void WindowGlobalActor::ConstructActor(const nsACString& aName, - JS::MutableHandleObject aActor, - ErrorResult& aRv) { - MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); - - JSActor::Type actorType = GetSide(); - MOZ_ASSERT_IF(actorType == JSActor::Type::Parent, XRE_IsParentProcess()); - - // Constructing an actor requires a running script, so push an AutoEntryScript - // onto the stack. - AutoEntryScript aes(xpc::PrivilegedJunkScope(), - "WindowGlobalActor construction"); - JSContext* cx = aes.cx(); - - RefPtr<JSActorService> actorSvc = JSActorService::GetSingleton(); - if (!actorSvc) { - aRv.ThrowNotSupportedError("Could not acquire actor service"); - return; - } - +already_AddRefed<JSActorProtocol> WindowGlobalActor::MatchingJSActorProtocol( + JSActorService* aActorSvc, const nsACString& aName, ErrorResult& aRv) { RefPtr<JSWindowActorProtocol> proto = - actorSvc->GetJSWindowActorProtocol(aName); + aActorSvc->GetJSWindowActorProtocol(aName); if (!proto) { - aRv.ThrowNotSupportedError(nsPrintfCString( - "Could not get JSWindowActorProtocol: %s is not registered", - PromiseFlatCString(aName).get())); - return; + aRv.ThrowNotFoundError(nsPrintfCString("No such JSWindowActor '%s'", + PromiseFlatCString(aName).get())); + return nullptr; } if (!proto->Matches(BrowsingContext(), GetDocumentURI(), GetRemoteType())) { aRv.Throw(NS_ERROR_NOT_AVAILABLE); - return; - } - - // Load the module using mozJSComponentLoader. - RefPtr<mozJSComponentLoader> loader = mozJSComponentLoader::Get(); - MOZ_ASSERT(loader); - - JS::RootedObject global(cx); - JS::RootedObject exports(cx); - - const JSWindowActorProtocol::Sided* side; - if (actorType == JSActor::Type::Parent) { - side = &proto->Parent(); - } else { - side = &proto->Child(); + return nullptr; } - - // Support basic functionally such as SendAsyncMessage and SendQuery for - // unspecified moduleURI. - if (!side->mModuleURI) { - RefPtr<JSActor> actor; - if (actorType == JSActor::Type::Parent) { - actor = new JSWindowActorParent(); - } else { - actor = new JSWindowActorChild(); - } - - JS::Rooted<JS::Value> wrapper(cx); - if (!ToJSValue(cx, actor, &wrapper)) { - aRv.NoteJSContextException(cx); - return; - } - - MOZ_ASSERT(wrapper.isObject()); - aActor.set(&wrapper.toObject()); - return; - } - - aRv = loader->Import(cx, side->mModuleURI.ref(), &global, &exports); - if (aRv.Failed()) { - return; - } - - MOZ_ASSERT(exports, "null exports!"); - - // Load the specific property from our module. - JS::RootedValue ctor(cx); - nsAutoCString ctorName(aName); - ctorName.Append(actorType == JSActor::Type::Parent ? "Parent"_ns - : "Child"_ns); - if (!JS_GetProperty(cx, exports, ctorName.get(), &ctor)) { - aRv.NoteJSContextException(cx); - return; - } - - if (NS_WARN_IF(!ctor.isObject())) { - nsPrintfCString message("Could not find actor constructor '%s'", - ctorName.get()); - aRv.ThrowNotFoundError(message); - return; - } - - // Invoke the constructor loaded from the module. - if (!JS::Construct(cx, ctor, JS::HandleValueArray::empty(), aActor)) { - aRv.NoteJSContextException(cx); - return; - } + return proto.forget(); } } // namespace dom } // namespace mozilla
--- a/dom/ipc/WindowGlobalActor.h +++ b/dom/ipc/WindowGlobalActor.h @@ -9,44 +9,43 @@ #include "nsWrapperCache.h" #include "nsISupports.h" #include "mozilla/dom/BrowsingContext.h" #include "mozilla/ErrorResult.h" #include "nsIURI.h" #include "nsString.h" #include "mozilla/dom/JSActor.h" +#include "mozilla/dom/JSActorManager.h" #include "mozilla/dom/WindowGlobalTypes.h" namespace mozilla { namespace dom { // Common base class for WindowGlobal{Parent, Child}. -class WindowGlobalActor : public nsISupports { +class WindowGlobalActor : public JSActorManager { public: // Called to determine initial state for a window global actor created for an // initial about:blank document. static WindowGlobalInit AboutBlankInitializer( dom::BrowsingContext* aBrowsingContext, nsIPrincipal* aPrincipal); // Called to determine initial state for a window global actor created for a // specific existing nsGlobalWindowInner. static WindowGlobalInit WindowInitializer(nsGlobalWindowInner* aWindow); protected: virtual ~WindowGlobalActor() = default; - // Load the module for the named Window Actor and contruct it. - // This method will not initialize the actor or set its manager, - // which is handled by callers. - void ConstructActor(const nsACString& aName, JS::MutableHandleObject aActor, - ErrorResult& aRv); + already_AddRefed<JSActorProtocol> MatchingJSActorProtocol( + JSActorService* aActorSvc, const nsACString& aName, + ErrorResult& aRv) final; + virtual nsIURI* GetDocumentURI() = 0; virtual const nsAString& GetRemoteType() = 0; - virtual JSActor::Type GetSide() = 0; virtual dom::BrowsingContext* BrowsingContext() = 0; static WindowGlobalInit BaseInitializer( dom::BrowsingContext* aBrowsingContext, uint64_t aInnerWindowId, uint64_t aOuterWindowId); }; } // namespace dom
--- a/dom/ipc/WindowGlobalChild.cpp +++ b/dom/ipc/WindowGlobalChild.cpp @@ -315,26 +315,17 @@ void WindowGlobalChild::BeforeUnloadRemo void WindowGlobalChild::Destroy() { // Destroying a WindowGlobalChild requires running script, so hold off on // doing it until we can safely run JS callbacks. nsContentUtils::AddScriptRunner(NS_NewRunnableFunction( "WindowGlobalChild::Destroy", [self = RefPtr<WindowGlobalChild>(this)]() { // Make a copy so that we can avoid potential iterator invalidation when // calling the user-provided Destroy() methods. - nsTArray<RefPtr<JSWindowActorChild>> windowActors( - self->mWindowActors.Count()); - for (auto iter = self->mWindowActors.Iter(); !iter.Done(); - iter.Next()) { - windowActors.AppendElement(iter.UserData()); - } - - for (auto& windowActor : windowActors) { - windowActor->StartDestroy(); - } + self->JSActorWillDestroy(); // Perform async IPC shutdown unless we're not in-process, and our // BrowserChild is in the process of being destroyed, which will destroy // us as well. RefPtr<BrowserChild> browserChild = self->GetBrowserChild(); if (!browserChild || !browserChild->IsDestroyed()) { self->SendDestroy(); } @@ -597,83 +588,66 @@ const nsAString& WindowGlobalChild::GetR return ContentChild::GetSingleton()->GetRemoteType(); } return VoidString(); } already_AddRefed<JSWindowActorChild> WindowGlobalChild::GetActor( const nsACString& aName, ErrorResult& aRv) { - if (!CanSend()) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return nullptr; - } - - // Check if this actor has already been created, and return it if it has. - if (mWindowActors.Contains(aName)) { - return do_AddRef(mWindowActors.GetWeak(aName)); - } + return JSActorManager::GetActor(aName, aRv).downcast<JSWindowActorChild>(); +} - // Otherwise, we want to create a new instance of this actor. - JS::RootedObject obj(RootingCx()); - ConstructActor(aName, &obj, aRv); - if (aRv.Failed()) { - return nullptr; - } - - // Unwrap our actor to a JSWindowActorChild object. +already_AddRefed<JSActor> WindowGlobalChild::InitJSActor( + JS::HandleObject aMaybeActor, const nsACString& aName, ErrorResult& aRv) { RefPtr<JSWindowActorChild> actor; - if (NS_FAILED(UNWRAP_OBJECT(JSWindowActorChild, &obj, actor))) { - return nullptr; + if (aMaybeActor.get()) { + aRv = UNWRAP_OBJECT(JSWindowActorChild, aMaybeActor.get(), actor); + if (aRv.Failed()) { + return nullptr; + } + } else { + actor = new JSWindowActorChild(); } MOZ_RELEASE_ASSERT(!actor->GetManager(), "mManager was already initialized once!"); actor->Init(aName, this); - mWindowActors.Put(aName, RefPtr{actor}); return actor.forget(); } void WindowGlobalChild::ActorDestroy(ActorDestroyReason aWhy) { MOZ_ASSERT(nsContentUtils::IsSafeToRunScript(), "Destroying WindowGlobalChild can run script"); gWindowGlobalChildById->Remove(InnerWindowId()); #ifdef MOZ_GECKO_PROFILER profiler_unregister_page(InnerWindowId()); #endif // Destroy our JSActors, and reject any pending queries. - nsRefPtrHashtable<nsCStringHashKey, JSWindowActorChild> windowActors; - mWindowActors.SwapElements(windowActors); - for (auto iter = windowActors.Iter(); !iter.Done(); iter.Next()) { - iter.Data()->RejectPendingQueries(); - iter.Data()->AfterDestroy(); - } - windowActors.Clear(); + JSActorDidDestroy(); } WindowGlobalChild::~WindowGlobalChild() { MOZ_ASSERT(!gWindowGlobalChildById || !gWindowGlobalChildById->Contains(InnerWindowId())); - MOZ_ASSERT(!mWindowActors.Count()); } JSObject* WindowGlobalChild::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { return WindowGlobalChild_Binding::Wrap(aCx, this, aGivenProto); } nsISupports* WindowGlobalChild::GetParentObject() { return xpc::NativeGlobal(xpc::PrivilegedJunkScope()); } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WindowGlobalChild, mWindowGlobal, - mWindowActors) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WindowGlobalChild, mWindowGlobal) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowGlobalChild) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(WindowGlobalChild) NS_IMPL_CYCLE_COLLECTING_RELEASE(WindowGlobalChild)
--- a/dom/ipc/WindowGlobalChild.h +++ b/dom/ipc/WindowGlobalChild.h @@ -111,17 +111,21 @@ class WindowGlobalChild final : public W void OnNewDocument(Document* aNewDocument); nsISupports* GetParentObject(); JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; protected: const nsAString& GetRemoteType() override; - JSActor::Type GetSide() override { return JSActor::Type::Child; } + + already_AddRefed<JSActor> InitJSActor(JS::HandleObject aMaybeActor, + const nsACString& aName, + ErrorResult& aRv) override; + mozilla::ipc::IProtocol* AsNativeActor() override { return this; } // IPC messages mozilla::ipc::IPCResult RecvRawMessage(const JSActorMessageMeta& aMeta, const ClonedMessageData& aData, const ClonedMessageData& aStack); mozilla::ipc::IPCResult RecvMakeFrameLocal( const MaybeDiscarded<dom::BrowsingContext>& aFrameContext, @@ -154,17 +158,16 @@ class WindowGlobalChild final : public W private: WindowGlobalChild(dom::WindowContext* aWindowContext, nsIPrincipal* aPrincipal, nsIURI* aURI); ~WindowGlobalChild(); RefPtr<nsGlobalWindowInner> mWindowGlobal; RefPtr<dom::WindowContext> mWindowContext; - nsRefPtrHashtable<nsCStringHashKey, JSWindowActorChild> mWindowActors; nsCOMPtr<nsIPrincipal> mDocumentPrincipal; nsCOMPtr<nsIURI> mDocumentURI; int64_t mBeforeUnloadListeners = 0; }; } // namespace dom } // namespace mozilla
--- a/dom/ipc/WindowGlobalParent.cpp +++ b/dom/ipc/WindowGlobalParent.cpp @@ -398,24 +398,17 @@ mozilla::ipc::IPCResult WindowGlobalPare const IPCClientInfo& aIPCClientInfo) { mClientInfo = Some(ClientInfo(aIPCClientInfo)); return IPC_OK(); } IPCResult WindowGlobalParent::RecvDestroy() { // Make a copy so that we can avoid potential iterator invalidation when // calling the user-provided Destroy() methods. - nsTArray<RefPtr<JSWindowActorParent>> windowActors(mWindowActors.Count()); - for (auto iter = mWindowActors.Iter(); !iter.Done(); iter.Next()) { - windowActors.AppendElement(iter.UserData()); - } - - for (auto& windowActor : windowActors) { - windowActor->StartDestroy(); - } + JSActorWillDestroy(); if (CanSend()) { RefPtr<BrowserParent> browserParent = GetBrowserParent(); if (!browserParent || !browserParent->IsDestroyed()) { Unused << Send__delete__(this); } } return IPC_OK(); @@ -487,43 +480,34 @@ void WindowGlobalParent::NotifyContentBl new RemoteWebProgress(0, false, BrowsingContext()->IsTopContent()); GetBrowsingContext()->Top()->GetWebProgress()->OnContentBlockingEvent( webProgress, aRequest, event.value()); } } already_AddRefed<JSWindowActorParent> WindowGlobalParent::GetActor( const nsACString& aName, ErrorResult& aRv) { - if (!CanSend()) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return nullptr; - } - - // Check if this actor has already been created, and return it if it has. - if (mWindowActors.Contains(aName)) { - return do_AddRef(mWindowActors.GetWeak(aName)); - } + return JSActorManager::GetActor(aName, aRv).downcast<JSWindowActorParent>(); +} - // Otherwise, we want to create a new instance of this actor. - JS::RootedObject obj(RootingCx()); - ConstructActor(aName, &obj, aRv); - if (aRv.Failed()) { - return nullptr; - } - - // Unwrap our actor to a JSWindowActorParent object. +already_AddRefed<JSActor> WindowGlobalParent::InitJSActor( + JS::HandleObject aMaybeActor, const nsACString& aName, ErrorResult& aRv) { RefPtr<JSWindowActorParent> actor; - if (NS_FAILED(UNWRAP_OBJECT(JSWindowActorParent, &obj, actor))) { - return nullptr; + if (aMaybeActor.get()) { + aRv = UNWRAP_OBJECT(JSWindowActorParent, aMaybeActor.get(), actor); + if (aRv.Failed()) { + return nullptr; + } + } else { + actor = new JSWindowActorParent(); } MOZ_RELEASE_ASSERT(!actor->GetManager(), "mManager was already initialized once!"); actor->Init(aName, this); - mWindowActors.Put(aName, RefPtr{actor}); return actor.forget(); } bool WindowGlobalParent::IsCurrentGlobal() { return CanSend() && BrowsingContext()->GetCurrentWindowGlobal() == this; } namespace { @@ -794,37 +778,29 @@ void WindowGlobalParent::ActorDestroy(Ac net::SchemeIsHTTPS(mDocumentURI))) { GetContentBlockingLog()->ReportOrigins(); } } } } // Destroy our JSWindowActors, and reject any pending queries. - nsRefPtrHashtable<nsCStringHashKey, JSWindowActorParent> windowActors; - mWindowActors.SwapElements(windowActors); - for (auto iter = windowActors.Iter(); !iter.Done(); iter.Next()) { - iter.Data()->RejectPendingQueries(); - iter.Data()->AfterDestroy(); - } - windowActors.Clear(); + JSActorDidDestroy(); nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); if (obs) { obs->NotifyObservers(ToSupports(this), "window-global-destroyed", nullptr); } if (mOriginCounter) { mOriginCounter->Accumulate(); } } -WindowGlobalParent::~WindowGlobalParent() { - MOZ_ASSERT(!mWindowActors.Count()); -} +WindowGlobalParent::~WindowGlobalParent() = default; JSObject* WindowGlobalParent::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { return WindowGlobalParent_Binding::Wrap(aCx, this, aGivenProto); } nsIGlobalObject* WindowGlobalParent::GetParentObject() { return xpc::NativeGlobal(xpc::PrivilegedJunkScope()); @@ -877,18 +853,17 @@ void WindowGlobalParent::AddMixedContent mMixedContentSecurityState |= aStateFlags; if (GetBrowsingContext()->GetCurrentWindowGlobal() == this) { GetBrowsingContext()->UpdateSecurityStateForLocationOrMixedContentChange(); } } -NS_IMPL_CYCLE_COLLECTION_INHERITED(WindowGlobalParent, WindowContext, - mWindowActors) +NS_IMPL_CYCLE_COLLECTION_INHERITED(WindowGlobalParent, WindowContext) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WindowGlobalParent, WindowContext) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowGlobalParent) NS_INTERFACE_MAP_END_INHERITING(WindowContext)
--- a/dom/ipc/WindowGlobalParent.h +++ b/dom/ipc/WindowGlobalParent.h @@ -196,17 +196,20 @@ class WindowGlobalParent final : public void AddMixedContentSecurityState(uint32_t aStateFlags); uint32_t GetMixedContentSecurityFlags() { return mMixedContentSecurityState; } nsITransportSecurityInfo* GetSecurityInfo() { return mSecurityInfo; } const nsAString& GetRemoteType() override; protected: - JSActor::Type GetSide() override { return JSActor::Type::Parent; } + already_AddRefed<JSActor> InitJSActor(JS::HandleObject aMaybeActor, + const nsACString& aName, + ErrorResult& aRv) override; + mozilla::ipc::IProtocol* AsNativeActor() override { return this; } // IPC messages mozilla::ipc::IPCResult RecvLoadURI( const MaybeDiscarded<dom::BrowsingContext>& aTargetBC, nsDocShellLoadState* aLoadState, bool aSetNavigating); mozilla::ipc::IPCResult RecvInternalLoad( const MaybeDiscarded<dom::BrowsingContext>& aTargetBC, nsDocShellLoadState* aLoadState); @@ -261,17 +264,16 @@ class WindowGlobalParent final : public // NOTE: This document principal doesn't reflect possible |document.domain| // mutations which may have been made in the actual document. nsCOMPtr<nsIPrincipal> mDocumentPrincipal; nsCOMPtr<nsIPrincipal> mDocContentBlockingAllowListPrincipal; nsCOMPtr<nsIURI> mDocumentURI; nsString mDocumentTitle; - nsRefPtrHashtable<nsCStringHashKey, JSWindowActorParent> mWindowActors; bool mIsInitialDocument; // True if this window has a "beforeunload" event listener. bool mHasBeforeUnload; // The log of all content blocking actions taken on the document related to // this WindowGlobalParent. This is only stored on top-level documents and // includes the activity log for all of the nested subdocuments as well.
--- a/dom/ipc/jsactor/JSActor.cpp +++ b/dom/ipc/jsactor/JSActor.cpp @@ -30,30 +30,30 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION( NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(JSActor) NS_IMPL_CYCLE_COLLECTING_RELEASE(JSActor) NS_IMPL_CYCLE_COLLECTION_CLASS(JSActor) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(JSActor) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal) NS_IMPL_CYCLE_COLLECTION_UNLINK(mWrappedJS) NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingQueries) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(JSActor) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWrappedJS) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingQueries) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(JSActor) -JSActor::JSActor() : mNextQueryId(0) {} - // RAII class to ensure that, if we crash while handling a message, the // crash will be annotated with the name of the actor and the message. struct MOZ_RAII AutoAnnotateMessageInCaseOfCrash { AutoAnnotateMessageInCaseOfCrash(const nsCString& aActorName, const nsCString& aMessageName) { CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::JSActorName, aActorName); CrashReporter::AnnotateCrashReport( @@ -62,28 +62,45 @@ struct MOZ_RAII AutoAnnotateMessageInCas ~AutoAnnotateMessageInCaseOfCrash() { CrashReporter::RemoveCrashReportAnnotation( CrashReporter::Annotation::JSActorMessage); CrashReporter::RemoveCrashReportAnnotation( CrashReporter::Annotation::JSActorName); } }; +JSActor::JSActor(nsISupports* aGlobal) { + mGlobal = do_QueryInterface(aGlobal); + if (!mGlobal) { + mGlobal = xpc::NativeGlobal(xpc::PrivilegedJunkScope()); + } +} + void JSActor::StartDestroy() { AutoAnnotateMessageInCaseOfCrash guard(/* aActorName = */ mName, "<WillDestroy>"_ns); InvokeCallback(CallbackFunction::WillDestroy); + mCanSend = false; } void JSActor::AfterDestroy() { AutoAnnotateMessageInCaseOfCrash guard(/* aActorName = */ mName, "<DidDestroy>"_ns); + mCanSend = false; + + // Take our queries out, in case somehow rejecting promises can trigger + // additions or removals. + nsRefPtrHashtable<nsUint64HashKey, Promise> pendingQueries; + mPendingQueries.SwapElements(pendingQueries); + for (auto& entry : pendingQueries) { + entry.GetData()->MaybeReject(NS_ERROR_NOT_AVAILABLE); + } + InvokeCallback(CallbackFunction::DidDestroy); - // Clear out & reject mPendingQueries - RejectPendingQueries(); + ClearManager(); } void JSActor::InvokeCallback(CallbackFunction callback) { MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); AutoEntryScript aes(GetParentObject(), "JSActor destroy callback"); JSContext* cx = aes.cx(); MozJSActorCallbacks callbacksHolder; @@ -126,28 +143,16 @@ nsresult JSActor::QueryInterfaceActor(co mWrappedJS = do_QueryInterface(wrappedJS); MOZ_ASSERT(mWrappedJS); } return mWrappedJS->QueryInterface(aIID, aPtr); } -void JSActor::RejectPendingQueries() { - MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); - - // Take our queries out, in case somehow rejecting promises can trigger - // additions or removals. - nsRefPtrHashtable<nsUint64HashKey, Promise> pendingQueries; - mPendingQueries.SwapElements(pendingQueries); - for (auto iter = pendingQueries.Iter(); !iter.Done(); iter.Next()) { - iter.Data()->MaybeReject(NS_ERROR_NOT_AVAILABLE); - } -} - /* static */ bool JSActor::AllowMessage(const JSActorMessageMeta& aMetadata, size_t aDataLength) { // A message includes more than structured clone data, so subtract // 20KB to make it more likely that a message within this bound won't // result in an overly large IPC message. static const size_t kMaxMessageSize = IPC::Channel::kMaximumMessageSize - 20 * 1024;
--- a/dom/ipc/jsactor/JSActor.h +++ b/dom/ipc/jsactor/JSActor.h @@ -18,55 +18,51 @@ class nsIGlobalObject; class nsQueryActorChild; class nsQueryActorParent; namespace mozilla { namespace dom { +class JSActorManager; +class JSActorMessageMeta; +class QueryPromiseHandler; + enum class JSActorMessageKind { Message, Query, QueryResolve, QueryReject, EndGuard_, }; -class JSActorMessageMeta; -class QueryPromiseHandler; - // Common base class for JSWindowActor{Parent,Child}. class JSActor : public nsISupports, public nsWrapperCache { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(JSActor) - JSActor(); - - enum class Type { Parent, Child }; - enum class CallbackFunction { WillDestroy, DidDestroy, ActorCreated }; + explicit JSActor(nsISupports* aGlobal = nullptr); const nsCString& Name() const { return mName; } void SendAsyncMessage(JSContext* aCx, const nsAString& aMessageName, JS::Handle<JS::Value> aObj, ErrorResult& aRv); already_AddRefed<Promise> SendQuery(JSContext* aCx, const nsAString& aMessageName, JS::Handle<JS::Value> aObj, ErrorResult& aRv); void ReceiveRawMessage(const JSActorMessageMeta& aMetadata, ipc::StructuredCloneData&& aData, ipc::StructuredCloneData&& aStack); - virtual nsIGlobalObject* GetParentObject() const = 0; - - void RejectPendingQueries(); + nsIGlobalObject* GetParentObject() const { return mGlobal; }; protected: // Send the message described by the structured clone data |aData|, and the // message metadata |aMetadata|. The underlying transport should call the // |ReceiveMessage| method on the other side asynchronously. virtual void SendRawMessage(const JSActorMessageMeta& aMetadata, ipc::StructuredCloneData&& aData, ipc::StructuredCloneData&& aStack, @@ -76,23 +72,28 @@ class JSActor : public nsISupports, publ // send it. If it is too large, record telemetry about the message. static bool AllowMessage(const JSActorMessageMeta& aMetadata, size_t aDataLength); virtual ~JSActor() = default; void SetName(const nsACString& aName); + bool CanSend() const { return mCanSend; } + void StartDestroy(); - void AfterDestroy(); + enum class CallbackFunction { WillDestroy, DidDestroy, ActorCreated }; void InvokeCallback(CallbackFunction willDestroy); + virtual void ClearManager() = 0; + private: + friend class JSActorManager; friend class ::nsQueryActorChild; // for QueryInterfaceActor friend class ::nsQueryActorParent; // for QueryInterfaceActor nsresult QueryInterfaceActor(const nsIID& aIID, void** aPtr); void ReceiveMessageOrQuery(JSContext* aCx, const JSActorMessageMeta& aMetadata, JS::Handle<JS::Value> aData, ErrorResult& aRv); @@ -123,20 +124,22 @@ class JSActor : public nsISupports, publ ipc::StructuredCloneData&& aData); RefPtr<JSActor> mActor; RefPtr<Promise> mPromise; nsString mMessageName; uint64_t mQueryId; }; + nsCOMPtr<nsIGlobalObject> mGlobal; nsCOMPtr<nsISupports> mWrappedJS; nsCString mName; nsRefPtrHashtable<nsUint64HashKey, Promise> mPendingQueries; - uint64_t mNextQueryId; + uint64_t mNextQueryId = 0; + bool mCanSend = true; }; } // namespace dom } // namespace mozilla namespace IPC { template <>
new file mode 100644 --- /dev/null +++ b/dom/ipc/jsactor/JSActorManager.cpp @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/JSActorManager.h" +#include "mozilla/dom/JSActorService.h" +#include "mozJSComponentLoader.h" +#include "jsapi.h" + +namespace mozilla { +namespace dom { + +already_AddRefed<JSActor> JSActorManager::GetActor(const nsACString& aName, + ErrorResult& aRv) { + MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); + + // If our connection has been closed, return an error. + mozilla::ipc::IProtocol* nativeActor = AsNativeActor(); + if (!nativeActor->CanSend()) { + aRv.ThrowInvalidStateError(nsPrintfCString( + "Cannot get actor '%s'. Native '%s' actor is destroyed.", + PromiseFlatCString(aName).get(), nativeActor->GetProtocolName())); + return nullptr; + } + + // Check if this actor has already been created, and return it if it has. + if (RefPtr<JSActor> actor = mJSActors.Get(aName)) { + return actor.forget(); + } + + RefPtr<JSActorService> actorSvc = JSActorService::GetSingleton(); + if (!actorSvc) { + aRv.ThrowInvalidStateError("JSActorService hasn't been initialized"); + return nullptr; + } + + // Check if this actor satisfies the requirements of the protocol + // corresponding to `aName`, and get the module which implements it. + RefPtr<JSActorProtocol> protocol = + MatchingJSActorProtocol(actorSvc, aName, aRv); + if (!protocol) { + return nullptr; + } + + bool isParent = nativeActor->GetSide() == mozilla::ipc::ParentSide; + auto& side = isParent ? protocol->Parent() : protocol->Child(); + + // Constructing an actor requires a running script, so push an AutoEntryScript + // onto the stack. + AutoEntryScript aes(xpc::PrivilegedJunkScope(), "JSActor construction"); + JSContext* cx = aes.cx(); + + // Load the module using mozJSComponentLoader. + RefPtr<mozJSComponentLoader> loader = mozJSComponentLoader::Get(); + MOZ_ASSERT(loader); + + // If a module URI was provided, use it to construct an instance of the actor. + JS::RootedObject actorObj(cx); + if (side.mModuleURI) { + JS::RootedObject global(cx); + JS::RootedObject exports(cx); + aRv = loader->Import(cx, side.mModuleURI.ref(), &global, &exports); + if (aRv.Failed()) { + return nullptr; + } + MOZ_ASSERT(exports, "null exports!"); + + // Load the specific property from our module. + JS::RootedValue ctor(cx); + nsAutoCString ctorName(aName); + ctorName.Append(isParent ? "Parent"_ns : "Child"_ns); + if (!JS_GetProperty(cx, exports, ctorName.get(), &ctor)) { + aRv.NoteJSContextException(cx); + return nullptr; + } + + if (NS_WARN_IF(!ctor.isObject())) { + aRv.ThrowNotFoundError( + nsPrintfCString("Could not find actor constructor '%s'", + PromiseFlatCString(ctorName).get())); + return nullptr; + } + + // Invoke the constructor loaded from the module. + if (!JS::Construct(cx, ctor, JS::HandleValueArray::empty(), &actorObj)) { + aRv.NoteJSContextException(cx); + return nullptr; + } + } + + // Initialize our newly-constructed actor, and return it. + RefPtr<JSActor> actor = InitJSActor(actorObj, aName, aRv); + if (aRv.Failed()) { + return nullptr; + } + mJSActors.Put(aName, RefPtr{actor}); + return actor.forget(); +} + +void JSActorManager::JSActorWillDestroy() { + MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); + + // Make a copy so that we can avoid potential iterator invalidation when + // calling the user-provided Destroy() methods. + nsTArray<RefPtr<JSActor>> actors(mJSActors.Count()); + for (auto& entry : mJSActors) { + actors.AppendElement(entry.GetData()); + } + for (auto& actor : actors) { + actor->StartDestroy(); + } +} + +void JSActorManager::JSActorDidDestroy() { + MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); + + // Swap the table with `mJSActors` so that we don't invalidate it while + // iterating. + nsRefPtrHashtable<nsCStringHashKey, JSActor> actors; + mJSActors.SwapElements(actors); + for (auto& entry : actors) { + entry.GetData()->AfterDestroy(); + } +} + +} // namespace dom +} // namespace mozilla
new file mode 100644 --- /dev/null +++ b/dom/ipc/jsactor/JSActorManager.h @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_JSActorManager_h +#define mozilla_dom_JSActorManager_h + +#include "js/TypeDecls.h" +#include "mozilla/dom/JSActor.h" +#include "mozilla/ErrorResult.h" +#include "nsString.h" + +namespace mozilla { +namespace ipc { +class IProtocol; +} + +namespace dom { + +class JSActorProtocol; +class JSActorService; + +class JSActorManager : public nsISupports { + public: + /** + * Get or create an actor by it's name. + * + * Will return an error if the actor fails to be constructed, or `nullptr` if + * actor creation was vetoed by a constraint. + */ + already_AddRefed<JSActor> GetActor(const nsACString& aName, ErrorResult& aRv); + + protected: + /** + * Lifecycle methods which will fire the `willDestroy` and `didDestroy` + * methods on relevant actors. + */ + void JSActorWillDestroy(); + void JSActorDidDestroy(); + + /** + * Return the protocol with the given name, if it is supported by the current + * actor. + */ + virtual already_AddRefed<JSActorProtocol> MatchingJSActorProtocol( + JSActorService* aActorSvc, const nsACString& aName, ErrorResult& aRv) = 0; + + /** + * Initialize a JSActor instance given the constructed JS object. + * `aMaybeActor` may be `nullptr`, which should construct the default empty + * actor. + */ + virtual already_AddRefed<JSActor> InitJSActor(JS::HandleObject aMaybeActor, + const nsACString& aName, + ErrorResult& aRv) = 0; + + /** + * Return this native actor. This should be the same object which is + * implementing `JSActorManager`. + */ + virtual mozilla::ipc::IProtocol* AsNativeActor() = 0; + + private: + nsRefPtrHashtable<nsCStringHashKey, JSActor> mJSActors; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_JSActorManager_h \ No newline at end of file
--- a/dom/ipc/jsactor/JSActorService.cpp +++ b/dom/ipc/jsactor/JSActorService.cpp @@ -8,18 +8,20 @@ #include "mozilla/dom/JSActorService.h" #include "mozilla/dom/ChromeUtilsBinding.h" #include "mozilla/dom/EventListenerBinding.h" #include "mozilla/dom/Event.h" #include "mozilla/dom/EventTargetBinding.h" #include "mozilla/dom/EventTarget.h" #include "mozilla/dom/JSProcessActorBinding.h" #include "mozilla/dom/JSProcessActorChild.h" +#include "mozilla/dom/JSProcessActorProtocol.h" #include "mozilla/dom/JSWindowActorBinding.h" #include "mozilla/dom/JSWindowActorChild.h" +#include "mozilla/dom/JSWindowActorProtocol.h" #include "mozilla/dom/MessageManagerBinding.h" #include "mozilla/dom/PContent.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/WindowGlobalChild.h" #include "mozilla/ArrayAlgorithm.h" #include "mozilla/StaticPtr.h" #include "mozilla/Logging.h"
--- a/dom/ipc/jsactor/JSActorService.h +++ b/dom/ipc/jsactor/JSActorService.h @@ -9,31 +9,31 @@ #include "mozilla/dom/BrowsingContext.h" #include "mozilla/ErrorResult.h" #include "nsIURI.h" #include "nsRefPtrHashtable.h" #include "nsString.h" #include "nsTArray.h" #include "mozilla/dom/JSActor.h" -#include "mozilla/dom/JSProcessActorProtocol.h" -#include "mozilla/dom/JSWindowActorProtocol.h" - #include "nsIObserver.h" #include "nsIDOMEventListener.h" #include "mozilla/EventListenerManager.h" #include "mozilla/extensions/WebExtensionContentScript.h" namespace mozilla { namespace dom { + struct ProcessActorOptions; struct WindowActorOptions; class JSProcessActorInfo; class JSWindowActorInfo; class EventTarget; +class JSWindowActorProtocol; +class JSProcessActorProtocol; class JSActorService final { public: NS_INLINE_DECL_REFCOUNTING(JSActorService) static already_AddRefed<JSActorService> GetSingleton(); // Register or unregister a chrome event target. @@ -81,17 +81,31 @@ class JSActorService final { ~JSActorService(); nsTArray<EventTarget*> mChromeEventTargets; // -- Window Actor nsRefPtrHashtable<nsCStringHashKey, JSWindowActorProtocol> mWindowActorDescriptors; - // -- Content Actor + // -- Process Actor nsRefPtrHashtable<nsCStringHashKey, JSProcessActorProtocol> mProcessActorDescriptors; }; +/** + * Base clsas for both `JSWindowActorProtocol` and `JSProcessActorProtocol` + * which can be used by generic code. + */ +class JSActorProtocol : public nsISupports { + public: + struct Sided { + Maybe<nsCString> mModuleURI; + }; + + virtual const Sided& Parent() const = 0; + virtual const Sided& Child() const = 0; +}; + } // namespace dom } // namespace mozilla #endif // mozilla_dom_JSActorService_h
--- a/dom/ipc/jsactor/JSProcessActorChild.cpp +++ b/dom/ipc/jsactor/JSProcessActorChild.cpp @@ -60,17 +60,17 @@ class AsyncMessageToProcessParent : publ }; } // namespace void JSProcessActorChild::SendRawMessage(const JSActorMessageMeta& aMeta, ipc::StructuredCloneData&& aData, ipc::StructuredCloneData&& aStack, ErrorResult& aRv) { - if (NS_WARN_IF(!mCanSend || !mManager || !mManager->GetCanSend())) { + if (NS_WARN_IF(!CanSend() || !mManager || !mManager->GetCanSend())) { aRv.ThrowInvalidStateError("JSProcessActorChild cannot send at the moment"); return; } if (NS_WARN_IF( !AllowMessage(aMeta, aData.DataLength() + aStack.DataLength()))) { aRv.ThrowDataCloneError( nsPrintfCString("JSProcessActorChild serialization error: data too " @@ -113,15 +113,12 @@ void JSProcessActorChild::Init(const nsA nsIDOMProcessChild* aManager) { MOZ_ASSERT(!mManager, "Cannot Init() a JSProcessActorChild twice!"); SetName(aName); mManager = aManager; InvokeCallback(CallbackFunction::ActorCreated); } -void JSProcessActorChild::AfterDestroy() { - JSActor::AfterDestroy(); - mManager = nullptr; -} +void JSProcessActorChild::ClearManager() { mManager = nullptr; } } // namespace dom } // namespace mozilla
--- a/dom/ipc/jsactor/JSProcessActorChild.h +++ b/dom/ipc/jsactor/JSProcessActorChild.h @@ -15,45 +15,43 @@ namespace dom { // Placeholder implementation. class JSProcessActorChild final : public JSActor { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(JSProcessActorChild, JSActor) - nsIGlobalObject* GetParentObject() const override { - return xpc::NativeGlobal(xpc::PrivilegedJunkScope()); - } + explicit JSProcessActorChild(nsISupports* aGlobal = nullptr) + : JSActor(aGlobal) {} JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; static already_AddRefed<JSProcessActorChild> Constructor( GlobalObject& aGlobal) { - return MakeAndAddRef<JSProcessActorChild>(); + return MakeAndAddRef<JSProcessActorChild>(aGlobal.GetAsSupports()); } nsIDOMProcessChild* Manager() const { return mManager; } void Init(const nsACString& aName, nsIDOMProcessChild* aManager); - void AfterDestroy(); + void ClearManager() override; protected: // Send the message described by the structured clone data |aData|, and the // message metadata |aMetadata|. The underlying transport should call the // |ReceiveMessage| method on the other side asynchronously. virtual void SendRawMessage(const JSActorMessageMeta& aMetadata, ipc::StructuredCloneData&& aData, ipc::StructuredCloneData&& aStack, ErrorResult& aRv) override; private: ~JSProcessActorChild() { MOZ_ASSERT(!mManager); } - bool mCanSend = true; nsCOMPtr<nsIDOMProcessChild> mManager; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_JSProcessActorChild_h
--- a/dom/ipc/jsactor/JSProcessActorParent.cpp +++ b/dom/ipc/jsactor/JSProcessActorParent.cpp @@ -71,17 +71,17 @@ class AsyncMessageToProcessChild : publi }; } // namespace void JSProcessActorParent::SendRawMessage(const JSActorMessageMeta& aMeta, ipc::StructuredCloneData&& aData, ipc::StructuredCloneData&& aStack, ErrorResult& aRv) { - if (NS_WARN_IF(!mCanSend || !mManager || !mManager->GetCanSend())) { + if (NS_WARN_IF(!CanSend() || !mManager || !mManager->GetCanSend())) { aRv.ThrowInvalidStateError( nsPrintfCString("Actor '%s' cannot send message '%s' during shutdown.", PromiseFlatCString(aMeta.actorName()).get(), NS_ConvertUTF16toUTF8(aMeta.messageName()).get())); return; } if (NS_WARN_IF( @@ -117,15 +117,12 @@ void JSProcessActorParent::SendRawMessag } if (NS_WARN_IF(!contentParent->SendRawMessage(aMeta, msgData, stackData))) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } } -void JSProcessActorParent::AfterDestroy() { - JSActor::AfterDestroy(); - mManager = nullptr; -} +void JSProcessActorParent::ClearManager() { mManager = nullptr; } } // namespace dom } // namespace mozilla
--- a/dom/ipc/jsactor/JSProcessActorParent.h +++ b/dom/ipc/jsactor/JSProcessActorParent.h @@ -22,45 +22,43 @@ namespace mozilla { namespace dom { class JSProcessActorParent final : public JSActor { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(JSProcessActorParent, JSActor) - nsIGlobalObject* GetParentObject() const override { - return xpc::NativeGlobal(xpc::PrivilegedJunkScope()); - } + explicit JSProcessActorParent(nsISupports* aGlobal = nullptr) + : JSActor(aGlobal) {} JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; static already_AddRefed<JSProcessActorParent> Constructor( GlobalObject& aGlobal) { - return MakeAndAddRef<JSProcessActorParent>(); + return MakeAndAddRef<JSProcessActorParent>(aGlobal.GetAsSupports()); } nsIDOMProcessParent* Manager() const { return mManager; } void Init(const nsACString& aName, nsIDOMProcessParent* aManager); - void AfterDestroy(); + void ClearManager() override; protected: // Send the message described by the structured clone data |aData|, and the // message metadata |aMetadata|. The underlying transport should call the // |ReceiveMessage| method on the other side asynchronously. virtual void SendRawMessage(const JSActorMessageMeta& aMetadata, ipc::StructuredCloneData&& aData, ipc::StructuredCloneData&& aStack, ErrorResult& aRv) override; private: ~JSProcessActorParent(); - bool mCanSend = true; nsCOMPtr<nsIDOMProcessParent> mManager; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_JSProcessActorParent_h
--- a/dom/ipc/jsactor/JSProcessActorProtocol.cpp +++ b/dom/ipc/jsactor/JSProcessActorProtocol.cpp @@ -74,31 +74,27 @@ JSProcessActorProtocol::FromWebIDLOption return proto.forget(); } NS_IMETHODIMP JSProcessActorProtocol::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); - nsCOMPtr<nsIDOMProcessChild> manager; + RefPtr<JSActorManager> manager; if (XRE_IsParentProcess()) { manager = InProcessChild::Singleton(); } else { manager = ContentChild::GetSingleton(); } - RefPtr<JSProcessActorChild> actor; - nsresult rv = manager->GetActor(mName, getter_AddRefs(actor)); - if (NS_WARN_IF(NS_FAILED(rv))) { - // Don't raise an error if creation of our actor was vetoed. - if (rv == NS_ERROR_NOT_AVAILABLE) { - return NS_OK; - } - return rv; + // Ensure our actor is present. + RefPtr<JSActor> actor = manager->GetActor(mName, IgnoreErrors()); + if (!actor) { + return NS_OK; } // Build a observer callback. JS::Rooted<JSObject*> global(RootingCx(), JS::GetNonCCWObjectGlobal(actor->GetWrapper())); RefPtr<MozObserverCallback> observerCallback = new MozObserverCallback(actor->GetWrapper(), global, nullptr, nullptr); observerCallback->Observe(aSubject, nsDependentCString(aTopic),
--- a/dom/ipc/jsactor/JSProcessActorProtocol.h +++ b/dom/ipc/jsactor/JSProcessActorProtocol.h @@ -3,16 +3,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_JSProcessActorProtocol_h #define mozilla_dom_JSProcessActorProtocol_h #include "mozilla/dom/BrowsingContext.h" +#include "mozilla/dom/JSActorService.h" #include "mozilla/ErrorResult.h" #include "nsIURI.h" #include "nsString.h" #include "nsTArray.h" #include "nsIObserver.h" namespace mozilla { namespace dom { @@ -22,42 +23,39 @@ class JSProcessActorInfo; class EventTarget; /** * Object corresponding to a single process actor protocol * * This object also can act as a carrier for methods and other state related to * a single protocol managed by the JSActorService. */ -class JSProcessActorProtocol final : public nsIObserver { +class JSProcessActorProtocol final : public JSActorProtocol, + public nsIObserver { public: NS_DECL_NSIOBSERVER NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(JSProcessActorProtocol, nsIObserver) static already_AddRefed<JSProcessActorProtocol> FromIPC( const JSProcessActorInfo& aInfo); JSProcessActorInfo ToIPC(); static already_AddRefed<JSProcessActorProtocol> FromWebIDLOptions( const nsACString& aName, const ProcessActorOptions& aOptions, ErrorResult& aRv); - struct Sided { - Maybe<nsCString> mModuleURI; - }; - struct ParentSide : public Sided {}; struct ChildSide : public Sided { nsTArray<nsCString> mObservers; }; - const ParentSide& Parent() const { return mParent; } - const ChildSide& Child() const { return mChild; } + const ParentSide& Parent() const override { return mParent; } + const ChildSide& Child() const override { return mChild; } void AddObservers(); void RemoveObservers(); bool Matches(const nsAString& aRemoteType); private: explicit JSProcessActorProtocol(const nsACString& aName) : mName(aName) {} bool RemoteTypePrefixMatches(const nsDependentSubstring& aRemoteType);
--- a/dom/ipc/jsactor/JSWindowActorChild.cpp +++ b/dom/ipc/jsactor/JSWindowActorChild.cpp @@ -12,20 +12,16 @@ #include "mozilla/dom/WindowProxyHolder.h" #include "mozilla/dom/MessageManagerBinding.h" #include "mozilla/dom/BrowsingContext.h" #include "nsGlobalWindowInner.h" namespace mozilla { namespace dom { -JSWindowActorChild::JSWindowActorChild(nsIGlobalObject* aGlobal) - : mGlobal(aGlobal ? aGlobal - : xpc::NativeGlobal(xpc::PrivilegedJunkScope())) {} - JSWindowActorChild::~JSWindowActorChild() { MOZ_ASSERT(!mManager); } JSObject* JSWindowActorChild::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { return JSWindowActorChild_Binding::Wrap(aCx, this, aGivenProto); } WindowGlobalChild* JSWindowActorChild::GetManager() const { return mManager; } @@ -70,17 +66,17 @@ class AsyncMessageToParent : public Runn }; } // anonymous namespace void JSWindowActorChild::SendRawMessage(const JSActorMessageMeta& aMeta, ipc::StructuredCloneData&& aData, ipc::StructuredCloneData&& aStack, ErrorResult& aRv) { - if (NS_WARN_IF(!mCanSend || !mManager || !mManager->CanSend())) { + if (NS_WARN_IF(!CanSend() || !mManager || !mManager->CanSend())) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (mManager->IsInProcess()) { nsCOMPtr<nsIRunnable> runnable = new AsyncMessageToParent( aMeta, std::move(aData), std::move(aStack), mManager); NS_DispatchToMainThread(runnable.forget()); @@ -139,25 +135,17 @@ nsIDocShell* JSWindowActorChild::GetDocS Nullable<WindowProxyHolder> JSWindowActorChild::GetContentWindow( ErrorResult& aRv) { if (BrowsingContext* bc = GetBrowsingContext(aRv)) { return WindowProxyHolder(bc); } return nullptr; } -void JSWindowActorChild::StartDestroy() { - JSActor::StartDestroy(); - mCanSend = false; -} - -void JSWindowActorChild::AfterDestroy() { - JSActor::AfterDestroy(); - mManager = nullptr; -} +void JSWindowActorChild::ClearManager() { mManager = nullptr; } NS_IMPL_CYCLE_COLLECTION_INHERITED(JSWindowActorChild, JSActor, mManager) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(JSWindowActorChild, JSActor) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JSWindowActorChild) NS_INTERFACE_MAP_END_INHERITING(JSActor)
--- a/dom/ipc/jsactor/JSWindowActorChild.h +++ b/dom/ipc/jsactor/JSWindowActorChild.h @@ -34,49 +34,44 @@ namespace mozilla { namespace dom { class JSWindowActorChild final : public JSActor { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(JSWindowActorChild, JSActor) - explicit JSWindowActorChild(nsIGlobalObject* aGlobal = nullptr); - - nsIGlobalObject* GetParentObject() const override { return mGlobal; } + explicit JSWindowActorChild(nsISupports* aGlobal = nullptr) + : JSActor(aGlobal) {} JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; static already_AddRefed<JSWindowActorChild> Constructor( GlobalObject& aGlobal) { - nsCOMPtr<nsIGlobalObject> global( - do_QueryInterface(aGlobal.GetAsSupports())); - return MakeAndAddRef<JSWindowActorChild>(global); + return MakeAndAddRef<JSWindowActorChild>(aGlobal.GetAsSupports()); } WindowGlobalChild* GetManager() const; void Init(const nsACString& aName, WindowGlobalChild* aManager); - void StartDestroy(); - void AfterDestroy(); + void ClearManager() override; Document* GetDocument(ErrorResult& aRv); BrowsingContext* GetBrowsingContext(ErrorResult& aRv); nsIDocShell* GetDocShell(ErrorResult& aRv); Nullable<WindowProxyHolder> GetContentWindow(ErrorResult& aRv); protected: void SendRawMessage(const JSActorMessageMeta& aMeta, ipc::StructuredCloneData&& aData, ipc::StructuredCloneData&& aStack, ErrorResult& aRv) override; private: ~JSWindowActorChild(); - bool mCanSend = true; RefPtr<WindowGlobalChild> mManager; nsCOMPtr<nsIGlobalObject> mGlobal; }; } // namespace dom } // namespace mozilla
--- a/dom/ipc/jsactor/JSWindowActorParent.cpp +++ b/dom/ipc/jsactor/JSWindowActorParent.cpp @@ -11,20 +11,16 @@ #include "mozilla/dom/WindowGlobalParent.h" #include "mozilla/dom/MessageManagerBinding.h" namespace mozilla { namespace dom { JSWindowActorParent::~JSWindowActorParent() { MOZ_ASSERT(!mManager); } -nsIGlobalObject* JSWindowActorParent::GetParentObject() const { - return xpc::NativeGlobal(xpc::PrivilegedJunkScope()); -} - JSObject* JSWindowActorParent::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { return JSWindowActorParent_Binding::Wrap(aCx, this, aGivenProto); } WindowGlobalParent* JSWindowActorParent::GetManager() const { return mManager; } void JSWindowActorParent::Init(const nsACString& aName, @@ -67,17 +63,17 @@ class AsyncMessageToChild : public Runna }; } // anonymous namespace void JSWindowActorParent::SendRawMessage(const JSActorMessageMeta& aMeta, ipc::StructuredCloneData&& aData, ipc::StructuredCloneData&& aStack, ErrorResult& aRv) { - if (NS_WARN_IF(!mCanSend || !mManager || !mManager->CanSend())) { + if (NS_WARN_IF(!CanSend() || !mManager || !mManager->CanSend())) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (mManager->IsInProcess()) { nsCOMPtr<nsIRunnable> runnable = new AsyncMessageToChild( aMeta, std::move(aData), std::move(aStack), mManager); NS_DispatchToMainThread(runnable.forget()); @@ -112,25 +108,17 @@ CanonicalBrowsingContext* JSWindowActorP if (!mManager) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } return mManager->BrowsingContext(); } -void JSWindowActorParent::StartDestroy() { - JSActor::StartDestroy(); - mCanSend = false; -} - -void JSWindowActorParent::AfterDestroy() { - JSActor::AfterDestroy(); - mManager = nullptr; -} +void JSWindowActorParent::ClearManager() { mManager = nullptr; } NS_IMPL_CYCLE_COLLECTION_INHERITED(JSWindowActorParent, JSActor, mManager) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(JSWindowActorParent, JSActor) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JSWindowActorParent) NS_INTERFACE_MAP_END_INHERITING(JSActor)
--- a/dom/ipc/jsactor/JSWindowActorParent.h +++ b/dom/ipc/jsactor/JSWindowActorParent.h @@ -28,41 +28,40 @@ namespace mozilla { namespace dom { class JSWindowActorParent final : public JSActor { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(JSWindowActorParent, JSActor) + explicit JSWindowActorParent(nsISupports* aGlobal = nullptr) + : JSActor(aGlobal) {} + JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; static already_AddRefed<JSWindowActorParent> Constructor( GlobalObject& aGlobal) { - return MakeAndAddRef<JSWindowActorParent>(); + return MakeAndAddRef<JSWindowActorParent>(aGlobal.GetAsSupports()); } - nsIGlobalObject* GetParentObject() const override; - WindowGlobalParent* GetManager() const; void Init(const nsACString& aName, WindowGlobalParent* aManager); - void StartDestroy(); - void AfterDestroy(); + void ClearManager() override; CanonicalBrowsingContext* GetBrowsingContext(ErrorResult& aRv); protected: void SendRawMessage(const JSActorMessageMeta& aMeta, ipc::StructuredCloneData&& aData, ipc::StructuredCloneData&& aStack, ErrorResult& aRv) override; private: ~JSWindowActorParent(); - bool mCanSend = true; RefPtr<WindowGlobalParent> mManager; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_JSWindowActorParent_h
--- a/dom/ipc/jsactor/JSWindowActorProtocol.cpp +++ b/dom/ipc/jsactor/JSWindowActorProtocol.cpp @@ -174,26 +174,19 @@ NS_IMETHODIMP JSWindowActorProtocol::Han } RefPtr<WindowGlobalChild> wgc = inner->GetWindowGlobalChild(); if (NS_WARN_IF(!wgc)) { return NS_ERROR_FAILURE; } // Ensure our actor is present. - ErrorResult error; - RefPtr<JSWindowActorChild> actor = wgc->GetActor(mName, error); - if (error.Failed()) { - nsresult rv = error.StealNSResult(); - - // Don't raise an error if creation of our actor was vetoed. - if (rv == NS_ERROR_NOT_AVAILABLE) { - return NS_OK; - } - return rv; + RefPtr<JSActor> actor = wgc->GetActor(mName, IgnoreErrors()); + if (!actor) { + return NS_OK; } // Build our event listener & call it. JS::Rooted<JSObject*> global(RootingCx(), JS::GetNonCCWObjectGlobal(actor->GetWrapper())); RefPtr<EventListener> eventListener = new EventListener(actor->GetWrapper(), global, nullptr, nullptr); eventListener->HandleEvent(*aEvent, "JSWindowActorProtocol::HandleEvent"); @@ -218,26 +211,19 @@ NS_IMETHODIMP JSWindowActorProtocol::Obs wgc = inner->GetWindowGlobalChild(); } if (NS_WARN_IF(!wgc)) { return NS_ERROR_FAILURE; } // Ensure our actor is present. - ErrorResult error; - RefPtr<JSWindowActorChild> actor = wgc->GetActor(mName, error); - if (NS_WARN_IF(error.Failed())) { - nsresult rv = error.StealNSResult(); - - // Don't raise an error if creation of our actor was vetoed. - if (rv == NS_ERROR_NOT_AVAILABLE) { - return NS_OK; - } - return rv; + RefPtr<JSActor> actor = wgc->GetActor(mName, IgnoreErrors()); + if (!actor) { + return NS_OK; } // Build a observer callback. JS::Rooted<JSObject*> global(RootingCx(), JS::GetNonCCWObjectGlobal(actor->GetWrapper())); RefPtr<MozObserverCallback> observerCallback = new MozObserverCallback(actor->GetWrapper(), global, nullptr, nullptr); observerCallback->Observe(aSubject, nsDependentCString(aTopic),
--- a/dom/ipc/jsactor/JSWindowActorProtocol.h +++ b/dom/ipc/jsactor/JSWindowActorProtocol.h @@ -3,16 +3,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_JSWindowActorProtocol_h #define mozilla_dom_JSWindowActorProtocol_h #include "mozilla/dom/BrowsingContext.h" +#include "mozilla/dom/JSActorService.h" #include "mozilla/ErrorResult.h" #include "nsIURI.h" #include "nsString.h" #include "nsTArray.h" #include "nsIObserver.h" #include "nsIDOMEventListener.h" #include "mozilla/extensions/WebExtensionContentScript.h" @@ -26,51 +27,48 @@ class EventTarget; /** * Object corresponding to a single window actor protocol. This object acts as * an Event listener for the actor which is called for events which would * trigger actor creation. * * This object also can act as a carrier for methods and other state related to * a single protocol managed by the JSActorService. */ -class JSWindowActorProtocol final : public nsIObserver, +class JSWindowActorProtocol final : public JSActorProtocol, + public nsIObserver, public nsIDOMEventListener { public: NS_DECL_NSIOBSERVER NS_DECL_NSIDOMEVENTLISTENER NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(JSWindowActorProtocol, nsIObserver) static already_AddRefed<JSWindowActorProtocol> FromIPC( const JSWindowActorInfo& aInfo); JSWindowActorInfo ToIPC(); static already_AddRefed<JSWindowActorProtocol> FromWebIDLOptions( const nsACString& aName, const WindowActorOptions& aOptions, ErrorResult& aRv); - struct Sided { - Maybe<nsCString> mModuleURI; - }; - struct ParentSide : public Sided {}; struct EventDecl { nsString mName; EventListenerFlags mFlags; Optional<bool> mPassive; }; struct ChildSide : public Sided { nsTArray<EventDecl> mEvents; nsTArray<nsCString> mObservers; }; - const ParentSide& Parent() const { return mParent; } - const ChildSide& Child() const { return mChild; } + const ParentSide& Parent() const override { return mParent; } + const ChildSide& Child() const override { return mChild; } void RegisterListenersFor(EventTarget* aTarget); void UnregisterListenersFor(EventTarget* aTarget); void AddObservers(); void RemoveObservers(); bool Matches(BrowsingContext* aBrowsingContext, nsIURI* aURI, const nsAString& aRemoteType);
--- a/dom/ipc/jsactor/moz.build +++ b/dom/ipc/jsactor/moz.build @@ -1,35 +1,38 @@ # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS.mozilla.dom += [ 'JSActor.h', + 'JSActorManager.h', 'JSActorService.h', 'JSProcessActorChild.h', 'JSProcessActorParent.h', 'JSProcessActorProtocol.h', 'JSWindowActorChild.h', 'JSWindowActorParent.h', 'JSWindowActorProtocol.h', ] UNIFIED_SOURCES += [ 'JSActor.cpp', + 'JSActorManager.cpp', 'JSActorService.cpp', 'JSProcessActorChild.cpp', 'JSProcessActorParent.cpp', 'JSProcessActorProtocol.cpp', 'JSWindowActorChild.cpp', 'JSWindowActorParent.cpp', 'JSWindowActorProtocol.cpp', ] LOCAL_INCLUDES += [ + '/js/xpconnect/loader', '/js/xpconnect/src', ] include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul'