LCOV - code coverage report
Current view: top level - xpcom/threads - MozPromise.h (source / functions) Hit Total Coverage
Test: output.info Lines: 234 444 52.7 %
Date: 2017-07-14 16:53:18 Functions: 159 5122 3.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #if !defined(MozPromise_h_)
       8             : #define MozPromise_h_
       9             : 
      10             : #include "mozilla/IndexSequence.h"
      11             : #include "mozilla/Logging.h"
      12             : #include "mozilla/Maybe.h"
      13             : #include "mozilla/Mutex.h"
      14             : #include "mozilla/Monitor.h"
      15             : #include "mozilla/Tuple.h"
      16             : #include "mozilla/TypeTraits.h"
      17             : #include "mozilla/Variant.h"
      18             : 
      19             : #include "nsISerialEventTarget.h"
      20             : #include "nsTArray.h"
      21             : #include "nsThreadUtils.h"
      22             : 
      23             : #if MOZ_DIAGNOSTIC_ASSERT_ENABLED
      24             : #define PROMISE_DEBUG
      25             : #endif
      26             : 
      27             : #ifdef PROMISE_DEBUG
      28             : #define PROMISE_ASSERT MOZ_RELEASE_ASSERT
      29             : #else
      30             : #define PROMISE_ASSERT(...) do { } while (0)
      31             : #endif
      32             : 
      33             : namespace mozilla {
      34             : 
      35             : extern LazyLogModule gMozPromiseLog;
      36             : 
      37             : #define PROMISE_LOG(x, ...) \
      38             :   MOZ_LOG(gMozPromiseLog, mozilla::LogLevel::Debug, (x, ##__VA_ARGS__))
      39             : 
      40             : namespace detail {
      41             : template <typename F>
      42             : struct MethodTraitsHelper : MethodTraitsHelper<decltype(&F::operator())>
      43             : {
      44             : };
      45             : template <typename ThisType, typename Ret, typename... ArgTypes>
      46             : struct MethodTraitsHelper<Ret(ThisType::*)(ArgTypes...)>
      47             : {
      48             :   using ReturnType = Ret;
      49             :   static const size_t ArgSize = sizeof...(ArgTypes);
      50             : };
      51             : template <typename ThisType, typename Ret, typename... ArgTypes>
      52             : struct MethodTraitsHelper<Ret(ThisType::*)(ArgTypes...) const>
      53             : {
      54             :   using ReturnType = Ret;
      55             :   static const size_t ArgSize = sizeof...(ArgTypes);
      56             : };
      57             : template <typename ThisType, typename Ret, typename... ArgTypes>
      58             : struct MethodTraitsHelper<Ret(ThisType::*)(ArgTypes...) volatile>
      59             : {
      60             :   using ReturnType = Ret;
      61             :   static const size_t ArgSize = sizeof...(ArgTypes);
      62             : };
      63             : template <typename ThisType, typename Ret, typename... ArgTypes>
      64             : struct MethodTraitsHelper<Ret(ThisType::*)(ArgTypes...) const volatile>
      65             : {
      66             :   using ReturnType = Ret;
      67             :   static const size_t ArgSize = sizeof...(ArgTypes);
      68             : };
      69             : template <typename T>
      70             : struct MethodTrait : MethodTraitsHelper<typename RemoveReference<T>::Type>
      71             : {
      72             : };
      73             : 
      74             : } // namespace detail
      75             : 
      76             : template<typename MethodType>
      77             : using TakesArgument =
      78             :   IntegralConstant<bool, detail::MethodTrait<MethodType>::ArgSize != 0>;
      79             : 
      80             : template<typename MethodType, typename TargetType>
      81             : using ReturnTypeIs =
      82             :   IsConvertible<typename detail::MethodTrait<MethodType>::ReturnType, TargetType>;
      83             : 
      84             : template<typename ResolveValueT, typename RejectValueT, bool IsExclusive>
      85             : class MozPromise;
      86             : 
      87             : template<typename Return>
      88             : struct IsMozPromise : FalseType
      89             : {
      90             : };
      91             : 
      92             : template<typename ResolveValueT, typename RejectValueT, bool IsExclusive>
      93             : struct IsMozPromise<MozPromise<ResolveValueT, RejectValueT, IsExclusive>>
      94             :   : TrueType
      95             : {
      96             : };
      97             : 
      98             : /*
      99             :  * A promise manages an asynchronous request that may or may not be able to be
     100             :  * fulfilled immediately. When an API returns a promise, the consumer may attach
     101             :  * callbacks to be invoked (asynchronously, on a specified thread) when the
     102             :  * request is either completed (resolved) or cannot be completed (rejected).
     103             :  * Whereas JS promise callbacks are dispatched from Microtask checkpoints,
     104             :  * MozPromises resolution/rejection make a normal round-trip through the event
     105             :  * loop, which simplifies their ordering semantics relative to other native code.
     106             :  *
     107             :  * MozPromises attempt to mirror the spirit of JS Promises to the extent that
     108             :  * is possible (and desirable) in C++. While the intent is that MozPromises
     109             :  * feel familiar to programmers who are accustomed to their JS-implemented cousin,
     110             :  * we don't shy away from imposing restrictions and adding features that make
     111             :  * sense for the use cases we encounter.
     112             :  *
     113             :  * A MozPromise is ThreadSafe, and may be ->Then()ed on any thread. The Then()
     114             :  * call accepts resolve and reject callbacks, and returns a magic object which
     115             :  * will be implicitly converted to a MozPromise::Request or a MozPromise object
     116             :  * depending on how the return value is used. The magic object serves several
     117             :  * purposes for the consumer.
     118             :  *
     119             :  *   (1) When converting to a MozPromise::Request, it allows the caller to
     120             :  *       cancel the delivery of the resolve/reject value if it has not already
     121             :  *       occurred, via Disconnect() (this must be done on the target thread to
     122             :  *       avoid racing).
     123             :  *
     124             :  *   (2) When converting to a MozPromise (which is called a completion promise),
     125             :  *       it allows promise chaining so ->Then() can be called again to attach
     126             :  *       more resolve and reject callbacks. If the resolve/reject callback
     127             :  *       returns a new MozPromise, that promise is chained to the completion
     128             :  *       promise, such that its resolve/reject value will be forwarded along
     129             :  *       when it arrives. If the resolve/reject callback returns void, the
     130             :  *       completion promise is resolved/rejected with the same value that was
     131             :  *       passed to the callback.
     132             :  *
     133             :  * The MozPromise APIs skirt traditional XPCOM convention by returning nsRefPtrs
     134             :  * (rather than already_AddRefed) from various methods. This is done to allow elegant
     135             :  * chaining of calls without cluttering up the code with intermediate variables, and
     136             :  * without introducing separate API variants for callers that want a return value
     137             :  * (from, say, ->Then()) from those that don't.
     138             :  *
     139             :  * When IsExclusive is true, the MozPromise does a release-mode assertion that
     140             :  * there is at most one call to either Then(...) or ChainTo(...).
     141             :  */
     142             : 
     143          19 : class MozPromiseRefcountable
     144             : {
     145             : public:
     146         100 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozPromiseRefcountable)
     147             : protected:
     148          19 :   virtual ~MozPromiseRefcountable() {}
     149             : };
     150             : 
     151          26 : class MozPromiseBase : public MozPromiseRefcountable
     152             : {
     153             : public:
     154             :   virtual void AssertIsDead() = 0;
     155             : };
     156             : 
     157             : template<typename T> class MozPromiseHolder;
     158             : template<typename T> class MozPromiseRequestHolder;
     159             : template<typename ResolveValueT, typename RejectValueT, bool IsExclusive>
     160             : class MozPromise : public MozPromiseBase
     161             : {
     162             :   static const uint32_t sMagic = 0xcecace11;
     163             : 
     164             :   // Return a |T&&| to enable move when IsExclusive is true or
     165             :   // a |const T&| to enforce copy otherwise.
     166             :   template <typename T,
     167             :     typename R = typename Conditional<IsExclusive, T&&, const T&>::Type>
     168          11 :   static R MaybeMove(T& aX)
     169             :   {
     170          11 :     return static_cast<R>(aX);
     171             :   }
     172             : 
     173             : public:
     174             :   typedef ResolveValueT ResolveValueType;
     175             :   typedef RejectValueT RejectValueType;
     176          26 :   class ResolveOrRejectValue
     177             :   {
     178             :   public:
     179             :     template<typename ResolveValueType_>
     180          13 :     void SetResolve(ResolveValueType_&& aResolveValue)
     181             :     {
     182          13 :       MOZ_ASSERT(IsNothing());
     183          13 :       mValue = Storage(VariantIndex<ResolveIndex>{},
     184             :                        Forward<ResolveValueType_>(aResolveValue));
     185          13 :     }
     186             : 
     187             :     template<typename RejectValueType_>
     188           0 :     void SetReject(RejectValueType_&& aRejectValue)
     189             :     {
     190           0 :       MOZ_ASSERT(IsNothing());
     191           0 :       mValue = Storage(VariantIndex<RejectIndex>{},
     192             :                        Forward<RejectValueType_>(aRejectValue));
     193           0 :     }
     194             : 
     195             :     template<typename ResolveValueType_>
     196             :     static ResolveOrRejectValue MakeResolve(ResolveValueType_&& aResolveValue)
     197             :     {
     198             :       ResolveOrRejectValue val;
     199             :       val.SetResolve(Forward<ResolveValueType_>(aResolveValue));
     200             :       return val;
     201             :     }
     202             : 
     203             :     template<typename RejectValueType_>
     204             :     static ResolveOrRejectValue MakeReject(RejectValueType_&& aRejectValue)
     205             :     {
     206             :       ResolveOrRejectValue val;
     207             :       val.SetReject(Forward<RejectValueType_>(aRejectValue));
     208             :       return val;
     209             :     }
     210             : 
     211          11 :     bool IsResolve() const { return mValue.template is<ResolveIndex>(); }
     212             :     bool IsReject() const { return mValue.template is<RejectIndex>(); }
     213          71 :     bool IsNothing() const { return mValue.template is<NothingIndex>(); }
     214             : 
     215             :     const ResolveValueType& ResolveValue() const
     216             :     {
     217             :       return mValue.template as<ResolveIndex>();
     218             :     }
     219          11 :     ResolveValueType& ResolveValue()
     220             :     {
     221          11 :       return mValue.template as<ResolveIndex>();
     222             :     }
     223             :     const RejectValueType& RejectValue() const
     224             :     {
     225             :       return mValue.template as<RejectIndex>();
     226             :     }
     227           0 :     RejectValueType& RejectValue()
     228             :     {
     229           0 :       return mValue.template as<RejectIndex>();
     230             :     }
     231             : 
     232             :   private:
     233             :     enum { NothingIndex, ResolveIndex, RejectIndex };
     234             :     using Storage = Variant<Nothing, ResolveValueType, RejectValueType>;
     235             :     Storage mValue = Storage(VariantIndex<NothingIndex>{});
     236             :   };
     237             : 
     238             : protected:
     239             :   // MozPromise is the public type, and never constructed directly. Construct
     240             :   // a MozPromise::Private, defined below.
     241          13 :   MozPromise(const char* aCreationSite, bool aIsCompletionPromise)
     242             :     : mCreationSite(aCreationSite)
     243             :     , mMutex("MozPromise Mutex")
     244             :     , mHaveRequest(false)
     245             :     , mIsCompletionPromise(aIsCompletionPromise)
     246             : #ifdef PROMISE_DEBUG
     247          13 :     , mMagic4(&mMutex)
     248             : #endif
     249             :   {
     250          13 :     PROMISE_LOG("%s creating MozPromise (%p)", mCreationSite, this);
     251          13 :   }
     252             : 
     253             : public:
     254             :   // MozPromise::Private allows us to separate the public interface (upon which
     255             :   // consumers of the promise may invoke methods like Then()) from the private
     256             :   // interface (upon which the creator of the promise may invoke Resolve() or
     257             :   // Reject()). APIs should create and store a MozPromise::Private (usually
     258             :   // via a MozPromiseHolder), and return a MozPromise to consumers.
     259             :   //
     260             :   // NB: We can include the definition of this class inline once B2G ICS is gone.
     261             :   class Private;
     262             : 
     263             :   template<typename ResolveValueType_>
     264             :   static RefPtr<MozPromise>
     265           4 :   CreateAndResolve(ResolveValueType_&& aResolveValue, const char* aResolveSite)
     266             :   {
     267           8 :     RefPtr<typename MozPromise::Private> p = new MozPromise::Private(aResolveSite);
     268           4 :     p->Resolve(Forward<ResolveValueType_>(aResolveValue), aResolveSite);
     269           8 :     return p.forget();
     270             :   }
     271             : 
     272             :   template<typename RejectValueType_>
     273             :   static RefPtr<MozPromise>
     274           0 :   CreateAndReject(RejectValueType_&& aRejectValue, const char* aRejectSite)
     275             :   {
     276           0 :     RefPtr<typename MozPromise::Private> p = new MozPromise::Private(aRejectSite);
     277           0 :     p->Reject(Forward<RejectValueType_>(aRejectValue), aRejectSite);
     278           0 :     return p.forget();
     279             :   }
     280             : 
     281             :   typedef MozPromise<nsTArray<ResolveValueType>, RejectValueType, IsExclusive> AllPromiseType;
     282             : private:
     283           0 :   class AllPromiseHolder : public MozPromiseRefcountable
     284             :   {
     285             :   public:
     286           0 :     explicit AllPromiseHolder(size_t aDependentPromises)
     287           0 :       : mPromise(new typename AllPromiseType::Private(__func__))
     288           0 :       , mOutstandingPromises(aDependentPromises)
     289             :     {
     290           0 :       MOZ_ASSERT(aDependentPromises > 0);
     291           0 :       mResolveValues.SetLength(aDependentPromises);
     292           0 :     }
     293             : 
     294           0 :     void Resolve(size_t aIndex, ResolveValueType&& aResolveValue)
     295             :     {
     296           0 :       if (!mPromise) {
     297             :         // Already rejected.
     298           0 :         return;
     299             :       }
     300             : 
     301           0 :       mResolveValues[aIndex].emplace(Move(aResolveValue));
     302           0 :       if (--mOutstandingPromises == 0) {
     303           0 :         nsTArray<ResolveValueType> resolveValues;
     304           0 :         resolveValues.SetCapacity(mResolveValues.Length());
     305           0 :         for (size_t i = 0; i < mResolveValues.Length(); ++i) {
     306           0 :           resolveValues.AppendElement(Move(mResolveValues[i].ref()));
     307             :         }
     308             : 
     309           0 :         mPromise->Resolve(Move(resolveValues), __func__);
     310           0 :         mPromise = nullptr;
     311           0 :         mResolveValues.Clear();
     312             :       }
     313             :     }
     314             : 
     315           0 :     void Reject(RejectValueType&& aRejectValue)
     316             :     {
     317           0 :       if (!mPromise) {
     318             :         // Already rejected.
     319           0 :         return;
     320             :       }
     321             : 
     322           0 :       mPromise->Reject(Move(aRejectValue), __func__);
     323           0 :       mPromise = nullptr;
     324           0 :       mResolveValues.Clear();
     325             :     }
     326             : 
     327           0 :     AllPromiseType* Promise() { return mPromise; }
     328             : 
     329             :   private:
     330             :     nsTArray<Maybe<ResolveValueType>> mResolveValues;
     331             :     RefPtr<typename AllPromiseType::Private> mPromise;
     332             :     size_t mOutstandingPromises;
     333             :   };
     334             : public:
     335             : 
     336           0 :   static RefPtr<AllPromiseType> All(nsISerialEventTarget* aProcessingTarget, nsTArray<RefPtr<MozPromise>>& aPromises)
     337             :   {
     338           0 :     if (aPromises.Length() == 0) {
     339           0 :       return AllPromiseType::CreateAndResolve(nsTArray<ResolveValueType>(), __func__);
     340             :     }
     341             : 
     342           0 :     RefPtr<AllPromiseHolder> holder = new AllPromiseHolder(aPromises.Length());
     343           0 :     for (size_t i = 0; i < aPromises.Length(); ++i) {
     344           0 :       aPromises[i]->Then(aProcessingTarget, __func__,
     345           0 :         [holder, i] (ResolveValueType aResolveValue) -> void { holder->Resolve(i, Move(aResolveValue)); },
     346           0 :         [holder] (RejectValueType aRejectValue) -> void { holder->Reject(Move(aRejectValue)); }
     347             :       );
     348             :     }
     349           0 :     return holder->Promise();
     350             :   }
     351             : 
     352             :   class Request : public MozPromiseRefcountable
     353             :   {
     354             :   public:
     355             :     virtual void Disconnect() = 0;
     356             : 
     357             :   protected:
     358           6 :     Request() : mComplete(false), mDisconnected(false) {}
     359           6 :     virtual ~Request() {}
     360             : 
     361             :     bool mComplete;
     362             :     bool mDisconnected;
     363             :   };
     364             : 
     365             : protected:
     366             : 
     367             :   /*
     368             :    * A ThenValue tracks a single consumer waiting on the promise. When a consumer
     369             :    * invokes promise->Then(...), a ThenValue is created. Once the Promise is
     370             :    * resolved or rejected, a {Resolve,Reject}Runnable is dispatched, which
     371             :    * invokes the resolve/reject method and then deletes the ThenValue.
     372             :    */
     373             :   class ThenValueBase : public Request
     374             :   {
     375             :     friend class MozPromise;
     376             :     static const uint32_t sMagic = 0xfadece11;
     377             : 
     378             :   public:
     379             :     class ResolveOrRejectRunnable : public CancelableRunnable
     380             :     {
     381             :     public:
     382           6 :       ResolveOrRejectRunnable(ThenValueBase* aThenValue, MozPromise* aPromise)
     383             :         : CancelableRunnable(
     384             :             "MozPromise::ThenValueBase::ResolveOrRejectRunnable")
     385             :         , mThenValue(aThenValue)
     386           6 :         , mPromise(aPromise)
     387             :       {
     388           6 :         MOZ_DIAGNOSTIC_ASSERT(!mPromise->IsPending());
     389           6 :       }
     390             : 
     391          12 :       ~ResolveOrRejectRunnable()
     392             :       {
     393           6 :         if (mThenValue) {
     394           0 :           mThenValue->AssertIsDead();
     395             :         }
     396          24 :       }
     397             : 
     398           6 :       NS_IMETHOD Run() override
     399             :       {
     400           6 :         PROMISE_LOG("ResolveOrRejectRunnable::Run() [this=%p]", this);
     401           6 :         mThenValue->DoResolveOrReject(mPromise->Value());
     402           6 :         mThenValue = nullptr;
     403           6 :         mPromise = nullptr;
     404           6 :         return NS_OK;
     405             :       }
     406             : 
     407           0 :       nsresult Cancel() override
     408             :       {
     409           0 :         return Run();
     410             :       }
     411             : 
     412             :     private:
     413             :       RefPtr<ThenValueBase> mThenValue;
     414             :       RefPtr<MozPromise> mPromise;
     415             :     };
     416             : 
     417           6 :     ThenValueBase(nsISerialEventTarget* aResponseTarget,
     418             :                   const char* aCallSite)
     419             :       : mResponseTarget(aResponseTarget)
     420           6 :       , mCallSite(aCallSite)
     421             :     {
     422           6 :       MOZ_ASSERT(aResponseTarget);
     423           6 :     }
     424             : 
     425             : #ifdef PROMISE_DEBUG
     426           6 :     ~ThenValueBase()
     427             :     {
     428           6 :       mMagic1 = 0;
     429           6 :       mMagic2 = 0;
     430          12 :     }
     431             : #endif
     432             : 
     433           0 :     void AssertIsDead()
     434             :     {
     435           0 :       PROMISE_ASSERT(mMagic1 == sMagic && mMagic2 == sMagic);
     436             :       // We want to assert that this ThenValues is dead - that is to say, that
     437             :       // there are no consumers waiting for the result. In the case of a normal
     438             :       // ThenValue, we check that it has been disconnected, which is the way
     439             :       // that the consumer signals that it no longer wishes to hear about the
     440             :       // result. If this ThenValue has a completion promise (which is mutually
     441             :       // exclusive with being disconnectable), we recursively assert that every
     442             :       // ThenValue associated with the completion promise is dead.
     443           0 :       if (MozPromiseBase* p = CompletionPromise()) {
     444           0 :         p->AssertIsDead();
     445             :       } else {
     446           0 :         MOZ_DIAGNOSTIC_ASSERT(Request::mDisconnected);
     447             :       }
     448           0 :     }
     449             : 
     450           6 :     void Dispatch(MozPromise *aPromise)
     451             :     {
     452           6 :       PROMISE_ASSERT(mMagic1 == sMagic && mMagic2 == sMagic);
     453           6 :       aPromise->mMutex.AssertCurrentThreadOwns();
     454           6 :       MOZ_ASSERT(!aPromise->IsPending());
     455             : 
     456          12 :       nsCOMPtr<nsIRunnable> r = new ResolveOrRejectRunnable(this, aPromise);
     457           6 :       PROMISE_LOG("%s Then() call made from %s [Runnable=%p, Promise=%p, ThenValue=%p]",
     458             :                   aPromise->mValue.IsResolve() ? "Resolving" : "Rejecting", mCallSite,
     459             :                   r.get(), aPromise, this);
     460             : 
     461             :       // Promise consumers are allowed to disconnect the Request object and
     462             :       // then shut down the thread or task queue that the promise result would
     463             :       // be dispatched on. So we unfortunately can't assert that promise
     464             :       // dispatch succeeds. :-(
     465           6 :       mResponseTarget->Dispatch(r.forget());
     466           6 :     }
     467             : 
     468           0 :     void Disconnect() override
     469             :     {
     470           0 :       MOZ_DIAGNOSTIC_ASSERT(mResponseTarget->IsOnCurrentThread());
     471           0 :       MOZ_DIAGNOSTIC_ASSERT(!Request::mComplete);
     472           0 :       Request::mDisconnected = true;
     473             : 
     474             :       // We could support rejecting the completion promise on disconnection, but
     475             :       // then we'd need to have some sort of default reject value. The use cases
     476             :       // of disconnection and completion promise chaining seem pretty orthogonal,
     477             :       // so let's use assert against it.
     478           0 :       MOZ_DIAGNOSTIC_ASSERT(!CompletionPromise());
     479           0 :     }
     480             : 
     481             :   protected:
     482             :     virtual MozPromiseBase* CompletionPromise() const = 0;
     483             :     virtual void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) = 0;
     484             : 
     485           6 :     void DoResolveOrReject(ResolveOrRejectValue& aValue)
     486             :     {
     487           6 :       PROMISE_ASSERT(mMagic1 == sMagic && mMagic2 == sMagic);
     488           6 :       MOZ_DIAGNOSTIC_ASSERT(mResponseTarget->IsOnCurrentThread());
     489           6 :       Request::mComplete = true;
     490           6 :       if (Request::mDisconnected) {
     491           0 :         PROMISE_LOG("ThenValue::DoResolveOrReject disconnected - bailing out [this=%p]", this);
     492           0 :         return;
     493             :       }
     494             : 
     495             :       // Invoke the resolve or reject method.
     496           6 :       DoResolveOrRejectInternal(aValue);
     497             :     }
     498             : 
     499             :     nsCOMPtr<nsISerialEventTarget> mResponseTarget; // May be released on any thread.
     500             : #ifdef PROMISE_DEBUG
     501             :     uint32_t mMagic1 = sMagic;
     502             : #endif
     503             :     const char* mCallSite;
     504             : #ifdef PROMISE_DEBUG
     505             :     uint32_t mMagic2 = sMagic;
     506             : #endif
     507             :   };
     508             : 
     509             :   /*
     510             :    * We create two overloads for invoking Resolve/Reject Methods so as to
     511             :    * make the resolve/reject value argument "optional".
     512             :    */
     513             :   template<typename ThisType, typename MethodType, typename ValueType>
     514             :   static typename EnableIf<
     515             :     TakesArgument<MethodType>::value,
     516             :     typename detail::MethodTrait<MethodType>::ReturnType>::Type
     517           2 :   InvokeMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue)
     518             :   {
     519           2 :     return (aThisVal->*aMethod)(Forward<ValueType>(aValue));
     520             :   }
     521             : 
     522             :   template<typename ThisType, typename MethodType, typename ValueType>
     523             :   static typename EnableIf<
     524             :     !TakesArgument<MethodType>::value,
     525             :     typename detail::MethodTrait<MethodType>::ReturnType>::Type
     526           4 :   InvokeMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue)
     527             :   {
     528           4 :     return (aThisVal->*aMethod)();
     529             :   }
     530             : 
     531             :   // Called when promise chaining is supported.
     532             :   template<bool SupportChaining,
     533             :            typename ThisType,
     534             :            typename MethodType,
     535             :            typename ValueType,
     536             :            typename CompletionPromiseType>
     537           2 :   static typename EnableIf<SupportChaining, void>::Type InvokeCallbackMethod(
     538             :     ThisType* aThisVal,
     539             :     MethodType aMethod,
     540             :     ValueType&& aValue,
     541             :     CompletionPromiseType&& aCompletionPromise)
     542             :   {
     543           4 :     auto p = InvokeMethod(aThisVal, aMethod, Forward<ValueType>(aValue));
     544           2 :     if (aCompletionPromise) {
     545           2 :       p->ChainTo(aCompletionPromise.forget(), "<chained completion promise>");
     546             :     }
     547           2 :   }
     548             : 
     549             :   // Called when promise chaining is not supported.
     550             :   template<bool SupportChaining,
     551             :            typename ThisType,
     552             :            typename MethodType,
     553             :            typename ValueType,
     554             :            typename CompletionPromiseType>
     555           4 :   static typename EnableIf<!SupportChaining, void>::Type InvokeCallbackMethod(
     556             :     ThisType* aThisVal,
     557             :     MethodType aMethod,
     558             :     ValueType&& aValue,
     559             :     CompletionPromiseType&& aCompletionPromise)
     560             :   {
     561           4 :     MOZ_DIAGNOSTIC_ASSERT(
     562             :       !aCompletionPromise,
     563             :       "Can't do promise chaining for a non-promise-returning method.");
     564           4 :     InvokeMethod(aThisVal, aMethod, Forward<ValueType>(aValue));
     565           4 :   }
     566             : 
     567             :   template<typename>
     568             :   class ThenCommand;
     569             : 
     570             :   template<typename...>
     571             :   class ThenValue;
     572             : 
     573             :   template<typename ThisType,
     574             :            typename ResolveMethodType,
     575             :            typename RejectMethodType>
     576           0 :   class ThenValue<ThisType*, ResolveMethodType, RejectMethodType>
     577             :     : public ThenValueBase
     578             :   {
     579             :     friend class ThenCommand<ThenValue>;
     580             : 
     581             :     using R1 = typename RemoveSmartPointer<
     582             :       typename detail::MethodTrait<ResolveMethodType>::ReturnType>::Type;
     583             :     using R2 = typename RemoveSmartPointer<
     584             :       typename detail::MethodTrait<RejectMethodType>::ReturnType>::Type;
     585             :     using SupportChaining =
     586             :       IntegralConstant<bool, IsMozPromise<R1>::value && IsSame<R1, R2>::value>;
     587             : 
     588             :     // Fall back to MozPromise when promise chaining is not supported to make code compile.
     589             :     using PromiseType =
     590             :       typename Conditional<SupportChaining::value, R1, MozPromise>::Type;
     591             : 
     592             :   public:
     593           0 :     ThenValue(nsISerialEventTarget* aResponseTarget,
     594             :               ThisType* aThisVal,
     595             :               ResolveMethodType aResolveMethod,
     596             :               RejectMethodType aRejectMethod,
     597             :               const char* aCallSite)
     598             :       : ThenValueBase(aResponseTarget, aCallSite)
     599             :       , mThisVal(aThisVal)
     600             :       , mResolveMethod(aResolveMethod)
     601           0 :       , mRejectMethod(aRejectMethod)
     602             :     {
     603           0 :     }
     604             : 
     605           0 :     void Disconnect() override
     606             :     {
     607           0 :       ThenValueBase::Disconnect();
     608             : 
     609             :       // If a Request has been disconnected, we don't guarantee that the
     610             :       // resolve/reject runnable will be dispatched. Null out our refcounted
     611             :       // this-value now so that it's released predictably on the dispatch thread.
     612           0 :       mThisVal = nullptr;
     613           0 :     }
     614             : 
     615             :   protected:
     616           0 :     MozPromiseBase* CompletionPromise() const override
     617             :     {
     618           0 :       return mCompletionPromise;
     619             :     }
     620             : 
     621           0 :     void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override
     622             :     {
     623           0 :       if (aValue.IsResolve()) {
     624           0 :         InvokeCallbackMethod<SupportChaining::value>(
     625             :           mThisVal.get(),
     626             :           mResolveMethod,
     627           0 :           MaybeMove(aValue.ResolveValue()),
     628           0 :           Move(mCompletionPromise));
     629             :       } else {
     630           0 :         InvokeCallbackMethod<SupportChaining::value>(
     631             :           mThisVal.get(),
     632             :           mRejectMethod,
     633           0 :           MaybeMove(aValue.RejectValue()),
     634           0 :           Move(mCompletionPromise));
     635             :       }
     636             : 
     637             :       // Null out mThisVal after invoking the callback so that any references are
     638             :       // released predictably on the dispatch thread. Otherwise, it would be
     639             :       // released on whatever thread last drops its reference to the ThenValue,
     640             :       // which may or may not be ok.
     641           0 :       mThisVal = nullptr;
     642           0 :     }
     643             : 
     644             :   private:
     645             :     RefPtr<ThisType> mThisVal; // Only accessed and refcounted on dispatch thread.
     646             :     ResolveMethodType mResolveMethod;
     647             :     RejectMethodType mRejectMethod;
     648             :     RefPtr<typename PromiseType::Private> mCompletionPromise;
     649             :   };
     650             : 
     651             :   template<typename ThisType, typename ResolveRejectMethodType>
     652             :   class ThenValue<ThisType*, ResolveRejectMethodType> : public ThenValueBase
     653             :   {
     654             :     friend class ThenCommand<ThenValue>;
     655             : 
     656             :     using R1 = typename RemoveSmartPointer<
     657             :       typename detail::MethodTrait<ResolveRejectMethodType>::ReturnType>::Type;
     658             :     using SupportChaining = IntegralConstant<bool, IsMozPromise<R1>::value>;
     659             : 
     660             :     // Fall back to MozPromise when promise chaining is not supported to make code compile.
     661             :     using PromiseType =
     662             :       typename Conditional<SupportChaining::value, R1, MozPromise>::Type;
     663             : 
     664             :   public:
     665             :     ThenValue(nsISerialEventTarget* aResponseTarget,
     666             :               ThisType* aThisVal,
     667             :               ResolveRejectMethodType aResolveRejectMethod,
     668             :               const char* aCallSite)
     669             :       : ThenValueBase(aResponseTarget, aCallSite)
     670             :       , mThisVal(aThisVal)
     671             :       , mResolveRejectMethod(aResolveRejectMethod)
     672             :     {}
     673             : 
     674             :     void Disconnect() override
     675             :     {
     676             :       ThenValueBase::Disconnect();
     677             : 
     678             :       // If a Request has been disconnected, we don't guarantee that the
     679             :       // resolve/reject runnable will be dispatched. Null out our refcounted
     680             :       // this-value now so that it's released predictably on the dispatch thread.
     681             :       mThisVal = nullptr;
     682             :     }
     683             : 
     684             :   protected:
     685             :     MozPromiseBase* CompletionPromise() const override
     686             :     {
     687             :       return mCompletionPromise;
     688             :     }
     689             : 
     690             :     void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override
     691             :     {
     692             :       InvokeCallbackMethod<SupportChaining::value>(mThisVal.get(),
     693             :                                                    mResolveRejectMethod,
     694             :                                                    MaybeMove(aValue),
     695             :                                                    Move(mCompletionPromise));
     696             : 
     697             :       // Null out mThisVal after invoking the callback so that any references are
     698             :       // released predictably on the dispatch thread. Otherwise, it would be
     699             :       // released on whatever thread last drops its reference to the ThenValue,
     700             :       // which may or may not be ok.
     701             :       mThisVal = nullptr;
     702             :     }
     703             : 
     704             :   private:
     705             :     RefPtr<ThisType> mThisVal; // Only accessed and refcounted on dispatch thread.
     706             :     ResolveRejectMethodType mResolveRejectMethod;
     707             :     RefPtr<typename PromiseType::Private> mCompletionPromise;
     708             :   };
     709             : 
     710             :   // NB: We could use std::function here instead of a template if it were supported. :-(
     711             :   template<typename ResolveFunction, typename RejectFunction>
     712          18 :   class ThenValue<ResolveFunction, RejectFunction> : public ThenValueBase
     713             :   {
     714             :     friend class ThenCommand<ThenValue>;
     715             : 
     716             :     using R1 = typename RemoveSmartPointer<
     717             :       typename detail::MethodTrait<ResolveFunction>::ReturnType>::Type;
     718             :     using R2 = typename RemoveSmartPointer<
     719             :       typename detail::MethodTrait<RejectFunction>::ReturnType>::Type;
     720             :     using SupportChaining =
     721             :       IntegralConstant<bool, IsMozPromise<R1>::value && IsSame<R1, R2>::value>;
     722             : 
     723             :     // Fall back to MozPromise when promise chaining is not supported to make code compile.
     724             :     using PromiseType =
     725             :       typename Conditional<SupportChaining::value, R1, MozPromise>::Type;
     726             : 
     727             :   public:
     728           6 :     ThenValue(nsISerialEventTarget* aResponseTarget,
     729             :               ResolveFunction&& aResolveFunction,
     730             :               RejectFunction&& aRejectFunction,
     731             :               const char* aCallSite)
     732           6 :       : ThenValueBase(aResponseTarget, aCallSite)
     733             :     {
     734           6 :       mResolveFunction.emplace(Move(aResolveFunction));
     735           6 :       mRejectFunction.emplace(Move(aRejectFunction));
     736           6 :     }
     737             : 
     738           0 :     void Disconnect() override
     739             :     {
     740           0 :       ThenValueBase::Disconnect();
     741             : 
     742             :       // If a Request has been disconnected, we don't guarantee that the
     743             :       // resolve/reject runnable will be dispatched. Destroy our callbacks
     744             :       // now so that any references in closures are released predictable on
     745             :       // the dispatch thread.
     746           0 :       mResolveFunction.reset();
     747           0 :       mRejectFunction.reset();
     748           0 :     }
     749             : 
     750             :   protected:
     751           0 :     MozPromiseBase* CompletionPromise() const override
     752             :     {
     753           0 :       return mCompletionPromise;
     754             :     }
     755             : 
     756           6 :     void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override
     757             :     {
     758             :       // Note: The usage of InvokeCallbackMethod here requires that
     759             :       // ResolveFunction/RejectFunction are capture-lambdas (i.e. anonymous
     760             :       // classes with ::operator()), since it allows us to share code more easily.
     761             :       // We could fix this if need be, though it's quite easy to work around by
     762             :       // just capturing something.
     763           6 :       if (aValue.IsResolve()) {
     764           6 :         InvokeCallbackMethod<SupportChaining::value>(
     765             :           mResolveFunction.ptr(),
     766             :           &ResolveFunction::operator(),
     767           6 :           MaybeMove(aValue.ResolveValue()),
     768           6 :           Move(mCompletionPromise));
     769             :       } else {
     770           0 :         InvokeCallbackMethod<SupportChaining::value>(
     771             :           mRejectFunction.ptr(),
     772             :           &RejectFunction::operator(),
     773           0 :           MaybeMove(aValue.RejectValue()),
     774           0 :           Move(mCompletionPromise));
     775             :       }
     776             : 
     777             :       // Destroy callbacks after invocation so that any references in closures are
     778             :       // released predictably on the dispatch thread. Otherwise, they would be
     779             :       // released on whatever thread last drops its reference to the ThenValue,
     780             :       // which may or may not be ok.
     781           6 :       mResolveFunction.reset();
     782           6 :       mRejectFunction.reset();
     783           6 :     }
     784             : 
     785             :   private:
     786             :     Maybe<ResolveFunction> mResolveFunction; // Only accessed and deleted on dispatch thread.
     787             :     Maybe<RejectFunction> mRejectFunction; // Only accessed and deleted on dispatch thread.
     788             :     RefPtr<typename PromiseType::Private> mCompletionPromise;
     789             :   };
     790             : 
     791             :   template<typename ResolveRejectFunction>
     792           0 :   class ThenValue<ResolveRejectFunction> : public ThenValueBase
     793             :   {
     794             :     friend class ThenCommand<ThenValue>;
     795             : 
     796             :     using R1 = typename RemoveSmartPointer<
     797             :       typename detail::MethodTrait<ResolveRejectFunction>::ReturnType>::Type;
     798             :     using SupportChaining = IntegralConstant<bool, IsMozPromise<R1>::value>;
     799             : 
     800             :     // Fall back to MozPromise when promise chaining is not supported to make code compile.
     801             :     using PromiseType =
     802             :       typename Conditional<SupportChaining::value, R1, MozPromise>::Type;
     803             : 
     804             :   public:
     805           0 :     ThenValue(nsISerialEventTarget* aResponseTarget,
     806             :               ResolveRejectFunction&& aResolveRejectFunction,
     807             :               const char* aCallSite)
     808           0 :       : ThenValueBase(aResponseTarget, aCallSite)
     809             :     {
     810           0 :       mResolveRejectFunction.emplace(Move(aResolveRejectFunction));
     811           0 :     }
     812             : 
     813           0 :     void Disconnect() override
     814             :     {
     815           0 :       ThenValueBase::Disconnect();
     816             : 
     817             :       // If a Request has been disconnected, we don't guarantee that the
     818             :       // resolve/reject runnable will be dispatched. Destroy our callbacks
     819             :       // now so that any references in closures are released predictable on
     820             :       // the dispatch thread.
     821           0 :       mResolveRejectFunction.reset();
     822           0 :     }
     823             : 
     824             :   protected:
     825           0 :     MozPromiseBase* CompletionPromise() const override
     826             :     {
     827           0 :       return mCompletionPromise;
     828             :     }
     829             : 
     830           0 :     void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override
     831             :     {
     832             :       // Note: The usage of InvokeCallbackMethod here requires that
     833             :       // ResolveRejectFunction is capture-lambdas (i.e. anonymous
     834             :       // classes with ::operator()), since it allows us to share code more easily.
     835             :       // We could fix this if need be, though it's quite easy to work around by
     836             :       // just capturing something.
     837           0 :       InvokeCallbackMethod<SupportChaining::value>(
     838             :         mResolveRejectFunction.ptr(),
     839             :         &ResolveRejectFunction::operator(),
     840             :         MaybeMove(aValue),
     841           0 :         Move(mCompletionPromise));
     842             : 
     843             :       // Destroy callbacks after invocation so that any references in closures are
     844             :       // released predictably on the dispatch thread. Otherwise, they would be
     845             :       // released on whatever thread last drops its reference to the ThenValue,
     846             :       // which may or may not be ok.
     847           0 :       mResolveRejectFunction.reset();
     848           0 :     }
     849             : 
     850             :   private:
     851             :     Maybe<ResolveRejectFunction> mResolveRejectFunction; // Only accessed and deleted on dispatch thread.
     852             :     RefPtr<typename PromiseType::Private> mCompletionPromise;
     853             :   };
     854             : 
     855             : public:
     856           6 :   void ThenInternal(already_AddRefed<ThenValueBase> aThenValue,
     857             :                     const char* aCallSite)
     858             :   {
     859           6 :     PROMISE_ASSERT(mMagic1 == sMagic && mMagic2 == sMagic && mMagic3 == sMagic && mMagic4 == &mMutex);
     860          12 :     RefPtr<ThenValueBase> thenValue = aThenValue;
     861          12 :     MutexAutoLock lock(mMutex);
     862           0 :     MOZ_DIAGNOSTIC_ASSERT(!IsExclusive || !mHaveRequest);
     863           6 :     mHaveRequest = true;
     864           6 :     PROMISE_LOG("%s invoking Then() [this=%p, aThenValue=%p, isPending=%d]",
     865             :                 aCallSite,
     866             :                 this,
     867             :                 thenValue.get(),
     868             :                 (int)IsPending());
     869           6 :     if (!IsPending()) {
     870           0 :       thenValue->Dispatch(this);
     871             :     } else {
     872           6 :       mThenValues.AppendElement(thenValue.forget());
     873             :     }
     874           6 :   }
     875             : 
     876             : protected:
     877             :   /*
     878             :    * A command object to store all information needed to make a request to
     879             :    * the promise. This allows us to delay the request until further use is
     880             :    * known (whether it is ->Then() again for more promise chaining or ->Track()
     881             :    * to terminate chaining and issue the request).
     882             :    *
     883             :    * This allows a unified syntax for promise chaining and disconnection
     884             :    * and feels more like its JS counterpart.
     885             :    */
     886             :   template<typename ThenValueType>
     887             :   class ThenCommand
     888             :   {
     889             :     // Allow Promise1::ThenCommand to access the private constructor,
     890             :     // Promise2::ThenCommand(ThenCommand&&).
     891             :     template<typename, typename, bool>
     892             :     friend class MozPromise;
     893             : 
     894             :     using PromiseType = typename ThenValueType::PromiseType;
     895             :     using Private = typename PromiseType::Private;
     896             : 
     897           6 :     ThenCommand(const char* aCallSite,
     898             :                 already_AddRefed<ThenValueType> aThenValue,
     899             :                 MozPromise* aReceiver)
     900             :       : mCallSite(aCallSite)
     901             :       , mThenValue(aThenValue)
     902           6 :       , mReceiver(aReceiver)
     903             :     {
     904           6 :     }
     905             : 
     906             :     ThenCommand(ThenCommand&& aOther) = default;
     907             : 
     908             :   public:
     909           6 :     ~ThenCommand()
     910             :     {
     911             :       // Issue the request now if the return value of Then() is not used.
     912           6 :       if (mThenValue) {
     913           1 :         mReceiver->ThenInternal(mThenValue.forget(), mCallSite);
     914             :       }
     915           6 :     }
     916             : 
     917             :     // Allow RefPtr<MozPromise> p = somePromise->Then();
     918             :     //       p->Then(thread1, ...);
     919             :     //       p->Then(thread2, ...);
     920           2 :     operator RefPtr<PromiseType>()
     921             :     {
     922             :       static_assert(
     923             :         ThenValueType::SupportChaining::value,
     924             :         "The resolve/reject callback needs to return a RefPtr<MozPromise> "
     925             :         "in order to do promise chaining.");
     926             : 
     927             :       // mCompletionPromise must be created before ThenInternal() to avoid race.
     928             :       RefPtr<Private> p =
     929           4 :         new Private("<completion promise>", true /* aIsCompletionPromise */);
     930           2 :       mThenValue->mCompletionPromise = p;
     931             :       // Note ThenInternal() might nullify mCompletionPromise before return.
     932             :       // So we need to return p instead of mCompletionPromise.
     933           2 :       mReceiver->ThenInternal(mThenValue.forget(), mCallSite);
     934           4 :       return p;
     935             :     }
     936             : 
     937             :     template<typename... Ts>
     938           0 :     auto Then(Ts&&... aArgs)
     939             :       -> decltype(DeclVal<PromiseType>().Then(Forward<Ts>(aArgs)...))
     940             :     {
     941             :       return static_cast<RefPtr<PromiseType>>(*this)->Then(
     942           0 :         Forward<Ts>(aArgs)...);
     943             :     }
     944             : 
     945           3 :     void Track(MozPromiseRequestHolder<MozPromise>& aRequestHolder)
     946             :     {
     947           3 :       aRequestHolder.Track(do_AddRef(mThenValue));
     948           3 :       mReceiver->ThenInternal(mThenValue.forget(), mCallSite);
     949           3 :     }
     950             : 
     951             :     // Allow calling ->Then() again for more promise chaining or ->Track() to
     952             :     // end chaining and track the request for future disconnection.
     953           3 :     ThenCommand* operator->()
     954             :     {
     955           3 :       return this;
     956             :     }
     957             : 
     958             :   private:
     959             :     const char* mCallSite;
     960             :     RefPtr<ThenValueType> mThenValue;
     961             :     RefPtr<MozPromise> mReceiver;
     962             :   };
     963             : 
     964             : public:
     965             :   template<typename ThisType,
     966             :            typename... Methods,
     967             :            typename ThenValueType = ThenValue<ThisType*, Methods...>,
     968             :            typename ReturnType = ThenCommand<ThenValueType>>
     969           0 :   ReturnType Then(nsISerialEventTarget* aResponseTarget,
     970             :                   const char* aCallSite,
     971             :                   ThisType* aThisVal,
     972             :                   Methods... aMethods)
     973             :   {
     974             :     RefPtr<ThenValueType> thenValue =
     975           0 :       new ThenValueType(aResponseTarget, aThisVal, aMethods..., aCallSite);
     976           0 :     return ReturnType(aCallSite, thenValue.forget(), this);
     977             :   }
     978             : 
     979             :   template<typename... Functions,
     980             :            typename ThenValueType = ThenValue<Functions...>,
     981             :            typename ReturnType = ThenCommand<ThenValueType>>
     982           6 :   ReturnType Then(nsISerialEventTarget* aResponseTarget,
     983             :                   const char* aCallSite,
     984             :                   Functions&&... aFunctions)
     985             :   {
     986             :     RefPtr<ThenValueType> thenValue =
     987          18 :       new ThenValueType(aResponseTarget, Move(aFunctions)..., aCallSite);
     988          12 :     return ReturnType(aCallSite, thenValue.forget(), this);
     989             :   }
     990             : 
     991           5 :   void ChainTo(already_AddRefed<Private> aChainedPromise, const char* aCallSite)
     992             :   {
     993          10 :     MutexAutoLock lock(mMutex);
     994           0 :     MOZ_DIAGNOSTIC_ASSERT(!IsExclusive || !mHaveRequest);
     995           5 :     mHaveRequest = true;
     996          10 :     RefPtr<Private> chainedPromise = aChainedPromise;
     997           5 :     PROMISE_LOG("%s invoking Chain() [this=%p, chainedPromise=%p, isPending=%d]",
     998             :                 aCallSite, this, chainedPromise.get(), (int) IsPending());
     999           5 :     if (!IsPending()) {
    1000           4 :       ForwardTo(chainedPromise);
    1001             :     } else {
    1002           1 :       mChainedPromises.AppendElement(chainedPromise);
    1003             :     }
    1004           5 :   }
    1005             : 
    1006             :   // Note we expose the function AssertIsDead() instead of IsDead() since
    1007             :   // checking IsDead() is a data race in the situation where the request is not
    1008             :   // dead. Therefore we enforce the form |Assert(IsDead())| by exposing
    1009             :   // AssertIsDead() only.
    1010          13 :   void AssertIsDead() override
    1011             :   {
    1012          13 :     PROMISE_ASSERT(mMagic1 == sMagic && mMagic2 == sMagic && mMagic3 == sMagic && mMagic4 == &mMutex);
    1013          26 :     MutexAutoLock lock(mMutex);
    1014          13 :     for (auto&& then : mThenValues) {
    1015           0 :       then->AssertIsDead();
    1016             :     }
    1017          13 :     for (auto&& chained : mChainedPromises) {
    1018           0 :       chained->AssertIsDead();
    1019             :     }
    1020          13 :   }
    1021             : 
    1022             : protected:
    1023          58 :   bool IsPending() const { return mValue.IsNothing(); }
    1024             : 
    1025           6 :   ResolveOrRejectValue& Value()
    1026             :   {
    1027             :     // This method should only be called once the value has stabilized. As
    1028             :     // such, we don't need to acquire the lock here.
    1029           6 :     MOZ_DIAGNOSTIC_ASSERT(!IsPending());
    1030           6 :     return mValue;
    1031             :   }
    1032             : 
    1033          13 :   void DispatchAll()
    1034             :   {
    1035          13 :     mMutex.AssertCurrentThreadOwns();
    1036          19 :     for (size_t i = 0; i < mThenValues.Length(); ++i) {
    1037           6 :       mThenValues[i]->Dispatch(this);
    1038             :     }
    1039          13 :     mThenValues.Clear();
    1040             : 
    1041          14 :     for (size_t i = 0; i < mChainedPromises.Length(); ++i) {
    1042           1 :       ForwardTo(mChainedPromises[i]);
    1043             :     }
    1044          13 :     mChainedPromises.Clear();
    1045          13 :   }
    1046             : 
    1047           5 :   void ForwardTo(Private* aOther)
    1048             :   {
    1049           5 :     MOZ_ASSERT(!IsPending());
    1050           5 :     if (mValue.IsResolve()) {
    1051           5 :       aOther->Resolve(MaybeMove(mValue.ResolveValue()), "<chained promise>");
    1052             :     } else {
    1053           0 :       aOther->Reject(MaybeMove(mValue.RejectValue()), "<chained promise>");
    1054             :     }
    1055           5 :   }
    1056             : 
    1057          13 :   virtual ~MozPromise()
    1058             :   {
    1059          13 :     PROMISE_LOG("MozPromise::~MozPromise [this=%p]", this);
    1060          13 :     AssertIsDead();
    1061             :     // We can't guarantee a completion promise will always be revolved or
    1062             :     // rejected since ResolveOrRejectRunnable might not run when dispatch fails.
    1063          13 :     if (!mIsCompletionPromise) {
    1064          11 :       MOZ_ASSERT(!IsPending());
    1065          11 :       MOZ_ASSERT(mThenValues.IsEmpty());
    1066          11 :       MOZ_ASSERT(mChainedPromises.IsEmpty());
    1067             :     }
    1068             : #ifdef PROMISE_DEBUG
    1069          13 :     mMagic1 = 0;
    1070          13 :     mMagic2 = 0;
    1071          13 :     mMagic3 = 0;
    1072          13 :     mMagic4 = nullptr;
    1073             : #endif
    1074          26 :   };
    1075             : 
    1076             :   const char* mCreationSite; // For logging
    1077             :   Mutex mMutex;
    1078             :   ResolveOrRejectValue mValue;
    1079             : #ifdef PROMISE_DEBUG
    1080             :   uint32_t mMagic1 = sMagic;
    1081             : #endif
    1082             :   // Try shows we never have more than 3 elements when IsExclusive is false.
    1083             :   // So '3' is a good value to avoid heap allocation in most cases.
    1084             :   AutoTArray<RefPtr<ThenValueBase>, IsExclusive ? 1 : 3> mThenValues;
    1085             : #ifdef PROMISE_DEBUG
    1086             :   uint32_t mMagic2 = sMagic;
    1087             : #endif
    1088             :   nsTArray<RefPtr<Private>> mChainedPromises;
    1089             : #ifdef PROMISE_DEBUG
    1090             :   uint32_t mMagic3 = sMagic;
    1091             : #endif
    1092             :   bool mHaveRequest;
    1093             :   const bool mIsCompletionPromise;
    1094             : #ifdef PROMISE_DEBUG
    1095             :   void* mMagic4;
    1096             : #endif
    1097             : };
    1098             : 
    1099             : template<typename ResolveValueT, typename RejectValueT, bool IsExclusive>
    1100          39 : class MozPromise<ResolveValueT, RejectValueT, IsExclusive>::Private
    1101             :   : public MozPromise<ResolveValueT, RejectValueT, IsExclusive>
    1102             : {
    1103             : public:
    1104          13 :   explicit Private(const char* aCreationSite, bool aIsCompletionPromise = false)
    1105          13 :     : MozPromise(aCreationSite, aIsCompletionPromise) {}
    1106             : 
    1107             :   template<typename ResolveValueT_>
    1108          13 :   void Resolve(ResolveValueT_&& aResolveValue, const char* aResolveSite)
    1109             :   {
    1110          13 :     PROMISE_ASSERT(mMagic1 == sMagic && mMagic2 == sMagic && mMagic3 == sMagic && mMagic4 == &mMutex);
    1111          26 :     MutexAutoLock lock(mMutex);
    1112          13 :     PROMISE_LOG("%s resolving MozPromise (%p created at %s)", aResolveSite, this, mCreationSite);
    1113          13 :     if (!IsPending()) {
    1114           0 :       PROMISE_LOG("%s ignored already resolved or rejected MozPromise (%p created at %s)", aResolveSite, this, mCreationSite);
    1115           0 :       return;
    1116             :     }
    1117          13 :     mValue.SetResolve(Forward<ResolveValueT_>(aResolveValue));
    1118          13 :     DispatchAll();
    1119             :   }
    1120             : 
    1121             :   template<typename RejectValueT_>
    1122           0 :   void Reject(RejectValueT_&& aRejectValue, const char* aRejectSite)
    1123             :   {
    1124           0 :     PROMISE_ASSERT(mMagic1 == sMagic && mMagic2 == sMagic && mMagic3 == sMagic && mMagic4 == &mMutex);
    1125           0 :     MutexAutoLock lock(mMutex);
    1126           0 :     PROMISE_LOG("%s rejecting MozPromise (%p created at %s)", aRejectSite, this, mCreationSite);
    1127           0 :     if (!IsPending()) {
    1128           0 :       PROMISE_LOG("%s ignored already resolved or rejected MozPromise (%p created at %s)", aRejectSite, this, mCreationSite);
    1129           0 :       return;
    1130             :     }
    1131           0 :     mValue.SetReject(Forward<RejectValueT_>(aRejectValue));
    1132           0 :     DispatchAll();
    1133             :   }
    1134             : 
    1135             :   template<typename ResolveOrRejectValue_>
    1136             :   void ResolveOrReject(ResolveOrRejectValue_&& aValue, const char* aSite)
    1137             :   {
    1138             :     PROMISE_ASSERT(mMagic1 == sMagic && mMagic2 == sMagic && mMagic3 == sMagic && mMagic4 == &mMutex);
    1139             :     MutexAutoLock lock(mMutex);
    1140             :     PROMISE_LOG("%s resolveOrRejecting MozPromise (%p created at %s)", aSite, this, mCreationSite);
    1141             :     if (!IsPending()) {
    1142             :       PROMISE_LOG("%s ignored already resolved or rejected MozPromise (%p created at %s)", aSite, this, mCreationSite);
    1143             :       return;
    1144             :     }
    1145             :     mValue = Forward<ResolveOrRejectValue_>(aValue);
    1146             :     DispatchAll();
    1147             :   }
    1148             : };
    1149             : 
    1150             : // A generic promise type that does the trick for simple use cases.
    1151             : typedef MozPromise<bool, nsresult, /* IsExclusive = */ false> GenericPromise;
    1152             : 
    1153             : /*
    1154             :  * Class to encapsulate a promise for a particular role. Use this as the member
    1155             :  * variable for a class whose method returns a promise.
    1156             :  */
    1157             : template<typename PromiseType>
    1158             : class MozPromiseHolder
    1159             : {
    1160             : public:
    1161           4 :   MozPromiseHolder()
    1162           4 :     : mMonitor(nullptr) {}
    1163             : 
    1164           0 :   MozPromiseHolder(MozPromiseHolder&& aOther)
    1165           0 :     : mMonitor(nullptr), mPromise(aOther.mPromise.forget()) {}
    1166             : 
    1167             :   // Move semantics.
    1168           0 :   MozPromiseHolder& operator=(MozPromiseHolder&& aOther)
    1169             :   {
    1170           0 :     MOZ_ASSERT(!mMonitor && !aOther.mMonitor);
    1171           0 :     MOZ_DIAGNOSTIC_ASSERT(!mPromise);
    1172           0 :     mPromise = aOther.mPromise;
    1173           0 :     aOther.mPromise = nullptr;
    1174           0 :     return *this;
    1175             :   }
    1176             : 
    1177           2 :   ~MozPromiseHolder() { MOZ_ASSERT(!mPromise); }
    1178             : 
    1179           4 :   already_AddRefed<PromiseType> Ensure(const char* aMethodName) {
    1180           4 :     if (mMonitor) {
    1181           1 :       mMonitor->AssertCurrentThreadOwns();
    1182             :     }
    1183           4 :     if (!mPromise) {
    1184           4 :       mPromise = new (typename PromiseType::Private)(aMethodName);
    1185             :     }
    1186           8 :     RefPtr<PromiseType> p = mPromise.get();
    1187           8 :     return p.forget();
    1188             :   }
    1189             : 
    1190             :   // Provide a Monitor that should always be held when accessing this instance.
    1191           1 :   void SetMonitor(Monitor* aMonitor) { mMonitor = aMonitor; }
    1192             : 
    1193          13 :   bool IsEmpty() const
    1194             :   {
    1195          13 :     if (mMonitor) {
    1196           0 :       mMonitor->AssertCurrentThreadOwns();
    1197             :     }
    1198          13 :     return !mPromise;
    1199             :   }
    1200             : 
    1201           0 :   already_AddRefed<typename PromiseType::Private> Steal()
    1202             :   {
    1203           0 :     if (mMonitor) {
    1204           0 :       mMonitor->AssertCurrentThreadOwns();
    1205             :     }
    1206             : 
    1207           0 :     RefPtr<typename PromiseType::Private> p = mPromise;
    1208           0 :     mPromise = nullptr;
    1209           0 :     return p.forget();
    1210             :   }
    1211             : 
    1212           0 :   void Resolve(const typename PromiseType::ResolveValueType& aResolveValue,
    1213             :                const char* aMethodName)
    1214             :   {
    1215           0 :     if (mMonitor) {
    1216           0 :       mMonitor->AssertCurrentThreadOwns();
    1217             :     }
    1218           0 :     MOZ_ASSERT(mPromise);
    1219           0 :     mPromise->Resolve(aResolveValue, aMethodName);
    1220           0 :     mPromise = nullptr;
    1221           0 :   }
    1222           4 :   void Resolve(typename PromiseType::ResolveValueType&& aResolveValue,
    1223             :                const char* aMethodName)
    1224             :   {
    1225           4 :     if (mMonitor) {
    1226           1 :       mMonitor->AssertCurrentThreadOwns();
    1227             :     }
    1228           4 :     MOZ_ASSERT(mPromise);
    1229           4 :     mPromise->Resolve(Move(aResolveValue), aMethodName);
    1230           4 :     mPromise = nullptr;
    1231           4 :   }
    1232             : 
    1233           0 :   void ResolveIfExists(const typename PromiseType::ResolveValueType& aResolveValue,
    1234             :                        const char* aMethodName)
    1235             :   {
    1236           0 :     if (!IsEmpty()) {
    1237           0 :       Resolve(aResolveValue, aMethodName);
    1238             :     }
    1239           0 :   }
    1240           3 :   void ResolveIfExists(typename PromiseType::ResolveValueType&& aResolveValue,
    1241             :                        const char* aMethodName)
    1242             :   {
    1243           3 :     if (!IsEmpty()) {
    1244           3 :       Resolve(Move(aResolveValue), aMethodName);
    1245             :     }
    1246           3 :   }
    1247             : 
    1248           0 :   void Reject(const typename PromiseType::RejectValueType& aRejectValue,
    1249             :               const char* aMethodName)
    1250             :   {
    1251           0 :     if (mMonitor) {
    1252           0 :       mMonitor->AssertCurrentThreadOwns();
    1253             :     }
    1254           0 :     MOZ_ASSERT(mPromise);
    1255           0 :     mPromise->Reject(aRejectValue, aMethodName);
    1256           0 :     mPromise = nullptr;
    1257           0 :   }
    1258           0 :   void Reject(typename PromiseType::RejectValueType&& aRejectValue,
    1259             :               const char* aMethodName)
    1260             :   {
    1261           0 :     if (mMonitor) {
    1262           0 :       mMonitor->AssertCurrentThreadOwns();
    1263             :     }
    1264           0 :     MOZ_ASSERT(mPromise);
    1265           0 :     mPromise->Reject(Move(aRejectValue), aMethodName);
    1266           0 :     mPromise = nullptr;
    1267           0 :   }
    1268             : 
    1269           0 :   void RejectIfExists(const typename PromiseType::RejectValueType& aRejectValue,
    1270             :                       const char* aMethodName)
    1271             :   {
    1272           0 :     if (!IsEmpty()) {
    1273           0 :       Reject(aRejectValue, aMethodName);
    1274             :     }
    1275           0 :   }
    1276           0 :   void RejectIfExists(typename PromiseType::RejectValueType&& aRejectValue,
    1277             :                       const char* aMethodName)
    1278             :   {
    1279           0 :     if (!IsEmpty()) {
    1280           0 :       Reject(Move(aRejectValue), aMethodName);
    1281             :     }
    1282           0 :   }
    1283             : 
    1284             : private:
    1285             :   Monitor* mMonitor;
    1286             :   RefPtr<typename PromiseType::Private> mPromise;
    1287             : };
    1288             : 
    1289             : /*
    1290             :  * Class to encapsulate a MozPromise::Request reference. Use this as the member
    1291             :  * variable for a class waiting on a MozPromise.
    1292             :  */
    1293             : template<typename PromiseType>
    1294             : class MozPromiseRequestHolder
    1295             : {
    1296             : public:
    1297           3 :   MozPromiseRequestHolder() {}
    1298           2 :   ~MozPromiseRequestHolder() { MOZ_ASSERT(!mRequest); }
    1299             : 
    1300           3 :   void Track(already_AddRefed<typename PromiseType::Request> aRequest)
    1301             :   {
    1302           3 :     MOZ_DIAGNOSTIC_ASSERT(!Exists());
    1303           3 :     mRequest = aRequest;
    1304           3 :   }
    1305             : 
    1306           3 :   void Complete()
    1307             :   {
    1308           3 :     MOZ_DIAGNOSTIC_ASSERT(Exists());
    1309           3 :     mRequest = nullptr;
    1310           3 :   }
    1311             : 
    1312             :   // Disconnects and forgets an outstanding promise. The resolve/reject methods
    1313             :   // will never be called.
    1314           0 :   void Disconnect() {
    1315           0 :     MOZ_ASSERT(Exists());
    1316           0 :     mRequest->Disconnect();
    1317           0 :     mRequest = nullptr;
    1318           0 :   }
    1319             : 
    1320           0 :   void DisconnectIfExists() {
    1321           0 :     if (Exists()) {
    1322           0 :       Disconnect();
    1323             :     }
    1324           0 :   }
    1325             : 
    1326           6 :   bool Exists() const { return !!mRequest; }
    1327             : 
    1328             : private:
    1329             :   RefPtr<typename PromiseType::Request> mRequest;
    1330             : };
    1331             : 
    1332             : // Asynchronous Potentially-Cross-Thread Method Calls.
    1333             : //
    1334             : // This machinery allows callers to schedule a promise-returning function
    1335             : // (a method and object, or a function object like a lambda) to be invoked
    1336             : // asynchronously on a given thread, while at the same time receiving a
    1337             : // promise upon which to invoke Then() immediately. InvokeAsync dispatches a
    1338             : // task to invoke the function on the proper thread and also chain the
    1339             : // resulting promise to the one that the caller received, so that resolve/
    1340             : // reject values are forwarded through.
    1341             : 
    1342             : namespace detail {
    1343             : 
    1344             : // Non-templated base class to allow us to use MOZ_COUNT_{C,D}TOR, which cause
    1345             : // assertions when used on templated types.
    1346             : class MethodCallBase
    1347             : {
    1348             : public:
    1349           3 :   MethodCallBase() { MOZ_COUNT_CTOR(MethodCallBase); }
    1350           3 :   virtual ~MethodCallBase() { MOZ_COUNT_DTOR(MethodCallBase); }
    1351             : };
    1352             : 
    1353             : template<typename PromiseType, typename MethodType, typename ThisType,
    1354             :          typename... Storages>
    1355           9 : class MethodCall : public MethodCallBase
    1356             : {
    1357             : public:
    1358             :   template<typename... Args>
    1359           3 :   MethodCall(MethodType aMethod, ThisType* aThisVal, Args&&... aArgs)
    1360             :     : mMethod(aMethod)
    1361             :     , mThisVal(aThisVal)
    1362           3 :     , mArgs(Forward<Args>(aArgs)...)
    1363             :   {
    1364             :     static_assert(sizeof...(Storages) == sizeof...(Args), "Storages and Args should have equal sizes");
    1365           3 :   }
    1366             : 
    1367           3 :   RefPtr<PromiseType> Invoke()
    1368             :   {
    1369           3 :     return mArgs.apply(mThisVal.get(), mMethod);
    1370             :   }
    1371             : 
    1372             : private:
    1373             :   MethodType mMethod;
    1374             :   RefPtr<ThisType> mThisVal;
    1375             :   RunnableMethodArguments<Storages...> mArgs;
    1376             : };
    1377             : 
    1378             : template<typename PromiseType, typename MethodType, typename ThisType,
    1379             :          typename... Storages>
    1380           9 : class ProxyRunnable : public CancelableRunnable
    1381             : {
    1382             : public:
    1383           3 :   ProxyRunnable(
    1384             :     typename PromiseType::Private* aProxyPromise,
    1385             :     MethodCall<PromiseType, MethodType, ThisType, Storages...>* aMethodCall)
    1386             :     : CancelableRunnable("detail::ProxyRunnable")
    1387             :     , mProxyPromise(aProxyPromise)
    1388           3 :     , mMethodCall(aMethodCall)
    1389             :   {
    1390           3 :   }
    1391             : 
    1392           3 :   NS_IMETHOD Run() override
    1393             :   {
    1394           6 :     RefPtr<PromiseType> p = mMethodCall->Invoke();
    1395           3 :     mMethodCall = nullptr;
    1396           3 :     p->ChainTo(mProxyPromise.forget(), "<Proxy Promise>");
    1397           6 :     return NS_OK;
    1398             :   }
    1399             : 
    1400           0 :   nsresult Cancel() override
    1401             :   {
    1402           0 :     return Run();
    1403             :   }
    1404             : 
    1405             : private:
    1406             :   RefPtr<typename PromiseType::Private> mProxyPromise;
    1407             :   nsAutoPtr<MethodCall<PromiseType, MethodType, ThisType, Storages...>> mMethodCall;
    1408             : };
    1409             : 
    1410             : template<typename... Storages,
    1411             :          typename PromiseType, typename ThisType, typename... ArgTypes,
    1412             :          typename... ActualArgTypes>
    1413             : static RefPtr<PromiseType>
    1414           3 : InvokeAsyncImpl(nsISerialEventTarget* aTarget, ThisType* aThisVal,
    1415             :                 const char* aCallerName,
    1416             :                 RefPtr<PromiseType>(ThisType::*aMethod)(ArgTypes...),
    1417             :                 ActualArgTypes&&... aArgs)
    1418             : {
    1419           3 :   MOZ_ASSERT(aTarget);
    1420             : 
    1421             :   typedef RefPtr<PromiseType>(ThisType::*MethodType)(ArgTypes...);
    1422             :   typedef detail::MethodCall<PromiseType, MethodType, ThisType, Storages...> MethodCallType;
    1423             :   typedef detail::ProxyRunnable<PromiseType, MethodType, ThisType, Storages...> ProxyRunnableType;
    1424             : 
    1425             :   MethodCallType* methodCall =
    1426           5 :     new MethodCallType(aMethod, aThisVal, Forward<ActualArgTypes>(aArgs)...);
    1427           6 :   RefPtr<typename PromiseType::Private> p = new (typename PromiseType::Private)(aCallerName);
    1428           9 :   RefPtr<ProxyRunnableType> r = new ProxyRunnableType(p, methodCall);
    1429           3 :   aTarget->Dispatch(r.forget());
    1430           6 :   return p.forget();
    1431             : }
    1432             : 
    1433             : constexpr bool Any()
    1434             : {
    1435             :   return false;
    1436             : }
    1437             : 
    1438             : template <typename T1>
    1439             : constexpr bool Any(T1 a)
    1440             : {
    1441             :   return static_cast<bool>(a);
    1442             : }
    1443             : 
    1444             : template <typename T1, typename... Ts>
    1445             : constexpr bool Any(T1 a, Ts... aOthers)
    1446             : {
    1447             :   return a || Any(aOthers...);
    1448             : }
    1449             : 
    1450             : } // namespace detail
    1451             : 
    1452             : // InvokeAsync with explicitly-specified storages.
    1453             : // See ParameterStorage in nsThreadUtils.h for help.
    1454             : template<typename... Storages,
    1455             :          typename PromiseType, typename ThisType, typename... ArgTypes,
    1456             :          typename... ActualArgTypes,
    1457             :          typename EnableIf<sizeof...(Storages) != 0, int>::Type = 0>
    1458             : static RefPtr<PromiseType>
    1459           0 : InvokeAsync(nsISerialEventTarget* aTarget, ThisType* aThisVal, const char* aCallerName,
    1460             :             RefPtr<PromiseType>(ThisType::*aMethod)(ArgTypes...),
    1461             :             ActualArgTypes&&... aArgs)
    1462             : {
    1463             :   static_assert(sizeof...(Storages) == sizeof...(ArgTypes),
    1464             :                 "Provided Storages and method's ArgTypes should have equal sizes");
    1465             :   static_assert(sizeof...(Storages) == sizeof...(ActualArgTypes),
    1466             :                 "Provided Storages and ActualArgTypes should have equal sizes");
    1467             :   return detail::InvokeAsyncImpl<Storages...>(
    1468             :            aTarget, aThisVal, aCallerName, aMethod,
    1469           0 :            Forward<ActualArgTypes>(aArgs)...);
    1470             : }
    1471             : 
    1472             : // InvokeAsync with no explicitly-specified storages, will copy arguments and
    1473             : // then move them out of the runnable into the target method parameters.
    1474             : template<typename... Storages,
    1475             :          typename PromiseType, typename ThisType, typename... ArgTypes,
    1476             :          typename... ActualArgTypes,
    1477             :          typename EnableIf<sizeof...(Storages) == 0, int>::Type = 0>
    1478             : static RefPtr<PromiseType>
    1479           3 : InvokeAsync(nsISerialEventTarget* aTarget, ThisType* aThisVal, const char* aCallerName,
    1480             :             RefPtr<PromiseType>(ThisType::*aMethod)(ArgTypes...),
    1481             :             ActualArgTypes&&... aArgs)
    1482             : {
    1483             :   static_assert(!detail::Any(IsPointer<typename RemoveReference<ActualArgTypes>::Type>::value...),
    1484             :                 "Cannot pass pointer types through InvokeAsync, Storages must be provided");
    1485             :   static_assert(sizeof...(ArgTypes) == sizeof...(ActualArgTypes),
    1486             :                 "Method's ArgTypes and ActualArgTypes should have equal sizes");
    1487             :   return detail::InvokeAsyncImpl<StoreCopyPassByRRef<typename Decay<ActualArgTypes>::Type>...>(
    1488             :            aTarget, aThisVal, aCallerName, aMethod,
    1489           3 :            Forward<ActualArgTypes>(aArgs)...);
    1490             : }
    1491             : 
    1492             : namespace detail {
    1493             : 
    1494             : template<typename Function, typename PromiseType>
    1495           0 : class ProxyFunctionRunnable : public CancelableRunnable
    1496             : {
    1497             :   typedef typename Decay<Function>::Type FunctionStorage;
    1498             : public:
    1499             :   template<typename F>
    1500           0 :   ProxyFunctionRunnable(typename PromiseType::Private* aProxyPromise,
    1501             :                         F&& aFunction)
    1502             :     : CancelableRunnable("detail::ProxyFunctionRunnable")
    1503             :     , mProxyPromise(aProxyPromise)
    1504           0 :     , mFunction(new FunctionStorage(Forward<F>(aFunction)))
    1505             :   {
    1506           0 :   }
    1507             : 
    1508           0 :   NS_IMETHOD Run() override
    1509             :   {
    1510           0 :     RefPtr<PromiseType> p = (*mFunction)();
    1511           0 :     mFunction = nullptr;
    1512           0 :     p->ChainTo(mProxyPromise.forget(), "<Proxy Promise>");
    1513           0 :     return NS_OK;
    1514             :   }
    1515             : 
    1516           0 :   nsresult Cancel() override
    1517             :   {
    1518           0 :     return Run();
    1519             :   }
    1520             : 
    1521             : private:
    1522             :   RefPtr<typename PromiseType::Private> mProxyPromise;
    1523             :   UniquePtr<FunctionStorage> mFunction;
    1524             : };
    1525             : 
    1526             : // Note: The following struct and function are not for public consumption (yet?)
    1527             : // as we would prefer all calls to pass on-the-spot lambdas (or at least moved
    1528             : // function objects). They could be moved outside of detail if really needed.
    1529             : 
    1530             : // We prefer getting function objects by non-lvalue-ref (to avoid copying them
    1531             : // and their captures). This struct is a tag that allows the use of objects
    1532             : // through lvalue-refs where necessary.
    1533             : struct AllowInvokeAsyncFunctionLVRef {};
    1534             : 
    1535             : // Invoke a function object (e.g., lambda or std/mozilla::function)
    1536             : // asynchronously; note that the object will be copied if provided by lvalue-ref.
    1537             : // Return a promise that the function should eventually resolve or reject.
    1538             : template<typename Function>
    1539             : static auto
    1540           0 : InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName,
    1541             :             AllowInvokeAsyncFunctionLVRef, Function&& aFunction)
    1542             :   -> decltype(aFunction())
    1543             : {
    1544             :   static_assert(IsRefcountedSmartPointer<decltype(aFunction())>::value
    1545             :                 && IsMozPromise<typename RemoveSmartPointer<
    1546             :                                            decltype(aFunction())>::Type>::value,
    1547             :                 "Function object must return RefPtr<MozPromise>");
    1548           0 :   MOZ_ASSERT(aTarget);
    1549             :   typedef typename RemoveSmartPointer<decltype(aFunction())>::Type PromiseType;
    1550             :   typedef detail::ProxyFunctionRunnable<Function, PromiseType> ProxyRunnableType;
    1551             : 
    1552             :   RefPtr<typename PromiseType::Private> p =
    1553           0 :     new (typename PromiseType::Private)(aCallerName);
    1554             :   RefPtr<ProxyRunnableType> r =
    1555           0 :     new ProxyRunnableType(p, Forward<Function>(aFunction));
    1556           0 :   aTarget->Dispatch(r.forget());
    1557           0 :   return p.forget();
    1558             : }
    1559             : 
    1560             : } // namespace detail
    1561             : 
    1562             : // Invoke a function object (e.g., lambda) asynchronously.
    1563             : // Return a promise that the function should eventually resolve or reject.
    1564             : template<typename Function>
    1565             : static auto
    1566           0 : InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName,
    1567             :             Function&& aFunction)
    1568             :   -> decltype(aFunction())
    1569             : {
    1570             :   static_assert(!IsLvalueReference<Function>::value,
    1571             :                 "Function object must not be passed by lvalue-ref (to avoid "
    1572             :                 "unplanned copies); Consider move()ing the object.");
    1573             :   return detail::InvokeAsync(aTarget, aCallerName,
    1574             :                              detail::AllowInvokeAsyncFunctionLVRef(),
    1575           0 :                              Forward<Function>(aFunction));
    1576             : }
    1577             : 
    1578             : #undef PROMISE_LOG
    1579             : #undef PROMISE_ASSERT
    1580             : #undef PROMISE_DEBUG
    1581             : 
    1582             : } // namespace mozilla
    1583             : 
    1584             : #endif

Generated by: LCOV version 1.13