Bug 974120: Add helpers for using Promse::MaybeResolve/MaybeReject from C++. r=bz
authorKyle Huey <khuey@kylehuey.com>
Tue, 25 Feb 2014 13:34:55 -0800
changeset 170907 e581cbef0dd93a2d0b4f3ed4466f4a26253ef959
parent 170906 0d186c979373404e260d6c7eced71f784427a03f
child 170908 e4dd4dd96cbe1c8f5952f44cd54227b2bb6e14ad
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersbz
bugs974120
milestone30.0a1
Bug 974120: Add helpers for using Promse::MaybeResolve/MaybeReject from C++. r=bz Using JSAPI is tedious and error-prone. It's much better to handle that once in the Promise code and allow callers to pass C++ objects.
dom/bindings/BindingUtils.cpp
dom/promise/Promise.cpp
dom/promise/Promise.h
dom/src/notification/Notification.cpp
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1817,22 +1817,22 @@ GlobalObject::GlobalObject(JSContext* aC
   }
 
   mGlobalJSObject = JS_GetGlobalForObject(aCx, obj);
 }
 
 nsISupports*
 GlobalObject::GetAsSupports() const
 {
-  if (!NS_IsMainThread()) {
-    return nullptr;
+  if (mGlobalObject) {
+    return mGlobalObject;
   }
 
-  if (mGlobalObject) {
-    return mGlobalObject;
+  if (!NS_IsMainThread()) {
+    return UnwrapDOMObjectToISupports(mGlobalJSObject);
   }
 
   JS::Rooted<JS::Value> val(mCx, JS::ObjectValue(*mGlobalJSObject));
 
   // Switch this to UnwrapDOMObjectToISupports once our global objects are
   // using new bindings.
   nsresult rv = xpc_qsUnwrapArg<nsISupports>(mCx, val, &mGlobalObject,
                                              static_cast<nsISupports**>(getter_AddRefs(mGlobalObjectRef)),
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -8,17 +8,16 @@
 
 #include "jsfriendapi.h"
 #include "mozilla/dom/OwningNonNull.h"
 #include "mozilla/dom/PromiseBinding.h"
 #include "mozilla/Preferences.h"
 #include "PromiseCallback.h"
 #include "PromiseNativeHandler.h"
 #include "nsContentUtils.h"
-#include "nsPIDOMWindow.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "nsJSPrincipals.h"
 #include "nsJSUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsJSEnvironment.h"
 
 namespace mozilla {
@@ -185,25 +184,25 @@ public:
 };
 
 // Promise
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Promise)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Promise)
   tmp->MaybeReportRejected();
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mResolveCallbacks);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mRejectCallbacks);
   tmp->mResult = JS::UndefinedValue();
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Promise)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResolveCallbacks);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRejectCallbacks);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Promise)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResult)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
@@ -212,43 +211,68 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Promise)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Promise)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Promise)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-Promise::Promise(nsPIDOMWindow* aWindow)
-  : mWindow(aWindow)
+Promise::Promise(nsIGlobalObject* aGlobal)
+  : mGlobal(aGlobal)
   , mResult(JS::UndefinedValue())
   , mState(Pending)
   , mTaskPending(false)
   , mHadRejectCallback(false)
   , mResolvePending(false)
 {
-  MOZ_COUNT_CTOR(Promise);
+  MOZ_ASSERT(mGlobal);
+
   mozilla::HoldJSObjects(this);
   SetIsDOMBinding();
 }
 
 Promise::~Promise()
 {
   MaybeReportRejected();
   mResult = JS::UndefinedValue();
   mozilla::DropJSObjects(this);
-  MOZ_COUNT_DTOR(Promise);
 }
 
 JSObject*
 Promise::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return PromiseBinding::Wrap(aCx, aScope, this);
 }
 
+JSObject*
+Promise::GetOrCreateWrapper(JSContext* aCx)
+{
+  if (JSObject* wrapper = GetWrapper()) {
+    return wrapper;
+  }
+
+  nsIGlobalObject* global = GetParentObject();
+  MOZ_ASSERT(global);
+
+  JS::Rooted<JSObject*> scope(aCx, global->GetGlobalJSObject());
+  if (!scope) {
+    JS_ReportError(aCx, "can't get scope");
+    return nullptr;
+  }
+
+  JS::Rooted<JS::Value> val(aCx);
+  if (!WrapNewBindingObject(aCx, scope, this, &val)) {
+    MOZ_ASSERT(JS_IsExceptionPending(aCx));
+    return nullptr;
+  }
+
+  return GetWrapper();
+}
+
 void
 Promise::MaybeResolve(JSContext* aCx,
                       JS::Handle<JS::Value> aValue)
 {
   MaybeResolveInternal(aCx, aValue);
 }
 
 void
@@ -448,28 +472,25 @@ Promise::CreateThenableFunction(JSContex
   return obj;
 }
 
 /* static */ already_AddRefed<Promise>
 Promise::Constructor(const GlobalObject& aGlobal,
                      PromiseInit& aInit, ErrorResult& aRv)
 {
   JSContext* cx = aGlobal.GetContext();
-  nsCOMPtr<nsPIDOMWindow> window;
 
-  // On workers, let the window be null.
-  if (MOZ_LIKELY(NS_IsMainThread())) {
-    window = do_QueryInterface(aGlobal.GetAsSupports());
-    if (!window) {
-      aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
-    }
+  nsCOMPtr<nsIGlobalObject> global;
+  global = do_QueryInterface(aGlobal.GetAsSupports());
+  if (!global) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
   }
 
-  nsRefPtr<Promise> promise = new Promise(window);
+  nsRefPtr<Promise> promise = new Promise(global);
 
   JS::Rooted<JSObject*> resolveFunc(cx,
                                     CreateFunction(cx, aGlobal.Get(), promise,
                                                    PromiseCallback::Resolve));
   if (!resolveFunc) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
@@ -508,61 +529,55 @@ Promise::Resolve(const GlobalObject& aGl
     nsresult rv = UNWRAP_OBJECT(Promise, valueObj, nextPromise);
 
     if (NS_SUCCEEDED(rv)) {
       nsRefPtr<Promise> addRefed = nextPromise;
       return addRefed.forget();
     }
   }
 
-  nsCOMPtr<nsPIDOMWindow> window;
-  if (MOZ_LIKELY(NS_IsMainThread())) {
-    window = do_QueryInterface(aGlobal.GetAsSupports());
-    if (!window) {
-      aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
-    }
+  nsCOMPtr<nsIGlobalObject> global =
+    do_QueryInterface(aGlobal.GetAsSupports());
+  if (!global) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
   }
 
-  return Resolve(window, aCx, aValue, aRv);
+  return Resolve(global, aCx, aValue, aRv);
 }
 
 /* static */ already_AddRefed<Promise>
-Promise::Resolve(nsPIDOMWindow* aWindow, JSContext* aCx,
+Promise::Resolve(nsIGlobalObject* aGlobal, JSContext* aCx,
                  JS::Handle<JS::Value> aValue, ErrorResult& aRv)
 {
-  // aWindow may be null.
-  nsRefPtr<Promise> promise = new Promise(aWindow);
+  nsRefPtr<Promise> promise = new Promise(aGlobal);
 
   promise->MaybeResolveInternal(aCx, aValue);
   return promise.forget();
 }
 
 /* static */ already_AddRefed<Promise>
 Promise::Reject(const GlobalObject& aGlobal, JSContext* aCx,
                 JS::Handle<JS::Value> aValue, ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window;
-  if (MOZ_LIKELY(NS_IsMainThread())) {
-    window = do_QueryInterface(aGlobal.GetAsSupports());
-    if (!window) {
-      aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
-    }
+  nsCOMPtr<nsIGlobalObject> global =
+    do_QueryInterface(aGlobal.GetAsSupports());
+  if (!global) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
   }
 
-  return Reject(window, aCx, aValue, aRv);
+  return Reject(global, aCx, aValue, aRv);
 }
 
 /* static */ already_AddRefed<Promise>
-Promise::Reject(nsPIDOMWindow* aWindow, JSContext* aCx,
+Promise::Reject(nsIGlobalObject* aGlobal, JSContext* aCx,
                 JS::Handle<JS::Value> aValue, ErrorResult& aRv)
 {
-  // aWindow may be null.
-  nsRefPtr<Promise> promise = new Promise(aWindow);
+  nsRefPtr<Promise> promise = new Promise(aGlobal);
 
   promise->MaybeRejectInternal(aCx, aValue);
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 Promise::Then(AnyCallback* aResolveCallback, AnyCallback* aRejectCallback)
 {
@@ -711,36 +726,34 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END_INHERITING(PromiseNativeHandler)
 
 NS_IMPL_CYCLE_COLLECTION_1(AllResolveHandler, mCountdownHolder)
 
 /* static */ already_AddRefed<Promise>
 Promise::All(const GlobalObject& aGlobal, JSContext* aCx,
              const Sequence<JS::Value>& aIterable, ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window;
-  if (MOZ_LIKELY(NS_IsMainThread())) {
-    window = do_QueryInterface(aGlobal.GetAsSupports());
-    if (!window) {
-      aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
-    }
+  nsCOMPtr<nsIGlobalObject> global =
+    do_QueryInterface(aGlobal.GetAsSupports());
+  if (!global) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
   }
 
   if (aIterable.Length() == 0) {
     JS::Rooted<JSObject*> empty(aCx, JS_NewArrayObject(aCx, 0));
     if (!empty) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return nullptr;
     }
     JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*empty));
     return Promise::Resolve(aGlobal, aCx, value, aRv);
   }
 
-  nsRefPtr<Promise> promise = new Promise(window);
+  nsRefPtr<Promise> promise = new Promise(global);
   nsRefPtr<CountdownHolder> holder =
     new CountdownHolder(aGlobal, promise, aIterable.Length());
 
   nsRefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(promise);
 
   for (uint32_t i = 0; i < aIterable.Length(); ++i) {
     JS::Rooted<JS::Value> value(aCx, aIterable.ElementAt(i));
     nsRefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, aCx, value, aRv);
@@ -759,26 +772,24 @@ Promise::All(const GlobalObject& aGlobal
 
   return promise.forget();
 }
 
 /* static */ already_AddRefed<Promise>
 Promise::Race(const GlobalObject& aGlobal, JSContext* aCx,
               const Sequence<JS::Value>& aIterable, ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window;
-  if (MOZ_LIKELY(NS_IsMainThread())) {
-    window = do_QueryInterface(aGlobal.GetAsSupports());
-    if (!window) {
-      aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
-    }
+  nsCOMPtr<nsIGlobalObject> global =
+    do_QueryInterface(aGlobal.GetAsSupports());
+  if (!global) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
   }
 
-  nsRefPtr<Promise> promise = new Promise(window);
+  nsRefPtr<Promise> promise = new Promise(global);
   nsRefPtr<PromiseCallback> resolveCb = new ResolvePromiseCallback(promise);
   nsRefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(promise);
 
   for (uint32_t i = 0; i < aIterable.Length(); ++i) {
     JS::Rooted<JS::Value> value(aCx, aIterable.ElementAt(i));
     nsRefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, aCx, value, aRv);
     // According to spec, Resolve can throw, but our implementation never does.
     // Well it does when window isn't passed on the main thread, but that is an
@@ -1052,10 +1063,31 @@ Promise::RunResolveTask(JS::Handle<JS::V
     return;
   }
 
   SetResult(aValue);
   SetState(aState);
   RunTask();
 }
 
+bool
+Promise::ArgumentToJSValue(const nsAString& aArgument,
+                           JSContext* aCx,
+                           JSObject* aScope,
+                           JS::MutableHandle<JS::Value> aValue)
+{
+  // XXXkhuey I'd love to use xpc::NonVoidStringToJsval here, but it requires
+  // a non-const nsAString for silly reasons.
+  nsStringBuffer* sharedBuffer;
+  if (!XPCStringConvert::ReadableToJSVal(aCx, aArgument, &sharedBuffer,
+                                         aValue)) {
+    return false;
+  }
+
+  if (sharedBuffer) {
+    NS_ADDREF(sharedBuffer);
+  }
+
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -4,24 +4,26 @@
  * 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_Promise_h
 #define mozilla_dom_Promise_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
+#include "mozilla/TypeTraits.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/dom/PromiseBinding.h"
 #include "nsWrapperCache.h"
 #include "nsAutoPtr.h"
-#include "nsPIDOMWindow.h"
 #include "js/TypeDecls.h"
 
+class nsIGlobalObject;
+
 namespace mozilla {
 namespace dom {
 
 class AnyCallback;
 class PromiseCallback;
 class PromiseInit;
 class PromiseNativeHandler;
 
@@ -33,56 +35,73 @@ class Promise MOZ_FINAL : public nsISupp
   friend class PromiseResolverTask;
   friend class PromiseTask;
   friend class RejectPromiseCallback;
   friend class ResolvePromiseCallback;
   friend class WorkerPromiseResolverTask;
   friend class WorkerPromiseTask;
   friend class WrapperPromiseCallback;
 
+  ~Promise();
+
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Promise)
 
-  Promise(nsPIDOMWindow* aWindow);
-  ~Promise();
+  Promise(nsIGlobalObject* aGlobal);
+
+  typedef void (Promise::*MaybeFunc)(JSContext* aCx,
+                                     JS::Handle<JS::Value> aValue);
 
   void MaybeResolve(JSContext* aCx,
                     JS::Handle<JS::Value> aValue);
   void MaybeReject(JSContext* aCx,
                    JS::Handle<JS::Value> aValue);
 
+  // Helpers for using Promise from C++.
+  // Most DOM objects are handled already.  To add a new type T, such as ints,
+  // or dictionaries, add an ArgumentToJSVal overload below.
+  template <typename T>
+  void MaybeResolve(T& aArg) {
+    MaybeSomething(aArg, &Promise::MaybeResolve);
+  }
+
+  template <typename T>
+  void MaybeReject(T& aArg) {
+    MaybeSomething(aArg, &Promise::MaybeReject);
+  }
+
   // WebIDL
 
-  nsPIDOMWindow* GetParentObject() const
+  nsIGlobalObject* GetParentObject() const
   {
-    return mWindow;
+    return mGlobal;
   }
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   static already_AddRefed<Promise>
   Constructor(const GlobalObject& aGlobal, PromiseInit& aInit,
               ErrorResult& aRv);
 
   static already_AddRefed<Promise>
   Resolve(const GlobalObject& aGlobal, JSContext* aCx,
           JS::Handle<JS::Value> aValue, ErrorResult& aRv);
 
   static already_AddRefed<Promise>
-  Resolve(nsPIDOMWindow* aWindow, JSContext* aCx,
+  Resolve(nsIGlobalObject* aGlobal, JSContext* aCx,
           JS::Handle<JS::Value> aValue, ErrorResult& aRv);
 
   static already_AddRefed<Promise>
   Reject(const GlobalObject& aGlobal, JSContext* aCx,
          JS::Handle<JS::Value> aValue, ErrorResult& aRv);
 
   static already_AddRefed<Promise>
-  Reject(nsPIDOMWindow* aWindow, JSContext* aCx,
+  Reject(nsIGlobalObject* aGlobal, JSContext* aCx,
          JS::Handle<JS::Value> aValue, ErrorResult& aRv);
 
   already_AddRefed<Promise>
   Then(AnyCallback* aResolveCallback, AnyCallback* aRejectCallback);
 
   already_AddRefed<Promise>
   Catch(AnyCallback* aRejectCallback);
 
@@ -149,16 +168,74 @@ private:
   void ResolveInternal(JSContext* aCx,
                        JS::Handle<JS::Value> aValue,
                        PromiseTaskSync aSync = AsyncTask);
 
   void RejectInternal(JSContext* aCx,
                       JS::Handle<JS::Value> aValue,
                       PromiseTaskSync aSync = AsyncTask);
 
+  // Helper methods for using Promises from C++
+  JSObject* GetOrCreateWrapper(JSContext* aCx);
+
+  // If ArgumentToJSValue returns false, it must set an exception on the
+  // JSContext.
+
+  // Accept strings.
+  bool
+  ArgumentToJSValue(const nsAString& aArgument,
+                    JSContext* aCx,
+                    JSObject* aScope,
+                    JS::MutableHandle<JS::Value> aValue);
+
+  // Accept objects that inherit from nsWrapperCache and nsISupports (e.g. most
+  // DOM objects).
+  template <class T>
+  typename EnableIf<IsBaseOf<nsWrapperCache, T>::value &&
+                    IsBaseOf<nsISupports, T>::value, bool>::Type
+  ArgumentToJSValue(T& aArgument,
+                    JSContext* aCx,
+                    JSObject* aScope,
+                    JS::MutableHandle<JS::Value> aValue)
+  {
+    JS::Rooted<JSObject*> scope(aCx, aScope);
+
+    return WrapNewBindingObject(aCx, scope, aArgument, aValue);
+  }
+
+  template <template <typename> class SmartPtr, typename T>
+  bool
+  ArgumentToJSValue(const SmartPtr<T>& aArgument,
+                    JSContext* aCx,
+                    JSObject* aScope,
+                    JS::MutableHandle<JS::Value> aValue)
+  {
+    return ArgumentToJSValue(*aArgument.get(), aCx, aScope, aValue);
+  }
+
+  template <typename T>
+  void MaybeSomething(T& aArgument, MaybeFunc aFunc) {
+    ThreadsafeAutoJSContext cx;
+
+    JSObject* wrapper = GetOrCreateWrapper(cx);
+    if (!wrapper) {
+      HandleException(cx);
+      return;
+    }
+
+    JSAutoCompartment ac(cx, wrapper);
+    JS::Rooted<JS::Value> val(cx);
+    if (!ArgumentToJSValue(aArgument, cx, wrapper, &val)) {
+      HandleException(cx);
+      return;
+    }
+
+    (this->*aFunc)(cx, val);
+  }
+
   // Static methods for the PromiseInit functions.
   static bool
   JSCallback(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
 
   static bool
   ThenableResolverCommon(JSContext* aCx, uint32_t /* PromiseCallback::Task */ aTask,
                          unsigned aArgc, JS::Value* aVp);
   static bool
@@ -170,17 +247,17 @@ private:
   CreateFunction(JSContext* aCx, JSObject* aParent, Promise* aPromise,
                 int32_t aTask);
 
   static JSObject*
   CreateThenableFunction(JSContext* aCx, Promise* aPromise, uint32_t aTask);
 
   void HandleException(JSContext* aCx);
 
-  nsRefPtr<nsPIDOMWindow> mWindow;
+  nsRefPtr<nsIGlobalObject> mGlobal;
 
   nsTArray<nsRefPtr<PromiseCallback> > mResolveCallbacks;
   nsTArray<nsRefPtr<PromiseCallback> > mRejectCallbacks;
 
   JS::Heap<JS::Value> mResult;
   PromiseState mState;
   bool mTaskPending;
   bool mHadRejectCallback;
--- a/dom/src/notification/Notification.cpp
+++ b/dom/src/notification/Notification.cpp
@@ -692,17 +692,20 @@ Notification::GetPermissionInternal(nsIS
   }
 }
 
 already_AddRefed<Promise>
 Notification::Get(const GlobalObject& aGlobal,
                   const GetNotificationOptions& aFilter,
                   ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
+  nsCOMPtr<nsIGlobalObject> global =
+    do_QueryInterface(aGlobal.GetAsSupports());
+  MOZ_ASSERT(global);
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global);
   MOZ_ASSERT(window);
   nsIDocument* doc = window->GetExtantDoc();
   if (!doc) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsString origin;
@@ -714,17 +717,17 @@ Notification::Get(const GlobalObject& aG
   nsresult rv;
   nsCOMPtr<nsINotificationStorage> notificationStorage =
     do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID, &rv);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
-  nsRefPtr<Promise> promise = new Promise(window);
+  nsRefPtr<Promise> promise = new Promise(global);
   nsCOMPtr<nsINotificationStorageCallback> callback =
     new NotificationStorageCallback(aGlobal, window, promise);
   nsString tag = aFilter.mTag.WasPassed() ?
                  aFilter.mTag.Value() :
                  EmptyString();
   aRv = notificationStorage->Get(origin, tag, callback);
   if (aRv.Failed()) {
     return nullptr;