Bug 1455217 - Part 2: Add support for promises to XPCConvert, r=mccr8
authorNika Layzell <nika@thelayzells.com>
Mon, 30 Apr 2018 15:54:52 -0400
changeset 418275 6b0ed3df62bd0c8b2fd1cb9ec460f271d67624e7
parent 418274 15e62b365b36d8400bc4f91721ea162ea53428d0
child 418276 5e2fa34896c4fc88755ec28d615a813ef84cf668
push id33997
push userncsoregi@mozilla.com
push dateTue, 15 May 2018 09:53:53 +0000
treeherdermozilla-central@cf3ee1402348 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs1455217
milestone62.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 1455217 - Part 2: Add support for promises to XPCConvert, r=mccr8
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCWrappedNative.cpp
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -350,16 +350,32 @@ XPCConvert::NativeData2JS(MutableHandleV
         if (!ptr) {
             d.setNull();
             return true;
         }
 
         return type.GetDOMObjectInfo().Wrap(cx, ptr, d);
     }
 
+    case nsXPTType::T_PROMISE:
+    {
+        Promise* promise = *static_cast<Promise* const*>(s);
+        if (!promise) {
+            d.setNull();
+            return true;
+        }
+
+        RootedObject jsobj(cx, promise->PromiseObj());
+        if (!JS_WrapObject(cx, &jsobj)) {
+            return false;
+        }
+        d.setObject(*jsobj);
+        return true;
+    }
+
     default:
         NS_ERROR("bad type");
         return false;
     }
     return true;
 }
 
 /***************************************************************************/
@@ -731,16 +747,39 @@ XPCConvert::JSData2Native(void* d, Handl
 
         nsresult err = type.GetDOMObjectInfo().Unwrap(s, (void**)d);
         if (pErr) {
             *pErr = err;
         }
         return NS_SUCCEEDED(err);
     }
 
+    case nsXPTType::T_PROMISE:
+    {
+        nsIGlobalObject* glob = NativeGlobal(CurrentGlobalOrNull(cx));
+        if (!glob) {
+            if (pErr) {
+                *pErr = NS_ERROR_UNEXPECTED;
+            }
+            return false;
+        }
+
+        // Call Promise::Resolve to create a Promise object. This allows us to
+        // support returning non-promise values from Promise-returning functions
+        // in JS.
+        IgnoredErrorResult err;
+        *(Promise**)d = Promise::Resolve(glob, cx, s, err).take();
+        bool ok = !err.Failed();
+        if (pErr) {
+            *pErr = err.StealNSResult();
+        }
+
+        return ok;
+    }
+
     default:
         NS_ERROR("bad type");
         return false;
     }
     return true;
 }
 
 /***************************************************************************/
@@ -791,16 +830,17 @@ XPCConvert::NativeInterface2JSObject(Mut
     }
     if (flat) {
         if (allowNativeWrapper && !JS_WrapObject(cx, &flat))
             return false;
         d.setObjectOrNull(flat);
         return true;
     }
 
+    // NOTE(nika): Remove if Promise becomes non-nsISupports
     if (iid->Equals(NS_GET_IID(nsISupports))) {
         // Check for a Promise being returned via nsISupports.  In that
         // situation, we want to dig out its underlying JS object and return
         // that.
         RefPtr<Promise> promise = do_QueryObject(aHelper.Object());
         if (promise) {
             flat = promise->PromiseObj();
             if (!JS_WrapObject(cx, &flat))
@@ -932,16 +972,17 @@ XPCConvert::JSObject2NativeInterface(voi
                     iface = nsPIDOMWindowInner::From(inner)->GetOuterWindow();
                     return NS_SUCCEEDED(iface->QueryInterface(*iid, dest));
                 }
             }
 
             return false;
         }
 
+        // NOTE(nika): Remove if Promise becomes non-nsISupports
         // Deal with Promises being passed as nsISupports.  In that situation we
         // want to create a dom::Promise and use that.
         if (iid->Equals(NS_GET_IID(nsISupports))) {
             RootedObject innerObj(cx, inner);
             if (IsPromiseObject(innerObj)) {
                 nsIGlobalObject* glob = NativeGlobal(innerObj);
                 RefPtr<Promise> p = Promise::CreateFromExisting(glob, innerObj);
                 return p && NS_SUCCEEDED(p->QueryInterface(*iid, dest));
@@ -1288,16 +1329,17 @@ XPCConvert::NativeArray2JS(MutableHandle
     case nsXPTType::T_VOID          : NS_ERROR("bad type");     return false;
     case nsXPTType::T_IID           : POPULATE(nsID*);          break;
     case nsXPTType::T_DOMSTRING     : NS_ERROR("bad type");     return false;
     case nsXPTType::T_CHAR_STR      : POPULATE(char*);          break;
     case nsXPTType::T_WCHAR_STR     : POPULATE(char16_t*);      break;
     case nsXPTType::T_INTERFACE     : POPULATE(nsISupports*);   break;
     case nsXPTType::T_INTERFACE_IS  : POPULATE(nsISupports*);   break;
     case nsXPTType::T_DOMOBJECT     : POPULATE(void*);          break;
+    case nsXPTType::T_PROMISE       : POPULATE(Promise*);       break;
     case nsXPTType::T_UTF8STRING    : NS_ERROR("bad type");     return false;
     case nsXPTType::T_CSTRING       : NS_ERROR("bad type");     return false;
     case nsXPTType::T_ASTRING       : NS_ERROR("bad type");     return false;
     default                         : NS_ERROR("bad type");     return false;
     }
 
     if (pErr)
         *pErr = NS_OK;
@@ -1552,16 +1594,17 @@ XPCConvert::JSArray2Native(void** d, Han
         for (initedCount = 0; initedCount < count; initedCount++) {            \
             if (!JS_GetElement(cx, jsarray, initedCount, &current) ||          \
                 !JSData2Native(((_t*)array)+initedCount, current, type,        \
                                iid, pErr))                                     \
                 goto failure;                                                  \
         }                                                                      \
     PR_END_MACRO
 
+    // NOTE(nika): Add a cleanup mode if Promise becomes non-nsISupports.
     // No Action, FRee memory, RElease object, CLeanup object
     enum CleanupMode {na, fr, re, cl};
 
     CleanupMode cleanupMode;
 
     void* array = nullptr;
     uint32_t initedCount;
     RootedValue current(cx);
@@ -1586,16 +1629,17 @@ XPCConvert::JSArray2Native(void** d, Han
     case nsXPTType::T_VOID          : NS_ERROR("bad type");         goto failure;
     case nsXPTType::T_IID           : POPULATE(fr, nsID*);          break;
     case nsXPTType::T_DOMSTRING     : NS_ERROR("bad type");         goto failure;
     case nsXPTType::T_CHAR_STR      : POPULATE(fr, char*);          break;
     case nsXPTType::T_WCHAR_STR     : POPULATE(fr, char16_t*);      break;
     case nsXPTType::T_INTERFACE     : POPULATE(re, nsISupports*);   break;
     case nsXPTType::T_INTERFACE_IS  : POPULATE(re, nsISupports*);   break;
     case nsXPTType::T_DOMOBJECT     : POPULATE(cl, void*);          break;
+    case nsXPTType::T_PROMISE       : POPULATE(re, Promise*);       break;
     case nsXPTType::T_UTF8STRING    : NS_ERROR("bad type");         goto failure;
     case nsXPTType::T_CSTRING       : NS_ERROR("bad type");         goto failure;
     case nsXPTType::T_ASTRING       : NS_ERROR("bad type");         goto failure;
     default                         : NS_ERROR("bad type");         goto failure;
     }
 
     *d = array;
     if (pErr)
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -1893,16 +1893,17 @@ CallMethodHelper::CleanupParam(nsXPTCMin
     // the null checking for all the different types into one check here.
     if (type.TagPart() != nsXPTType::T_JSVAL && param.val.p == nullptr)
         return;
 
     switch (type.TagPart()) {
         case nsXPTType::T_JSVAL:
             js::RemoveRawValueRoot(mCallContext, &param.val.j);
             break;
+        case nsXPTType::T_PROMISE: // NOTE(nika): Change if Promise becomes non-nsISupports
         case nsXPTType::T_INTERFACE:
         case nsXPTType::T_INTERFACE_IS:
             ((nsISupports*)param.val.p)->Release();
             break;
         case nsXPTType::T_DOMOBJECT:
             type.GetDOMObjectInfo().Cleanup(param.val.p);
             break;
         case nsXPTType::T_ASTRING: