Backed out 12 changesets (bug 834732) for b2g bustage and OSX mochitest-1 crashes on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 12 Feb 2013 20:54:48 -0500
changeset 131579 a69f329fc7eef21b722b2d6d514d7432f9ec18e8
parent 131578 a20345bfe817e5d2842f2aacb3e2ce816e339cf8
child 131580 5edf10ac61043b929ccf85ed34aed070b61becd6
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs834732
milestone21.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
Backed out 12 changesets (bug 834732) for b2g bustage and OSX mochitest-1 crashes on a CLOSED TREE.
caps/src/nsPrincipal.cpp
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.cpp
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsObjectLoadingContent.cpp
content/events/src/nsEventListenerManager.cpp
docshell/base/nsDocShell.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsJSEnvironment.cpp
dom/base/nsStructuredCloneContainer.cpp
dom/bindings/CallbackObject.cpp
dom/indexedDB/IDBFactory.cpp
dom/sms/src/SmsRequest.cpp
dom/system/gonk/SystemWorkerManager.cpp
js/ipc/ObjectWrapperChild.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/dictionary_helper_gen.py
js/xpconnect/wrappers/WrapperFactory.cpp
layout/base/nsRefreshDriver.cpp
xpfe/appshell/src/nsXULWindow.cpp
--- a/caps/src/nsPrincipal.cpp
+++ b/caps/src/nsPrincipal.cpp
@@ -487,17 +487,18 @@ nsPrincipal::SetDomain(nsIURI* aDomain)
   mDomain = NS_TryToMakeImmutable(aDomain);
   mDomainImmutable = URIIsImmutable(mDomain);
 
   // Domain has changed, forget cached security policy
   SetSecurityPolicy(nullptr);
 
   // Recompute all wrappers between compartments using this principal and other
   // non-chrome compartments.
-  SafeAutoJSContext cx;
+  JSContext *cx = nsContentUtils::GetSafeJSContext();
+  NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
   JSPrincipals *principals = nsJSPrincipals::get(static_cast<nsIPrincipal*>(this));
   bool success = js::RecomputeWrappers(cx, js::ContentCompartmentsOnly(),
                                        js::CompartmentsWithPrincipals(principals));
   NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
   success = js::RecomputeWrappers(cx, js::CompartmentsWithPrincipals(principals),
                                   js::ContentCompartmentsOnly());
   NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
 
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -2200,27 +2200,27 @@ public:
 
   // Returns false if something erroneous happened.
   bool Push(nsIDOMEventTarget *aCurrentTarget);
   // If nothing has been pushed to stack, this works like Push.
   // Otherwise if context will change, Pop and Push will be called.
   bool RePush(nsIDOMEventTarget *aCurrentTarget);
   // If a null JSContext is passed to Push(), that will cause no
   // push to happen and false to be returned.
-  void Push(JSContext *cx);
+  bool Push(JSContext *cx, bool aRequiresScriptContext = true);
   // Explicitly push a null JSContext on the the stack
-  void PushNull();
+  bool PushNull();
 
   // Pop() will be a no-op if Push() or PushNull() fail
   void Pop();
 
   nsIScriptContext* GetCurrentScriptContext() { return mScx; }
 private:
   // Combined code for PushNull() and Push(JSContext*)
-  void DoPush(JSContext* cx);
+  bool DoPush(JSContext* cx);
 
   nsCOMPtr<nsIScriptContext> mScx;
   bool mScriptIsRunning;
   bool mPushedSomething;
 #ifdef DEBUG
   JSContext* mPushedContext;
   unsigned mCompartmentDepthOnEntry;
 #endif
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -3010,24 +3010,29 @@ nsCxPusher::Push(nsIDOMEventTarget *aCur
       DoPush(cx);
     }
 
     // Nothing to do here, I guess.  Have to return true so that event firing
     // will still work correctly even if there is no associated JSContext
     return true;
   }
 
-  JSContext* cx = scx ? scx->GetNativeContext() : nullptr;
+  JSContext* cx = nullptr;
+
+  if (scx) {
+    cx = scx->GetNativeContext();
+    // Bad, no JSContext from script context!
+    NS_ENSURE_TRUE(cx, false);
+  }
 
   // If there's no native context in the script context it must be
   // in the process or being torn down. We don't want to notify the
   // script context about scripts having been evaluated in such a
   // case, calling with a null cx is fine in that case.
-  Push(cx);
-  return true;
+  return Push(cx);
 }
 
 bool
 nsCxPusher::RePush(nsIDOMEventTarget *aCurrentTarget)
 {
   if (!mPushedSomething) {
     return Push(aCurrentTarget);
   }
@@ -3048,60 +3053,74 @@ nsCxPusher::RePush(nsIDOMEventTarget *aC
       return true;
     }
   }
 
   Pop();
   return Push(aCurrentTarget);
 }
 
-void
-nsCxPusher::Push(JSContext *cx)
-{
-  MOZ_ASSERT(!mPushedSomething, "No double pushing with nsCxPusher::Push()!");
-  MOZ_ASSERT(cx);
+bool
+nsCxPusher::Push(JSContext *cx, bool aRequiresScriptContext)
+{
+  if (mPushedSomething) {
+    NS_ERROR("Whaaa! No double pushing with nsCxPusher::Push()!");
+
+    return false;
+  }
+
+  if (!cx) {
+    return false;
+  }
 
   // Hold a strong ref to the nsIScriptContext, just in case
   // XXXbz do we really need to?  If we don't get one of these in Pop(), is
   // that really a problem?  Or do we need to do this to effectively root |cx|?
   mScx = GetScriptContextFromJSContext(cx);
-
-  DoPush(cx);
-}
-
-void
+  if (!mScx && aRequiresScriptContext) {
+    // Should probably return false. See bug 416916.
+    return true;
+  }
+
+  return DoPush(cx);
+}
+
+bool
 nsCxPusher::DoPush(JSContext* cx)
 {
   nsIThreadJSContextStack* stack = nsContentUtils::ThreadJSContextStack();
   if (!stack) {
-    return;
+    return true;
   }
 
   if (cx && IsContextOnStack(stack, cx)) {
     // If the context is on the stack, that means that a script
     // is running at the moment in the context.
     mScriptIsRunning = true;
   }
 
   if (NS_FAILED(stack->Push(cx))) {
-    MOZ_CRASH();
+    mScriptIsRunning = false;
+    mScx = nullptr;
+    return false;
   }
 
   mPushedSomething = true;
 #ifdef DEBUG
   mPushedContext = cx;
   if (cx)
     mCompartmentDepthOnEntry = js::GetEnterCompartmentDepth(cx);
 #endif
-}
-
-void
+  return true;
+}
+
+bool
 nsCxPusher::PushNull()
 {
-  DoPush(nullptr);
+  return DoPush(nullptr);
 }
 
 void
 nsCxPusher::Pop()
 {
   nsIThreadJSContextStack* stack = nsContentUtils::ThreadJSContextStack();
   if (!mPushedSomething || !stack) {
     mScx = nullptr;
@@ -6836,17 +6855,20 @@ AutoJSContext::Init(bool aSafe MOZ_GUARD
   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 
   if (!aSafe) {
     mCx = nsContentUtils::GetCurrentJSContext();
   }
 
   if (!mCx) {
     mCx = nsContentUtils::GetSafeJSContext();
-    mPusher.Push(mCx);
+    bool result = mPusher.Push(mCx);
+    if (!result || !mCx) {
+      MOZ_CRASH();
+    }
   }
 }
 
 AutoJSContext::operator JSContext*()
 {
   return mCx;
 }
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -6176,17 +6176,16 @@ private:
  * @param aOldDocument The document to try to get a context from.
  * @param aNewDocument The document to get aNewScope from.
  * @param aCx [out] Context gotten through one of the scopes, from the stack
  *                  or the safe context.
  * @param aNewScope [out] Scope gotten from aNewDocument.
  */
 static nsresult
 GetContextAndScope(nsIDocument* aOldDocument, nsIDocument* aNewDocument,
-                   nsCxPusher& aPusher,
                    JSContext** aCx, JSObject** aNewScope)
 {
   MOZ_ASSERT(aOldDocument);
   MOZ_ASSERT(aNewDocument);
 
   *aCx = nullptr;
   *aNewScope = nullptr;
 
@@ -6219,19 +6218,16 @@ GetContextAndScope(nsIDocument* aOldDocu
           NS_WARNING("No context reachable in GetContextAndScopes()!");
 
           return NS_ERROR_NOT_AVAILABLE;
         }
       }
     }
   }
 
-  if (cx) {
-    aPusher.Push(cx);
-  }
   if (!newScope && cx) {
     JS::Value v;
     nsresult rv = nsContentUtils::WrapNative(cx, global, aNewDocument,
                                              aNewDocument, &v);
     NS_ENSURE_SUCCESS(rv, rv);
 
     newScope = JSVAL_TO_OBJECT(v);
   }
@@ -6355,19 +6351,18 @@ nsIDocument::AdoptNode(nsINode& aAdopted
     }
   }
 
   nsCOMPtr<nsIDocument> oldDocument = adoptedNode->OwnerDoc();
   bool sameDocument = oldDocument == this;
 
   JSContext *cx = nullptr;
   JSObject *newScope = nullptr;
-  nsCxPusher pusher;
   if (!sameDocument) {
-    rv = GetContextAndScope(oldDocument, this, pusher, &cx, &newScope);
+    rv = GetContextAndScope(oldDocument, this, &cx, &newScope);
     if (rv.Failed()) {
       return nullptr;
     }
   }
 
   nsCOMArray<nsINode> nodesWithProperties;
   rv = nsNodeUtils::Adopt(adoptedNode, sameDocument ? nullptr : mNodeInfoManager,
                           cx, newScope, nodesWithProperties);
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -646,17 +646,17 @@ nsFrameMessageManager::ReceiveMessage(ns
           continue;
         }
         JSObject* object = nullptr;
         wrappedJS->GetJSObject(&object);
         if (!object) {
           continue;
         }
         nsCxPusher pusher;
-        pusher.Push(ctx);
+        NS_ENSURE_STATE(pusher.Push(ctx, false));
 
         JSAutoRequest ar(ctx);
         JSAutoCompartment ac(ctx, object);
 
         // The parameter for the listener function.
         JSObject* param = JS_NewObject(ctx, NULL, NULL, NULL);
         NS_ENSURE_TRUE(param, NS_ERROR_OUT_OF_MEMORY);
 
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -2571,18 +2571,16 @@ nsObjectLoadingContent::NotifyContentObj
   if (!sgo)
     return;
 
   nsIScriptContext *scx = sgo->GetContext();
   if (!scx)
     return;
 
   JSContext *cx = scx->GetNativeContext();
-  nsCxPusher pusher;
-  pusher.Push(cx);
 
   nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
   nsContentUtils::XPConnect()->
   GetWrappedNativeOfNativeObject(cx, sgo->GetGlobalJSObject(), thisContent,
                                  NS_GET_IID(nsISupports),
                                  getter_AddRefs(wrapper));
 
   if (!wrapper) {
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -813,18 +813,18 @@ nsEventListenerManager::CompileEventHand
       nsIURI *uri = doc->GetDocumentURI();
       if (uri) {
         uri->GetSpec(url);
         lineNo = 1;
       }
     }
 
     nsCxPusher pusher;
-    if (aNeedsCxPush) {
-      pusher.Push(cx);
+    if (aNeedsCxPush && !pusher.Push(cx)) {
+      return NS_ERROR_FAILURE;
     }
 
     uint32_t argCount;
     const char **argNames;
     // If no content, then just use kNameSpaceID_None for the
     // namespace ID.  In practice, it doesn't matter since SVG is
     // the only thing with weird arg names and SVG doesn't map event
     // listeners to the window.
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -10198,20 +10198,18 @@ nsDocShell::AddState(nsIVariant *aData, 
         nsCOMPtr<nsIDocument> origDocument =
             do_GetInterface(GetAsSupports(this));
         if (!origDocument)
             return NS_ERROR_DOM_SECURITY_ERR;
         nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
 
         scContainer = new nsStructuredCloneContainer();
         JSContext *cx = aCx;
-        nsCxPusher pusher;
         if (!cx) {
             cx = nsContentUtils::GetContextFromDocument(document);
-            pusher.Push(cx);
         }
         rv = scContainer->InitFromVariant(aData, cx);
 
         // If we're running in the document's context and the structured clone
         // failed, clear the context's pending exception.  See bug 637116.
         if (NS_FAILED(rv) && !aCx) {
             JS_ClearPendingException(aCx);
         }
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -4760,17 +4760,17 @@ BaseStubConstructor(nsIWeakReference* aW
 
       JSObject* object = nullptr;
       wrappedJS->GetJSObject(&object);
       if (!object) {
         return NS_ERROR_UNEXPECTED;
       }
 
       nsCxPusher pusher;
-      pusher.Push(cx);
+      NS_ENSURE_STATE(pusher.Push(cx, false));
 
       JSAutoRequest ar(cx);
       JSAutoCompartment ac(cx, object);
 
       JS::Value thisValue = JSVAL_VOID;
       JS::Value funval;
       if (!JS_GetProperty(cx, object, "constructor", &funval) || !funval.isObject()) {
         return NS_ERROR_UNEXPECTED;
@@ -6123,27 +6123,25 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
   // window's own context (not on some other window-caller's
   // context).
   if (!ObjectIsNativeWrapper(cx, obj)) {
     JSBool did_resolve = JS_FALSE;
     JSBool ok = JS_TRUE;
     JS::Value exn = JSVAL_VOID;
 
     {
-      nsCxPusher pusher;
       Maybe<JSAutoCompartment> ac;
 
       JSContext* my_cx;
       if (!my_context) {
         my_cx = cx;
       } else {
         my_cx = my_context->GetNativeContext();
 
         if (my_cx != cx) {
-          pusher.Push(my_cx);
           ac.construct(my_cx, obj);
         }
       }
 
       JSAutoRequest transfer(my_cx);
 
       // Don't resolve standard classes on XPCNativeWrapper etc, only
       // resolve them if we're resolving on the real global object.
@@ -8507,20 +8505,27 @@ public:
                                   nsIScriptContext* scriptContext)
     : mWrapper(wrapper),
       mContext(scriptContext)
   {
   }
 
   NS_IMETHOD Run()
   {
-    nsCxPusher pusher;
-    JSContext* cx = mContext ? mContext->GetNativeContext()
-                             : nsContentUtils::GetSafeJSContext();
-    pusher.Push(cx);
+    JSContext* cx = nullptr;
+    if (mContext) {
+      cx = mContext->GetNativeContext();
+    } else {
+      nsCOMPtr<nsIThreadJSContextStack> stack =
+        do_GetService("@mozilla.org/js/xpc/ContextStack;1");
+      NS_ENSURE_TRUE(stack, NS_OK);
+
+      cx = stack->GetSafeJSContext();
+      NS_ENSURE_TRUE(cx, NS_OK);
+    }
 
     JSObject* obj = nullptr;
     mWrapper->GetJSObject(&obj);
     NS_ASSERTION(obj, "Should never be null");
     nsHTMLPluginObjElementSH::SetupProtoChain(mWrapper, cx, obj);
     return NS_OK;
   }
 
@@ -8534,17 +8539,21 @@ NS_IMPL_ISUPPORTS1(nsPluginProtoChainIns
 // static
 nsresult
 nsHTMLPluginObjElementSH::SetupProtoChain(nsIXPConnectWrappedNative *wrapper,
                                           JSContext *cx,
                                           JSObject *obj)
 {
   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
                "Shouldn't have gotten in here");
-  MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
+
+  nsCxPusher cxPusher;
+  if (!cxPusher.Push(cx)) {
+    return NS_OK;
+  }
 
   JSAutoRequest ar(cx);
   JSAutoCompartment ac(cx, obj);
 
   nsRefPtr<nsNPAPIPluginInstance> pi;
   nsresult rv = GetPluginInstanceIfSafe(wrapper, obj, cx, getter_AddRefs(pi));
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2080,17 +2080,19 @@ nsGlobalWindow::SetNewDocument(nsIDocume
   }
 
   nsRefPtr<nsGlobalWindow> newInnerWindow;
   bool createdInnerWindow = false;
 
   bool thisChrome = IsChromeWindow();
 
   nsCxPusher cxPusher;
-  cxPusher.Push(cx);
+  if (!cxPusher.Push(cx)) {
+    return NS_ERROR_FAILURE;
+  }
 
   XPCAutoRequest ar(cx);
 
   nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
   NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
 
   if (reUseInnerWindow) {
     // We're reusing the current inner window.
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1255,17 +1255,18 @@ nsJSContext::EvaluateString(const nsAStr
     *aRetValue = JSVAL_VOID;
   }
 
   if (!mScriptsEnabled) {
     return NS_OK;
   }
 
   nsCxPusher pusher;
-  pusher.Push(mContext);
+  if (!pusher.Push(mContext))
+    return NS_ERROR_FAILURE;
 
   xpc_UnmarkGrayObject(&aScopeObject);
   nsAutoMicroTask mt;
 
   JSPrincipals* p = JS_GetCompartmentPrincipals(js::GetObjectCompartment(&aScopeObject));
   aOptions.setPrincipals(p);
 
   bool ok = false;
@@ -1394,45 +1395,46 @@ nsJSContext::ExecuteScript(JSScript* aSc
     aScopeObject = JS_GetGlobalObject(mContext);
   }
 
   xpc_UnmarkGrayScript(aScriptObject);
   xpc_UnmarkGrayObject(aScopeObject);
 
   // Push our JSContext on our thread's context stack, in case native code
   // called from JS calls back into JS via XPConnect.
-  nsCxPusher pusher;
-  pusher.Push(mContext);
+  nsresult rv;
+  nsCOMPtr<nsIJSContextStack> stack =
+           do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
+  if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
+    return NS_ERROR_FAILURE;
+  }
 
   nsJSContext::TerminationFuncHolder holder(this);
   XPCAutoRequest ar(mContext);
-
-  // Scope the JSAutoCompartment so that it gets destroyed before we pop the
-  // cx and potentially call JS_RestoreFrameChain.
-  {
-    JSAutoCompartment ac(mContext, aScopeObject);
-    ++mExecuteDepth;
-
-    // The result of evaluation, used only if there were no errors. This need
-    // not be a GC root currently, provided we run the GC only from the
-    // operation callback or from ScriptEvaluated.
-    jsval val;
-    if (!JS_ExecuteScript(mContext, aScopeObject, aScriptObject, &val)) {
-      ReportPendingException();
-    }
-    --mExecuteDepth;
+  JSAutoCompartment ac(mContext, aScopeObject);
+  ++mExecuteDepth;
+
+  // The result of evaluation, used only if there were no errors. This need
+  // not be a GC root currently, provided we run the GC only from the
+  // operation callback or from ScriptEvaluated.
+  jsval val;
+  if (!JS_ExecuteScript(mContext, aScopeObject, aScriptObject, &val)) {
+    ReportPendingException();
   }
+  --mExecuteDepth;
 
   // Pop here, after JS_ValueToString and any other possible evaluation.
-  pusher.Pop();
+  if (NS_FAILED(stack->Pop(nullptr))) {
+    rv = NS_ERROR_FAILURE;
+  }
 
   // ScriptEvaluated needs to come after we pop the stack
   ScriptEvaluated(true);
 
-  return NS_OK;
+  return rv;
 }
 
 
 #ifdef DEBUG
 bool
 AtomIsEventHandlerName(nsIAtom *aName)
 {
   const PRUnichar *name = aName->GetUTF16String();
@@ -1494,32 +1496,33 @@ nsJSContext::CallEventHandler(nsISupport
   }
 
   SAMPLE_LABEL("JS", "CallEventHandler");
 
   nsAutoMicroTask mt;
   xpc_UnmarkGrayObject(aScope);
   xpc_UnmarkGrayObject(aHandler);
 
-  nsCxPusher pusher;
-  pusher.Push(mContext);
   XPCAutoRequest ar(mContext);
-
   JSObject* target = nullptr;
   nsresult rv = JSObjectFromInterface(aTarget, aScope, &target);
   NS_ENSURE_SUCCESS(rv, rv);
 
   JS::AutoObjectRooter targetVal(mContext, target);
   jsval rval = JSVAL_VOID;
 
   // This one's a lot easier than EvaluateString because we don't have to
   // hassle with principals: they're already compiled into the JS function.
   // xxxmarkh - this comment is no longer true - principals are not used at
   // all now, and never were in some cases.
 
+  nsCxPusher pusher;
+  if (!pusher.Push(mContext, true))
+    return NS_ERROR_FAILURE;
+
   // check if the event handler can be run on the object in question
   rv = sSecurityManager->CheckFunctionAccess(mContext, aHandler, target);
 
   nsJSContext::TerminationFuncHolder holder(this);
 
   if (NS_SUCCEEDED(rv)) {
     // Convert args to jsvals.
     uint32_t argc = 0;
@@ -1742,18 +1745,16 @@ nsJSContext::InitializeExternalClasses()
 }
 
 nsresult
 nsJSContext::SetProperty(JSObject* aTarget, const char* aPropName, nsISupports* aArgs)
 {
   uint32_t  argc;
   jsval    *argv = nullptr;
 
-  nsCxPusher pusher;
-  pusher.Push(mContext);
   XPCAutoRequest ar(mContext);
 
   Maybe<nsRootedJSValueArray> tempStorage;
 
   nsresult rv =
     ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, &argv, tempStorage);
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -45,21 +45,23 @@ nsStructuredCloneContainer::InitFromVari
 
   // First, try to extract a jsval from the variant |aData|.  This works only
   // if the variant implements GetAsJSVal.
   jsval jsData;
   nsresult rv = aData->GetAsJSVal(&jsData);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
 
   // Make sure that we serialize in the right context.
-  MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
   JSAutoRequest ar(aCx);
   JSAutoCompartment ac(aCx, JS_GetGlobalObject(aCx));
   JS_WrapValue(aCx, &jsData);
 
+  nsCxPusher cxPusher;
+  cxPusher.Push(aCx);
+
   uint64_t* jsBytes = nullptr;
   bool success = JS_WriteStructuredClone(aCx, jsData, &jsBytes, &mSize,
                                            nullptr, nullptr, JSVAL_VOID);
   NS_ENSURE_STATE(success);
   NS_ENSURE_STATE(jsBytes);
 
   // Copy jsBytes into our own buffer.
   mData = (uint64_t*) malloc(mSize);
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -82,17 +82,19 @@ CallbackObject::CallSetup::CallSetup(JSO
     // back on using the safe context.
     cx = nsContentUtils::GetSafeJSContext();
   }
 
   // Victory!  We have a JSContext.  Now do the things we need a JSContext for.
   mAr.construct(cx);
 
   // Make sure our JSContext is pushed on the stack.
-  mCxPusher.Push(cx);
+  if (!mCxPusher.Push(cx, false)) {
+    return;
+  }
 
   // After this point we guarantee calling ScriptEvaluated() if we
   // have an nsIScriptContext.
   // XXXbz Why, if, say CheckFunctionAccess fails?  I know that's how
   // nsJSContext::CallEventHandler works, but is it required?
   // FIXME: Bug 807369.
   mCtx = ctx;
 
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -209,17 +209,25 @@ IDBFactory::Create(ContentParent* aConte
     }
   }
 #endif
 
   nsCOMPtr<nsIPrincipal> principal =
     do_CreateInstance("@mozilla.org/nullprincipal;1");
   NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
 
-  SafeAutoJSContext cx;
+  JSContext* cx = nsContentUtils::GetSafeJSContext();
+  NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
+
+  nsCxPusher pusher;
+  if (!pusher.Push(cx)) {
+    NS_WARNING("Failed to push safe JS context!");
+    return NS_ERROR_FAILURE;
+  }
+
   JSAutoRequest ar(cx);
 
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
   NS_ASSERTION(xpc, "This should never be null!");
 
   nsCOMPtr<nsIXPConnectJSObjectHolder> globalHolder;
   nsresult rv = xpc->CreateSandbox(cx, principal, getter_AddRefs(globalHolder));
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/sms/src/SmsRequest.cpp
+++ b/dom/sms/src/SmsRequest.cpp
@@ -518,17 +518,17 @@ SmsRequest::NotifyThreadList(const Infal
   MOZ_ASSERT(cx);
 
   nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(GetOwner());
 
   JSObject* ownerObj = sgo->GetGlobalJSObject();
   NS_ENSURE_TRUE_VOID(ownerObj);
 
   nsCxPusher pusher;
-  pusher.Push(cx);
+  NS_ENSURE_TRUE_VOID(pusher.Push(cx, false));
 
   JSAutoRequest ar(cx);
   JSAutoCompartment ac(cx, ownerObj);
 
   JSObject* array = JS_NewArrayObject(cx, aItems.Length(), nullptr);
   NS_ENSURE_TRUE_VOID(array);
 
   bool ok;
--- a/dom/system/gonk/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -337,17 +337,23 @@ SystemWorkerManager::Init()
 {
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   NS_ASSERTION(NS_IsMainThread(), "We can only initialize on the main thread");
   NS_ASSERTION(!mShutdown, "Already shutdown!");
 
-  AutoSafeJSContext cx;
+  JSContext* cx = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext();
+  NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
+
+  nsCxPusher pusher;
+  if (!pusher.Push(cx, false)) {
+    return NS_ERROR_FAILURE;
+  }
 
   nsresult rv = InitWifi(cx);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to initialize WiFi Networking!");
     return rv;
   }
 
 #ifdef MOZ_WIDGET_GONK
--- a/js/ipc/ObjectWrapperChild.cpp
+++ b/js/ipc/ObjectWrapperChild.cpp
@@ -37,17 +37,17 @@ namespace {
         AutoContextPusher(JSContext* cx
                           MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
             : mRequest(cx)
             , mContext(cx)
             , mSavedOptions(JS_SetOptions(cx, (JS_GetOptions(cx) |
                                                JSOPTION_DONT_REPORT_UNCAUGHT)))
         {
             MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-            mStack.Push(cx);
+            mStack.Push(cx, false);
         }
 
         ~AutoContextPusher() {
             mStack.Pop();
             JS_SetOptions(mContext, mSavedOptions);
         }
 
     };
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3859,114 +3859,148 @@ nsXPCComponents_Utils::EvalInSandbox(con
 }
 
 nsresult
 xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source,
                   const char *filename, int32_t lineNo,
                   JSVersion jsVersion, bool returnStringOnly, jsval *rval)
 {
     JS_AbortIfWrongThread(JS_GetRuntime(cx));
-    JSAutoRequest ar(cx);
-    *rval = JS::UndefinedValue();
 
     bool waiveXray = xpc::WrapperFactory::HasWaiveXrayFlag(sandbox);
     sandbox = js::UnwrapObjectChecked(sandbox);
     if (!sandbox || js::GetObjectJSClass(sandbox) != &SandboxClass) {
         return NS_ERROR_INVALID_ARG;
     }
 
     nsIScriptObjectPrincipal *sop =
         (nsIScriptObjectPrincipal*)xpc_GetJSPrivate(sandbox);
     NS_ASSERTION(sop, "Invalid sandbox passed");
     nsCOMPtr<nsIPrincipal> prin = sop->GetPrincipal();
-    NS_ENSURE_TRUE(prin, NS_ERROR_FAILURE);
+
+    if (!prin) {
+        return NS_ERROR_FAILURE;
+    }
 
     nsAutoCString filenameBuf;
     if (!filename) {
         // Default to the spec of the principal.
         nsJSPrincipals::get(prin)->GetScriptLocation(filenameBuf);
         filename = filenameBuf.get();
         lineNo = 1;
     }
 
-    // We create a separate cx to do the sandbox evaluation. Scope it.
-    JS::Value v = JS::UndefinedValue();
-    JS::Value exn = JS::UndefinedValue();
-    bool ok = true;
+    JSObject *callingScope;
     {
-        // Make a special cx for the sandbox and push it.
-        // NB: As soon as the RefPtr goes away, the cx goes away. So declare
-        // it first so that it disappears last.
-        nsRefPtr<ContextHolder> sandcxHolder = new ContextHolder(cx, sandbox, prin);
-        JSContext *sandcx = sandcxHolder->GetJSContext();
-        if (!sandcx) {
-            JS_ReportError(cx, "Can't prepare context for evalInSandbox");
-            return NS_ERROR_OUT_OF_MEMORY;
+        JSAutoRequest req(cx);
+
+        callingScope = JS_GetGlobalForScopeChain(cx);
+        if (!callingScope) {
+            return NS_ERROR_FAILURE;
         }
-        nsCxPusher pusher;
-        pusher.Push(sandcx);
-
-        JSAutoRequest req(sandcx);
-        JSAutoCompartment ac(sandcx, sandbox);
-
-        if (jsVersion != JSVERSION_DEFAULT)
-            JS_SetVersion(sandcx, jsVersion);
-
-        JS::CompileOptions options(sandcx);
+    }
+
+    nsRefPtr<ContextHolder> sandcx = new ContextHolder(cx, sandbox, prin);
+    if (!sandcx || !sandcx->GetJSContext()) {
+        JS_ReportError(cx, "Can't prepare context for evalInSandbox");
+        return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    if (jsVersion != JSVERSION_DEFAULT)
+        JS_SetVersion(sandcx->GetJSContext(), jsVersion);
+
+    XPCJSContextStack *stack = XPCJSRuntime::Get()->GetJSContextStack();
+    MOZ_ASSERT(stack);
+    if (!stack->Push(sandcx->GetJSContext())) {
+        JS_ReportError(cx, "Unable to initialize XPConnect with the sandbox context");
+        return NS_ERROR_FAILURE;
+    }
+
+    nsresult rv = NS_OK;
+
+    {
+        JSAutoRequest req(sandcx->GetJSContext());
+        JSAutoCompartment ac(sandcx->GetJSContext(), sandbox);
+
+        jsval v;
+        JSString *str = nullptr;
+        JS::CompileOptions options(sandcx->GetJSContext());
         options.setPrincipals(nsJSPrincipals::get(prin))
                .setFileAndLine(filename, lineNo);
-        js::RootedObject rootedSandbox(sandcx, sandbox);
-        ok = JS::Evaluate(sandcx, rootedSandbox, options,
-                          PromiseFlatString(source).get(), source.Length(), &v);
+        js::RootedObject rootedSandbox(sandcx->GetJSContext(), sandbox);
+        bool ok = JS::Evaluate(sandcx->GetJSContext(), rootedSandbox, options,
+                               PromiseFlatString(source).get(), source.Length(), &v);
         if (ok && returnStringOnly && !(JSVAL_IS_VOID(v))) {
-            JSString *str = JS_ValueToString(sandcx, v);
-            ok = !!str;
-            v = ok ? JS::StringValue(str) : JS::UndefinedValue();
+            ok = !!(str = JS_ValueToString(sandcx->GetJSContext(), v));
         }
 
-        // If the sandbox threw an exception, grab it off the context.
-        if (JS_GetPendingException(sandcx, &exn)) {
-            MOZ_ASSERT(!ok);
-            JS_ClearPendingException(sandcx);
-            if (returnStringOnly) {
-                // The caller asked for strings only, convert the
-                // exception into a string.
-                JSString *str = JS_ValueToString(sandcx, exn);
-                exn = str ? JS::StringValue(str) : JS::UndefinedValue();
+        if (!ok) {
+            // The sandbox threw an exception, convert it to a string (if
+            // asked) or convert it to a SJOW.
+
+            jsval exn;
+            if (JS_GetPendingException(sandcx->GetJSContext(), &exn)) {
+                JS_ClearPendingException(sandcx->GetJSContext());
+
+                if (returnStringOnly) {
+                    // The caller asked for strings only, convert the
+                    // exception into a string.
+                    str = JS_ValueToString(sandcx->GetJSContext(), exn);
+
+                    if (str) {
+                        // We converted the exception to a string. Use that
+                        // as the value exception.
+                        exn = STRING_TO_JSVAL(str);
+                        if (JS_WrapValue(cx, &exn)) {
+                            JS_SetPendingException(cx, exn);
+                        } else {
+                            JS_ClearPendingException(cx);
+                            rv = NS_ERROR_FAILURE;
+                        }
+                    } else {
+                        JS_ClearPendingException(cx);
+                        rv = NS_ERROR_FAILURE;
+                    }
+                } else {
+                    if (JS_WrapValue(cx, &exn)) {
+                        JS_SetPendingException(cx, exn);
+                    }
+                }
+
+
+                // Clear str so we don't confuse callers.
+                str = nullptr;
+            } else {
+                rv = NS_ERROR_OUT_OF_MEMORY;
+            }
+        } else {
+            // Convert the result into something safe for our caller.
+            JSAutoRequest req(cx);
+            JSAutoCompartment ac(cx, callingScope);
+
+            if (str) {
+                v = STRING_TO_JSVAL(str);
+            }
+
+            // Transitively apply Xray waivers if |sb| was waived.
+            if (waiveXray && !xpc::WrapperFactory::WaiveXrayAndWrap(cx, &v))
+                rv = NS_ERROR_FAILURE;
+            if (!waiveXray && !JS_WrapValue(cx, &v))
+                rv = NS_ERROR_FAILURE;
+
+            if (NS_SUCCEEDED(rv)) {
+                *rval = v;
             }
         }
     }
 
-    //
-    // Alright, we're back on the caller's cx. If an error occured, try to
-    // wrap and set the exception. Otherwise, wrap the return value.
-    //
-
-    if (!ok) {
-        // If we end up without an exception, it was probably due to OOM along
-        // the way, in which case we thow. Otherwise, wrap it.
-        if (exn.isUndefined() || !JS_WrapValue(cx, &exn))
-            return NS_ERROR_OUT_OF_MEMORY;
-
-        // Set the exception on our caller's cx.
-        JS_SetPendingException(cx, exn);
-        return NS_OK;
-    }
-
-    // Transitively apply Xray waivers if |sb| was waived.
-    if (waiveXray) {
-        ok = xpc::WrapperFactory::WaiveXrayAndWrap(cx, &v);
-    } else {
-        ok = JS_WrapValue(cx, &v);
-    }
-    NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
-
-    // Whew!
-    *rval = v;
-    return NS_OK;
+    if (stack)
+        unused << stack->Pop();
+
+    return rv;
 }
 
 /* JSObject import (in AUTF8String registryLocation,
  *                  [optional] in JSObject targetObj);
  */
 NS_IMETHODIMP
 nsXPCComponents_Utils::Import(const nsACString& registryLocation,
                               const JS::Value& targetObj,
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -487,17 +487,16 @@ nsXPCWrappedJSClass::IsWrappedJS(nsISupp
 {
     void* result;
     NS_PRECONDITION(aPtr, "null pointer");
     return aPtr &&
            NS_OK == aPtr->QueryInterface(NS_GET_IID(WrappedJSIdentity), &result) &&
            result == WrappedJSIdentity::GetSingleton();
 }
 
-// NB: This returns null unless there's nothing on the JSContext stack.
 static JSContext *
 GetContextFromObject(JSObject *obj)
 {
     // Don't stomp over a running context.
     XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack();
 
     if (stack && stack->Peek())
         return nullptr;
--- a/js/xpconnect/src/dictionary_helper_gen.py
+++ b/js/xpconnect/src/dictionary_helper_gen.py
@@ -423,17 +423,17 @@ def write_cpp(iface, fd):
              "  if (!aCx || !aVal) {\n"
              "    return NS_OK;\n"
              "  }\n"
              "  if (!aVal->isObject()) {\n"
              "    return aVal->isNullOrUndefined() ? NS_OK : NS_ERROR_TYPE_ERR;\n"
              "  }\n\n"
              "  JSObject* obj = &aVal->toObject();\n"
              "  nsCxPusher pusher;\n"
-             "  pusher.Push(aCx);\n"
+             "  NS_ENSURE_STATE(pusher.Push(aCx, false));\n"
              "  JSAutoRequest ar(aCx);\n"
              "  JSAutoCompartment ac(aCx, obj);\n")
 
     fd.write("  return %s_InitInternal(*this, aCx, obj);\n}\n\n" %
                  iface.name)
 
 
 if __name__ == '__main__':
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -336,19 +336,16 @@ WrapperFactory::Rewrap(JSContext *cx, JS
                        unsigned flags)
 {
     MOZ_ASSERT(!IsWrapper(obj) ||
                GetProxyHandler(obj) == &XrayWaiver ||
                js::GetObjectClass(obj)->ext.innerObject,
                "wrapped object passed to rewrap");
     MOZ_ASSERT(JS_GetClass(obj) != &XrayUtils::HolderClass, "trying to wrap a holder");
     MOZ_ASSERT(!js::IsInnerObject(obj));
-    // We sometimes end up here after nsContentUtils has been shut down but before
-    // XPConnect has been shut down, so check the context stack the roundabout way.
-    MOZ_ASSERT(XPCJSRuntime::Get()->GetJSContextStack()->Peek() == cx);
 
     // Compute the information we need to select the right wrapper.
     JSCompartment *origin = js::GetObjectCompartment(obj);
     JSCompartment *target = js::GetContextCompartment(cx);
     bool originIsChrome = AccessCheck::isChrome(origin);
     bool targetIsChrome = AccessCheck::isChrome(target);
     bool originSubsumesTarget = AccessCheck::subsumes(origin, target);
     bool targetSubsumesOrigin = AccessCheck::subsumes(target, origin);
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -550,18 +550,20 @@ nsRefreshDriver::AdvanceTimeAndRefresh(i
 
     mTestControllingRefreshes = true;
   }
 
   mMostRecentRefreshEpochTime += aMilliseconds * 1000;
   mMostRecentRefresh += TimeDuration::FromMilliseconds((double) aMilliseconds);
 
   nsCxPusher pusher;
-  pusher.PushNull();
-  DoTick();
+  if (pusher.PushNull()) {
+    DoTick();
+    pusher.Pop();
+  }
 }
 
 void
 nsRefreshDriver::RestoreNormalRefresh()
 {
   mTestControllingRefreshes = false;
   EnsureTimerStarted(false);
 }
--- a/xpfe/appshell/src/nsXULWindow.cpp
+++ b/xpfe/appshell/src/nsXULWindow.cpp
@@ -1795,17 +1795,18 @@ NS_IMETHODIMP nsXULWindow::CreateNewCont
   }
   NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
 
   // We need to create a chrome window to contain the content window we're about
   // to pass back. The subject principal needs to be system while we're creating
   // it to make things work right, so push a null cx. See bug 799348 comment 13
   // for a description of what happens when we don't.
   nsCxPusher pusher;
-  pusher.PushNull();
+  if (!pusher.PushNull())
+    return NS_ERROR_FAILURE;
   nsCOMPtr<nsIXULWindow> newWindow;
   appShell->CreateTopLevelWindow(this, uri,
                                  aChromeFlags, 615, 480,
                                  getter_AddRefs(newWindow));
   NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE);
   pusher.Pop();
 
   // Specify that we want the window to remain locked until the chrome has loaded.