Bug 995163 - wrap the Promise value in NativePromiseCallback, r=bz
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 29 Apr 2014 22:12:14 +0100
changeset 201175 5b722269feee1758bc7c7dfb20e9bca8fcee9900
parent 201174 a0db52e1d0ab9cb0d820f1a0d65a2891e9b585bd
child 201176 6bb86257e36aac92c89cd5eb7fc27a66e957c635
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs995163
milestone32.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 995163 - wrap the Promise value in NativePromiseCallback, r=bz
dom/promise/Promise.cpp
dom/promise/PromiseCallback.cpp
dom/promise/PromiseCallback.h
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -860,21 +860,30 @@ Promise::RunTask()
   MOZ_ASSERT(mState != Pending);
 
   nsTArray<nsRefPtr<PromiseCallback>> callbacks;
   callbacks.SwapElements(mState == Resolved ? mResolveCallbacks
                                             : mRejectCallbacks);
   mResolveCallbacks.Clear();
   mRejectCallbacks.Clear();
 
-  ThreadsafeAutoJSContext cx; // Just for rooting.
+  ThreadsafeAutoJSContext cx;
   JS::Rooted<JS::Value> value(cx, mResult);
+  JS::Rooted<JSObject*> wrapper(cx, GetOrCreateWrapper(cx));
+  if (!wrapper) {
+    return;
+  }
+
+  JSAutoCompartment ac(cx, wrapper);
+  if (!MaybeWrapValue(cx, &value)) {
+    return;
+  }
 
   for (uint32_t i = 0; i < callbacks.Length(); ++i) {
-    callbacks[i]->Call(value);
+    callbacks[i]->Call(cx, value);
   }
 }
 
 void
 Promise::MaybeReportRejected()
 {
   if (mState != Rejected || mHadRejectCallback || mResult.isUndefined()) {
     return;
--- a/dom/promise/PromiseCallback.cpp
+++ b/dom/promise/PromiseCallback.cpp
@@ -77,29 +77,29 @@ ResolvePromiseCallback::ResolvePromiseCa
 
 ResolvePromiseCallback::~ResolvePromiseCallback()
 {
   MOZ_COUNT_DTOR(ResolvePromiseCallback);
   DropJSObjects(this);
 }
 
 void
-ResolvePromiseCallback::Call(JS::Handle<JS::Value> aValue)
+ResolvePromiseCallback::Call(JSContext* aCx,
+                             JS::Handle<JS::Value> aValue)
 {
   // Run resolver's algorithm with value and the synchronous flag set.
-  ThreadsafeAutoSafeJSContext cx;
 
-  JSAutoCompartment ac(cx, mGlobal);
-  JS::Rooted<JS::Value> value(cx, aValue);
-  if (!JS_WrapValue(cx, &value)) {
+  JSAutoCompartment ac(aCx, mGlobal);
+  JS::Rooted<JS::Value> value(aCx, aValue);
+  if (!JS_WrapValue(aCx, &value)) {
     NS_WARNING("Failed to wrap value into the right compartment.");
     return;
   }
 
-  mPromise->ResolveInternal(cx, value, Promise::SyncTask);
+  mPromise->ResolveInternal(aCx, value, Promise::SyncTask);
 }
 
 // RejectPromiseCallback
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(RejectPromiseCallback)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(RejectPromiseCallback,
                                                 PromiseCallback)
@@ -137,30 +137,30 @@ RejectPromiseCallback::RejectPromiseCall
 
 RejectPromiseCallback::~RejectPromiseCallback()
 {
   MOZ_COUNT_DTOR(RejectPromiseCallback);
   DropJSObjects(this);
 }
 
 void
-RejectPromiseCallback::Call(JS::Handle<JS::Value> aValue)
+RejectPromiseCallback::Call(JSContext* aCx,
+                            JS::Handle<JS::Value> aValue)
 {
   // Run resolver's algorithm with value and the synchronous flag set.
-  ThreadsafeAutoSafeJSContext cx;
 
-  JSAutoCompartment ac(cx, mGlobal);
-  JS::Rooted<JS::Value> value(cx, aValue);
-  if (!JS_WrapValue(cx, &value)) {
+  JSAutoCompartment ac(aCx, mGlobal);
+  JS::Rooted<JS::Value> value(aCx, aValue);
+  if (!JS_WrapValue(aCx, &value)) {
     NS_WARNING("Failed to wrap value into the right compartment.");
     return;
   }
 
 
-  mPromise->RejectInternal(cx, value, Promise::SyncTask);
+  mPromise->RejectInternal(aCx, value, Promise::SyncTask);
 }
 
 // WrapperPromiseCallback
 NS_IMPL_CYCLE_COLLECTION_CLASS(WrapperPromiseCallback)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WrapperPromiseCallback,
                                                 PromiseCallback)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNextPromise)
@@ -200,118 +200,117 @@ WrapperPromiseCallback::WrapperPromiseCa
 
 WrapperPromiseCallback::~WrapperPromiseCallback()
 {
   MOZ_COUNT_DTOR(WrapperPromiseCallback);
   DropJSObjects(this);
 }
 
 void
-WrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue)
+WrapperPromiseCallback::Call(JSContext* aCx,
+                             JS::Handle<JS::Value> aValue)
 {
-  ThreadsafeAutoSafeJSContext cx;
-
-  JSAutoCompartment ac(cx, mGlobal);
-  JS::Rooted<JS::Value> value(cx, aValue);
-  if (!JS_WrapValue(cx, &value)) {
+  JSAutoCompartment ac(aCx, mGlobal);
+  JS::Rooted<JS::Value> value(aCx, aValue);
+  if (!JS_WrapValue(aCx, &value)) {
     NS_WARNING("Failed to wrap value into the right compartment.");
     return;
   }
 
   ErrorResult rv;
 
   // If invoking callback threw an exception, run resolver's reject with the
   // thrown exception as argument and the synchronous flag set.
-  JS::Rooted<JS::Value> retValue(cx,
+  JS::Rooted<JS::Value> retValue(aCx,
     mCallback->Call(value, rv, CallbackObject::eRethrowExceptions));
 
   rv.WouldReportJSException();
 
   if (rv.Failed() && rv.IsJSException()) {
-    JS::Rooted<JS::Value> value(cx);
-    rv.StealJSException(cx, &value);
+    JS::Rooted<JS::Value> value(aCx);
+    rv.StealJSException(aCx, &value);
 
-    if (!JS_WrapValue(cx, &value)) {
+    if (!JS_WrapValue(aCx, &value)) {
       NS_WARNING("Failed to wrap value into the right compartment.");
       return;
     }
 
-    mNextPromise->RejectInternal(cx, value, Promise::SyncTask);
+    mNextPromise->RejectInternal(aCx, value, Promise::SyncTask);
     return;
   }
 
   // If the return value is the same as the promise itself, throw TypeError.
   if (retValue.isObject()) {
-    JS::Rooted<JSObject*> valueObj(cx, &retValue.toObject());
+    JS::Rooted<JSObject*> valueObj(aCx, &retValue.toObject());
     Promise* returnedPromise;
     nsresult r = UNWRAP_OBJECT(Promise, valueObj, returnedPromise);
 
     if (NS_SUCCEEDED(r) && returnedPromise == mNextPromise) {
       const char* fileName = nullptr;
       uint32_t lineNumber = 0;
 
       // Try to get some information about the callback to report a sane error,
       // but don't try too hard (only deals with scripted functions).
-      JS::Rooted<JSObject*> unwrapped(cx,
+      JS::Rooted<JSObject*> unwrapped(aCx,
         js::CheckedUnwrap(mCallback->Callback()));
 
       if (unwrapped) {
-        JSAutoCompartment ac(cx, unwrapped);
-        if (JS_ObjectIsFunction(cx, unwrapped)) {
-          JS::Rooted<JS::Value> asValue(cx, JS::ObjectValue(*unwrapped));
-          JS::Rooted<JSFunction*> func(cx, JS_ValueToFunction(cx, asValue));
+        JSAutoCompartment ac(aCx, unwrapped);
+        if (JS_ObjectIsFunction(aCx, unwrapped)) {
+          JS::Rooted<JS::Value> asValue(aCx, JS::ObjectValue(*unwrapped));
+          JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, asValue));
 
           MOZ_ASSERT(func);
-          JSScript* script = JS_GetFunctionScript(cx, func);
+          JSScript* script = JS_GetFunctionScript(aCx, func);
           if (script) {
             fileName = JS_GetScriptFilename(script);
-            lineNumber = JS_GetScriptBaseLineNumber(cx, script);
+            lineNumber = JS_GetScriptBaseLineNumber(aCx, script);
           }
         }
       }
 
       // We're back in aValue's compartment here.
-      JS::Rooted<JSString*> stack(cx, JS_GetEmptyString(JS_GetRuntime(cx)));
-      JS::Rooted<JSString*> fn(cx, JS_NewStringCopyZ(cx, fileName));
+      JS::Rooted<JSString*> stack(aCx, JS_GetEmptyString(JS_GetRuntime(aCx)));
+      JS::Rooted<JSString*> fn(aCx, JS_NewStringCopyZ(aCx, fileName));
       if (!fn) {
         // Out of memory. Promise will stay unresolved.
-        JS_ClearPendingException(cx);
+        JS_ClearPendingException(aCx);
         return;
       }
 
-      JS::Rooted<JSString*> message(cx,
-        JS_NewStringCopyZ(cx,
+      JS::Rooted<JSString*> message(aCx,
+        JS_NewStringCopyZ(aCx,
           "then() cannot return same Promise that it resolves."));
       if (!message) {
         // Out of memory. Promise will stay unresolved.
-        JS_ClearPendingException(cx);
+        JS_ClearPendingException(aCx);
         return;
       }
 
-      JS::Rooted<JS::Value> typeError(cx);
-      if (!JS::CreateTypeError(cx, stack, fn, lineNumber, 0,
+      JS::Rooted<JS::Value> typeError(aCx);
+      if (!JS::CreateTypeError(aCx, stack, fn, lineNumber, 0,
                                nullptr, message, &typeError)) {
         // Out of memory. Promise will stay unresolved.
-        JS_ClearPendingException(cx);
+        JS_ClearPendingException(aCx);
         return;
       }
 
-      mNextPromise->RejectInternal(cx, typeError, Promise::SyncTask);
+      mNextPromise->RejectInternal(aCx, typeError, Promise::SyncTask);
       return;
     }
   }
 
   // Otherwise, run resolver's resolve with value and the synchronous flag
   // set.
-  if (!JS_WrapValue(cx, &retValue)) {
+  if (!JS_WrapValue(aCx, &retValue)) {
     NS_WARNING("Failed to wrap value into the right compartment.");
     return;
   }
 
-  mNextPromise->ResolveInternal(cx, retValue, Promise::SyncTask);
+  mNextPromise->ResolveInternal(aCx, retValue, Promise::SyncTask);
 }
 
 // NativePromiseCallback
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(NativePromiseCallback,
                                    PromiseCallback, mHandler)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(NativePromiseCallback)
@@ -330,17 +329,18 @@ NativePromiseCallback::NativePromiseCall
 }
 
 NativePromiseCallback::~NativePromiseCallback()
 {
   MOZ_COUNT_DTOR(NativePromiseCallback);
 }
 
 void
-NativePromiseCallback::Call(JS::Handle<JS::Value> aValue)
+NativePromiseCallback::Call(JSContext* aCx,
+                            JS::Handle<JS::Value> aValue)
 {
   if (mState == Promise::Resolved) {
     mHandler->ResolvedCallback(aValue);
     return;
   }
 
   if (mState == Promise::Rejected) {
     mHandler->RejectedCallback(aValue);
--- a/dom/promise/PromiseCallback.h
+++ b/dom/promise/PromiseCallback.h
@@ -19,17 +19,18 @@ class PromiseCallback : public nsISuppor
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(PromiseCallback)
 
   PromiseCallback();
   virtual ~PromiseCallback();
 
-  virtual void Call(JS::Handle<JS::Value> aValue) = 0;
+  virtual void Call(JSContext* aCx,
+                    JS::Handle<JS::Value> aValue) = 0;
 
   enum Task {
     Resolve,
     Reject
   };
 
   // This factory returns a PromiseCallback object with refcount of 0.
   static PromiseCallback*
@@ -42,17 +43,18 @@ public:
 // aNextPromise->RejectFunction() if the JS Callback throws.
 class WrapperPromiseCallback MOZ_FINAL : public PromiseCallback
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WrapperPromiseCallback,
                                                          PromiseCallback)
 
-  void Call(JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
+  void Call(JSContext* aCx,
+            JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
 
   WrapperPromiseCallback(Promise* aNextPromise, JS::Handle<JSObject*> aGlobal,
                          AnyCallback* aCallback);
   ~WrapperPromiseCallback();
 
 private:
   nsRefPtr<Promise> mNextPromise;
   JS::Heap<JSObject*> mGlobal;
@@ -63,17 +65,18 @@ private:
 // received by Call().
 class ResolvePromiseCallback MOZ_FINAL : public PromiseCallback
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ResolvePromiseCallback,
                                                          PromiseCallback)
 
-  void Call(JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
+  void Call(JSContext* aCx,
+            JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
 
   ResolvePromiseCallback(Promise* aPromise, JS::Handle<JSObject*> aGlobal);
   ~ResolvePromiseCallback();
 
 private:
   nsRefPtr<Promise> mPromise;
   JS::Heap<JSObject*> mGlobal;
 };
@@ -82,17 +85,18 @@ private:
 // received by Call().
 class RejectPromiseCallback MOZ_FINAL : public PromiseCallback
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(RejectPromiseCallback,
                                                          PromiseCallback)
 
-  void Call(JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
+  void Call(JSContext* aCx,
+            JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
 
   RejectPromiseCallback(Promise* aPromise, JS::Handle<JSObject*> aGlobal);
   ~RejectPromiseCallback();
 
 private:
   nsRefPtr<Promise> mPromise;
   JS::Heap<JSObject*> mGlobal;
 };
@@ -100,17 +104,18 @@ private:
 // NativePromiseCallback wraps a NativePromiseHandler.
 class NativePromiseCallback MOZ_FINAL : public PromiseCallback
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(NativePromiseCallback,
                                            PromiseCallback)
 
-  void Call(JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
+  void Call(JSContext* aCx,
+            JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
 
   NativePromiseCallback(PromiseNativeHandler* aHandler,
                         Promise::PromiseState aState);
   ~NativePromiseCallback();
 
 private:
   nsRefPtr<PromiseNativeHandler> mHandler;
   Promise::PromiseState mState;