Bug 1457187 P1 Add a DOMMozPromiseRequestHolder helper class to auto-disconnect MozPromise Thenables when the global dies. r=baku
authorBen Kelly <ben@wanderview.com>
Thu, 26 Apr 2018 09:18:01 -0700
changeset 415841 184cbe8d02d950ffd9b678f0349c796f2e9170f9
parent 415840 f1c7ad9294b3c200d66590f0e7ddd8cf0c47f0cf
child 415842 4446fa7a754f1283e4a26124a507b648ec0e0a01
push id33910
push usershindli@mozilla.com
push dateThu, 26 Apr 2018 21:39:52 +0000
treeherdermozilla-central@63a0e2f626fe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1457187
milestone61.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 1457187 P1 Add a DOMMozPromiseRequestHolder helper class to auto-disconnect MozPromise Thenables when the global dies. r=baku
dom/base/DOMMozPromiseRequestHolder.h
dom/base/moz.build
new file mode 100644
--- /dev/null
+++ b/dom/base/DOMMozPromiseRequestHolder.h
@@ -0,0 +1,125 @@
+/* -*- 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_DOMMozPromiseRequestHolder_h
+#define mozilla_dom_DOMMozPromiseRequestHolder_h
+
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/MozPromise.h"
+
+namespace mozilla {
+namespace dom {
+
+/**
+ * This is a helper class that can be used when MozPromises are
+ * being consumed by binding layer code.  It effectively creates
+ * a MozPromiseRequestHolder that auto-disconnects when the binding's
+ * global is disconnected.
+ *
+ * It can be used like this:
+ *
+ *    RefPtr<Promise>
+ *    SomeAsyncAPI(Args& aArgs, ErrorResult& aRv)
+ *    {
+ *      nsIGlobalObject* global = GetParentObject();
+ *      if (!global) {
+ *        aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ *        return nullptr;
+ *      }
+ *
+ *      RefPtr<Promise> outer = Promise::Create(global, aRv);
+ *      if (aRv.Failed()) {
+ *        return nullptr;
+ *      }
+ *
+ *      RefPtr<DOMMozPromiseRequestHolder> holder =
+ *        new DOMMozPromiseRequestHolder(global);
+ *
+ *      DoAsyncStuff()->Then(
+ *        global->EventTargetFor(TaskCategory::Other), __func__,
+ *        [holder, outer] (const Result& aResult) {
+ *          holder->Complete();
+ *          outer->MaybeResolve(aResult);
+ *        }, [holder, outer] (nsresult aRv) {
+ *          holder->Complete();
+ *          outer->MaybeReject(aRv);
+ *        })->Track(*holder);
+ *
+ *      return outer.forget();
+ *    }
+ *
+ * NOTE: Currently this helper class extends DETH.  This is only
+ *       so that it can bind to the global and receive the
+ *       DisconnectFromOwner() method call.  In this future the
+ *       binding code should be factored out so DETH is not
+ *       needed here.  See bug 1456893.
+ */
+template<typename PromiseType>
+class DOMMozPromiseRequestHolder final : public DOMEventTargetHelper
+{
+  MozPromiseRequestHolder<PromiseType> mHolder;
+
+  ~DOMMozPromiseRequestHolder() = default;
+
+  void
+  DisconnectFromOwner() override
+  {
+    mHolder.DisconnectIfExists();
+    DOMEventTargetHelper::DisconnectFromOwner();
+  }
+
+  JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
+  {
+    // We are extending DETH to get notified when the global goes
+    // away, but this object should never actually be exposed to
+    // script.
+    MOZ_CRASH("illegal method");
+  }
+
+public:
+  explicit DOMMozPromiseRequestHolder(nsIGlobalObject* aGlobal)
+    : DOMEventTargetHelper(aGlobal)
+  {
+    MOZ_DIAGNOSTIC_ASSERT(aGlobal);
+  }
+
+  operator MozPromiseRequestHolder<PromiseType>& ()
+  {
+    return mHolder;
+  }
+
+  operator const MozPromiseRequestHolder<PromiseType>& () const
+  {
+    return mHolder;
+  }
+
+  void
+  Complete()
+  {
+    mHolder.Complete();
+    DisconnectFromOwner();
+  }
+
+  void
+  DisconnectIfExists()
+  {
+    mHolder.DisconnectIfExists();
+  }
+
+  bool
+  Exists() const
+  {
+    return mHolder.Exists();
+  }
+
+  NS_INLINE_DECL_REFCOUNTING_INHERITED(DOMMozPromiseRequestHolder, DOMEventTargetHelper)
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_DOMMozPromiseRequestHolder_h
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -164,16 +164,17 @@ EXPORTS.mozilla.dom += [
     'DocumentFragment.h',
     'DocumentOrShadowRoot.h',
     'DocumentType.h',
     'DOMError.h',
     'DOMException.h',
     'DOMImplementation.h',
     'DOMIntersectionObserver.h',
     'DOMMatrix.h',
+    'DOMMozPromiseRequestHolder.h',
     'DOMParser.h',
     'DOMPoint.h',
     'DOMPrefs.h',
     'DOMPrefsInternal.h',
     'DOMQuad.h',
     'DOMRect.h',
     'DOMRequest.h',
     'DOMStringList.h',