Bug 1538979 - Part 2: Add WillDestroy and DidDestroy lifecycle methods on JSWindowActor; r=nika
☠☠ backed out by 012ce6437a4c ☠ ☠
authorJohn Dai <jdai@mozilla.com>
Fri, 10 May 2019 09:19:30 +0000
changeset 532182 8e065761738c199fc06388dcfc22df7e92827152
parent 532181 9df2b856b6550578f75d862a1fb4579b5665742e
child 532183 a098226e42117f59f17112ed7be9e39710e18681
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika
bugs1538979
milestone68.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
Bug 1538979 - Part 2: Add WillDestroy and DidDestroy lifecycle methods on JSWindowActor; r=nika Differential Revision: https://phabricator.services.mozilla.com/D30196
dom/chrome-webidl/JSWindowActor.webidl
dom/ipc/JSWindowActor.cpp
dom/ipc/JSWindowActor.h
dom/ipc/JSWindowActorChild.cpp
dom/ipc/JSWindowActorParent.cpp
--- a/dom/chrome-webidl/JSWindowActor.webidl
+++ b/dom/chrome-webidl/JSWindowActor.webidl
@@ -46,8 +46,17 @@ JSWindowActorChild implements JSWindowAc
 // WebIDL callback interface version of the nsIObserver interface for use when
 // calling the observe method on JSWindowActors.
 //
 // NOTE: This isn't marked as ChromeOnly, as it has no interface object, and
 // thus cannot be conditionally exposed.
 callback interface MozObserverCallback {
   void observe(nsISupports subject, ByteString topic, DOMString? data);
 };
+
+// WebIDL callback interface calling the `willDestroy` and `didDestroy`
+// method on JSWindowActors.
+callback MozActorDestroyCallback = void();
+
+dictionary MozActorDestroyCallbacks {
+  [ChromeOnly] MozActorDestroyCallback willDestroy;
+  [ChromeOnly] MozActorDestroyCallback didDestroy;
+};
--- a/dom/ipc/JSWindowActor.cpp
+++ b/dom/ipc/JSWindowActor.cpp
@@ -34,16 +34,47 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(JSWindowActor)
 
 JSWindowActor::JSWindowActor() : mNextQueryId(0) {}
 
 nsIGlobalObject* JSWindowActor::GetParentObject() const {
   return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
 }
 
+void JSWindowActor::StartDestroy() {
+  DestroyCallback(DestroyCallbackFunction::WillDestroy);
+}
+
+void JSWindowActor::AfterDestroy() {
+  DestroyCallback(DestroyCallbackFunction::DidDestroy);
+}
+
+void JSWindowActor::DestroyCallback(DestroyCallbackFunction callback) {
+  AutoEntryScript aes(xpc::PrivilegedJunkScope(),
+                      "JSWindowActor destroy callback");
+  JSContext* cx = aes.cx();
+  MozActorDestroyCallbacks callbacksHolder;
+  NS_ENSURE_TRUE_VOID(GetWrapper());
+  JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*GetWrapper()));
+  if (NS_WARN_IF(!callbacksHolder.Init(cx, val))) {
+    return;
+  }
+
+  // Destroy callback is optional.
+  if (callback == DestroyCallbackFunction::WillDestroy) {
+    if (callbacksHolder.mWillDestroy.WasPassed()) {
+      callbacksHolder.mWillDestroy.Value()->Call();
+    }
+  } else {
+    if (callbacksHolder.mDidDestroy.WasPassed()) {
+      callbacksHolder.mDidDestroy.Value()->Call();
+    }
+  }
+}
+
 void JSWindowActor::RejectPendingQueries() {
   // 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);
   }
--- a/dom/ipc/JSWindowActor.h
+++ b/dom/ipc/JSWindowActor.h
@@ -34,16 +34,17 @@ class QueryPromiseHandler;
 class JSWindowActor : public nsISupports, public nsWrapperCache {
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(JSWindowActor)
 
   JSWindowActor();
 
   enum class Type { Parent, Child };
+  enum class DestroyCallbackFunction { WillDestroy, DidDestroy };
 
   const nsString& Name() const { return mName; }
 
   void SendAsyncMessage(JSContext* aCx, const nsAString& aMessageName,
                         JS::Handle<JS::Value> aObj,
                         JS::Handle<JS::Value> aTransfers, ErrorResult& aRv);
 
   already_AddRefed<Promise> SendQuery(JSContext* aCx,
@@ -66,16 +67,22 @@ class JSWindowActor : public nsISupports
   virtual void SendRawMessage(const JSWindowActorMessageMeta& aMetadata,
                               ipc::StructuredCloneData&& aData,
                               ErrorResult& aRv) = 0;
 
   virtual ~JSWindowActor() = default;
 
   void SetName(const nsAString& aName);
 
+  void StartDestroy();
+
+  void AfterDestroy();
+
+  void DestroyCallback(DestroyCallbackFunction willDestroy);
+
  private:
   void ReceiveMessageOrQuery(JSContext* aCx,
                              const JSWindowActorMessageMeta& aMetadata,
                              JS::Handle<JS::Value> aData, ErrorResult& aRv);
 
   void ReceiveQueryReply(JSContext* aCx,
                          const JSWindowActorMessageMeta& aMetadata,
                          JS::Handle<JS::Value> aData, ErrorResult& aRv);
--- a/dom/ipc/JSWindowActorChild.cpp
+++ b/dom/ipc/JSWindowActorChild.cpp
@@ -110,20 +110,22 @@ Nullable<WindowProxyHolder> JSWindowActo
     ErrorResult& aRv) {
   if (BrowsingContext* bc = GetBrowsingContext(aRv)) {
     return WindowProxyHolder(bc);
   }
   return nullptr;
 }
 
 void JSWindowActorChild::StartDestroy() {
+  JSWindowActor::StartDestroy();
   mCanSend = false;
 }
 
 void JSWindowActorChild::AfterDestroy() {
+  JSWindowActor::AfterDestroy();
   mManager = nullptr;
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(JSWindowActorChild, JSWindowActor, mManager)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(JSWindowActorChild,
                                                JSWindowActor)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
--- a/dom/ipc/JSWindowActorParent.cpp
+++ b/dom/ipc/JSWindowActorParent.cpp
@@ -81,20 +81,22 @@ void JSWindowActorParent::SendRawMessage
 
   if (NS_WARN_IF(!mManager->SendRawMessage(aMeta, msgData))) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
 }
 
 void JSWindowActorParent::StartDestroy() {
+  JSWindowActor::StartDestroy();
   mCanSend = false;
 }
 
 void JSWindowActorParent::AfterDestroy() {
+  JSWindowActor::AfterDestroy();
   mManager = nullptr;
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(JSWindowActorParent, JSWindowActor, mManager)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(JSWindowActorParent,
                                                JSWindowActor)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END