Bug 1170760 part 2. Pass in the 'this' value to Promise static methods. r=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 25 Nov 2015 15:48:08 -0500
changeset 308960 b8bdcbadd22b7bdd4dc430f12d02df508372cf02
parent 308959 86e73c5414d638ce77d4960a260cbeebff659568
child 308961 6fbe06bfeba55e7f03a98c6d800a0564d22a8dfd
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs1170760
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1170760 part 2. Pass in the 'this' value to Promise static methods. r=peterv
dom/bindings/BindingUtils.cpp
dom/bindings/Codegen.py
dom/promise/Promise.cpp
dom/promise/Promise.h
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2756,18 +2756,27 @@ ConvertExceptionToPromise(JSContext* cx,
   if (!JS_GetPendingException(cx, &exn)) {
     // This is very important: if there is no pending exception here but we're
     // ending up in this code, that means the callee threw an uncatchable
     // exception.  Just propagate that out as-is.
     return false;
   }
 
   JS_ClearPendingException(cx);
+
+  nsCOMPtr<nsIGlobalObject> globalObj =
+    do_QueryInterface(global.GetAsSupports());
+  if (!globalObj) {
+    ErrorResult rv;
+    rv.Throw(NS_ERROR_UNEXPECTED);
+    return !rv.MaybeSetPendingException(cx);
+  }
+
   ErrorResult rv;
-  RefPtr<Promise> promise = Promise::Reject(global, exn, rv);
+  RefPtr<Promise> promise = Promise::Reject(globalObj, cx, exn, rv);
   if (rv.MaybeSetPendingException(cx)) {
     // We just give up.  We put the exception from the ErrorResult on
     // the JSContext just to make sure to not leak memory on the
     // ErrorResult, but now just put the original exception back.
     JS_SetPendingException(cx, exn);
     return false;
   }
 
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -5080,22 +5080,29 @@ def getJSToNativeConversionInfo(type, de
         if isPromise:
             templateBody = fill(
                 """
                 { // Scope for our GlobalObject and ErrorResult
 
                   // Might as well use CurrentGlobalOrNull here; that will at
                   // least give us the same behavior as if the caller just called
                   // Promise.resolve() themselves.
-                  GlobalObject promiseGlobal(cx, JS::CurrentGlobalOrNull(cx));
+                  JS::Rooted<JSObject*> globalObj(cx, JS::CurrentGlobalOrNull(cx));
+                  GlobalObject promiseGlobal(cx, globalObj);
                   if (promiseGlobal.Failed()) {
                     $*{exceptionCode}
                   }
                   ErrorResult promiseRv;
-                  $${declName} = Promise::Resolve(promiseGlobal, $${val}, promiseRv);
+                  JS::Handle<JSObject*> promiseCtor =
+                    PromiseBinding::GetConstructorObjectHandle(cx, globalObj);
+                  if (!promiseCtor) {
+                    $*{exceptionCode}
+                  }
+                  JS::Rooted<JS::Value> resolveThisv(cx, JS::ObjectValue(*promiseCtor));
+                  $${declName} = Promise::Resolve(promiseGlobal, resolveThisv, $${val}, promiseRv);
                   if (promiseRv.MaybeSetPendingException(cx)) {
                     $*{exceptionCode}
                   }
                 }
                 """,
                 exceptionCode=exceptionCode)
         elif not descriptor.skipGen and not descriptor.interface.isConsequential() and not descriptor.interface.isExternal():
             if failureCode is not None:
@@ -7049,16 +7056,21 @@ class CGPerSignatureCall(CGThing):
                 argsPost.append("js::GetObjectCompartment(unwrappedObj ? *unwrappedObj : obj)")
         elif needScopeObject(returnType, arguments, self.extendedAttributes,
                              descriptor.wrapperCache, True,
                              idlNode.getExtendedAttribute("StoreInSlot")):
             needsUnwrap = True
             needsUnwrappedVar = True
             argsPre.append("unwrappedObj ? *unwrappedObj : obj")
 
+        if static and not isConstructor and descriptor.name == "Promise":
+            # Hack for Promise for now: pass in the "this" value to
+            # Promise static methods.
+            argsPre.append("args.thisv()")
+
         if needsUnwrap and needsUnwrappedVar:
             # We cannot assign into obj because it's a Handle, not a
             # MutableHandle, so we need a separate Rooted.
             cgThings.append(CGGeneric("Maybe<JS::Rooted<JSObject*> > unwrappedObj;\n"))
             unwrappedVar = "unwrappedObj.ref()"
 
         if idlNode.isMethod() and idlNode.isLegacycaller():
             # If we can have legacycaller with identifier, we can't
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -808,17 +808,17 @@ Promise::CallInitFunction(const GlobalOb
     JS::Rooted<JS::Value> value(cx);
     DebugOnly<bool> conversionResult = ToJSValue(cx, aRv, &value);
     MOZ_ASSERT(conversionResult);
     MaybeRejectInternal(cx, value);
   }
 }
 
 /* static */ already_AddRefed<Promise>
-Promise::Resolve(const GlobalObject& aGlobal,
+Promise::Resolve(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
                  JS::Handle<JS::Value> aValue, ErrorResult& aRv)
 {
   // If a Promise was passed, just return it.
   if (aValue.isObject()) {
     JS::Rooted<JSObject*> valueObj(aGlobal.Context(), &aValue.toObject());
     Promise* nextPromise;
     nsresult rv = UNWRAP_OBJECT(Promise, valueObj, nextPromise);
 
@@ -851,17 +851,17 @@ Promise::Resolve(nsIGlobalObject* aGloba
     return nullptr;
   }
 
   promise->MaybeResolveInternal(aCx, aValue);
   return promise.forget();
 }
 
 /* static */ already_AddRefed<Promise>
-Promise::Reject(const GlobalObject& aGlobal,
+Promise::Reject(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
                 JS::Handle<JS::Value> aValue, ErrorResult& aRv)
 {
   nsCOMPtr<nsIGlobalObject> global =
     do_QueryInterface(aGlobal.GetAsSupports());
   if (!global) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
@@ -1052,26 +1052,26 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(AllReso
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AllResolveElementFunction)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION(AllResolveElementFunction, mCountdownHolder)
 
 /* static */ already_AddRefed<Promise>
-Promise::All(const GlobalObject& aGlobal,
+Promise::All(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
              const Sequence<JS::Value>& aIterable, ErrorResult& aRv)
 {
   JSContext* cx = aGlobal.Context();
 
   nsTArray<RefPtr<Promise>> promiseList;
 
   for (uint32_t i = 0; i < aIterable.Length(); ++i) {
     JS::Rooted<JS::Value> value(cx, aIterable.ElementAt(i));
-    RefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, value, aRv);
+    RefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, aThisv, value, aRv);
 
     MOZ_ASSERT(!aRv.Failed());
 
     promiseList.AppendElement(Move(nextPromise));
   }
 
   return Promise::All(aGlobal, promiseList, aRv);
 }
@@ -1127,17 +1127,17 @@ Promise::All(const GlobalObject& aGlobal
     // index in the array to the resolution value.
     aPromiseList[i]->AppendCallbacks(resolveCb, rejectCb);
   }
 
   return promise.forget();
 }
 
 /* static */ already_AddRefed<Promise>
-Promise::Race(const GlobalObject& aGlobal,
+Promise::Race(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
               const Sequence<JS::Value>& aIterable, ErrorResult& aRv)
 {
   nsCOMPtr<nsIGlobalObject> global =
     do_QueryInterface(aGlobal.GetAsSupports());
   if (!global) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
@@ -1157,17 +1157,17 @@ Promise::Race(const GlobalObject& aGloba
 
   RefPtr<PromiseCallback> resolveCb =
     new ResolvePromiseCallback(promise, obj);
 
   RefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(promise, obj);
 
   for (uint32_t i = 0; i < aIterable.Length(); ++i) {
     JS::Rooted<JS::Value> value(cx, aIterable.ElementAt(i));
-    RefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, value, aRv);
+    RefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, aThisv, 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
     // implementation detail which should never be reached since we are checking
     // for window above. Remove this when subclassing is supported.
     MOZ_ASSERT(!aRv.Failed());
     nextPromise->AppendCallbacks(resolveCb, rejectCb);
   }
 
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -159,48 +159,48 @@ public:
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   static already_AddRefed<Promise>
   Constructor(const GlobalObject& aGlobal, PromiseInit& aInit,
               ErrorResult& aRv, JS::Handle<JSObject*> aDesiredProto);
 
   static already_AddRefed<Promise>
-  Resolve(const GlobalObject& aGlobal,
+  Resolve(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
           JS::Handle<JS::Value> aValue, ErrorResult& aRv);
 
   static already_AddRefed<Promise>
   Resolve(nsIGlobalObject* aGlobal, JSContext* aCx,
           JS::Handle<JS::Value> aValue, ErrorResult& aRv);
 
   static already_AddRefed<Promise>
-  Reject(const GlobalObject& aGlobal,
+  Reject(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
          JS::Handle<JS::Value> aValue, ErrorResult& aRv);
 
   static already_AddRefed<Promise>
   Reject(nsIGlobalObject* aGlobal, JSContext* aCx,
          JS::Handle<JS::Value> aValue, ErrorResult& aRv);
 
   already_AddRefed<Promise>
   Then(JSContext* aCx, AnyCallback* aResolveCallback,
        AnyCallback* aRejectCallback, ErrorResult& aRv);
 
   already_AddRefed<Promise>
   Catch(JSContext* aCx, AnyCallback* aRejectCallback, ErrorResult& aRv);
 
   static already_AddRefed<Promise>
-  All(const GlobalObject& aGlobal,
+  All(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
       const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
 
   static already_AddRefed<Promise>
   All(const GlobalObject& aGlobal,
       const nsTArray<RefPtr<Promise>>& aPromiseList, ErrorResult& aRv);
 
   static already_AddRefed<Promise>
-  Race(const GlobalObject& aGlobal,
+  Race(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
        const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
 
   void AppendNativeHandler(PromiseNativeHandler* aRunnable);
 
   JSObject* GlobalJSObject() const;
 
   JSCompartment* Compartment() const;