Bug 543558 - Make sure we're in a request when calling JS_SaveFrameChain/JS_RestoreFrameChain. r=mrbkap
authorLuke Wagner <lw@mozilla.com>
Thu, 04 Feb 2010 16:37:43 -0800
changeset 37912 d3189d83fddc6d89acc632b2d6153fcc4427f25e
parent 37911 31cf1c8d1672653327b004e217f7cfd2cc09dcd9
child 37913 0f817ba0678720b5606ea4a9713577cdfd08535f
push id11492
push usermrbkap@mozilla.com
push dateFri, 05 Feb 2010 00:37:55 +0000
treeherdermozilla-central@d3189d83fddc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs543558
milestone1.9.3a1pre
Bug 543558 - Make sure we're in a request when calling JS_SaveFrameChain/JS_RestoreFrameChain. r=mrbkap
js/src/jsapi.cpp
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpcthreadcontext.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5181,26 +5181,28 @@ JS_PUBLIC_API(JSBool)
 JS_IsConstructing(JSContext *cx)
 {
     return cx->isConstructing();
 }
 
 JS_PUBLIC_API(JSStackFrame *)
 JS_SaveFrameChain(JSContext *cx)
 {
+    CHECK_REQUEST(cx);
     JSStackFrame *fp = js_GetTopStackFrame(cx);
     if (!fp)
         return NULL;
     cx->saveActiveCallStack();
     return fp;
 }
 
 JS_PUBLIC_API(void)
 JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
 {
+    CHECK_REQUEST(cx);
     JS_ASSERT_NOT_ON_TRACE(cx);
     JS_ASSERT(!cx->fp);
     if (!fp)
         return;
     cx->restoreCallStack();
 }
 
 /************************************************************************/
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -1090,20 +1090,21 @@ InitWebGLTypes(JSContext *aJSContext, JS
 
 /* void initClasses (in JSContextPtr aJSContext, in JSObjectPtr aGlobalJSObj); */
 NS_IMETHODIMP
 nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj)
 {
     NS_ASSERTION(aJSContext, "bad param");
     NS_ASSERTION(aGlobalJSObj, "bad param");
 
-    SaveFrame sf(aJSContext);
+    // Nest frame chain save/restore in request created by XPCCallContext.
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if(!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
+    SaveFrame sf(aJSContext);
 
     if(!xpc_InitJSxIDClassObjects())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     if(!xpc_InitWrappedNativeJSOps())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     XPCWrappedNativeScope* scope =
@@ -1130,20 +1131,21 @@ nsXPConnect::InitClasses(JSContext * aJS
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     return NS_OK;
 }
 
 /* void initClassesForOuterObject (in JSContextPtr aJSContext, in JSObjectPtr aGlobalJSObj); */
 NS_IMETHODIMP nsXPConnect::InitClassesForOuterObject(JSContext * aJSContext, JSObject * aGlobalJSObj)
 {
-    SaveFrame sf(aJSContext);
+    // Nest frame chain save/restore in request created by XPCCallContext.
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if(!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
+    SaveFrame sf(aJSContext);
 
     XPCWrappedNativeScope* scope =
         XPCWrappedNativeScope::GetNewOrUsed(ccx, aGlobalJSObj);
 
     if(!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     scope->RemoveWrappedNativeProtos();
@@ -1249,16 +1251,17 @@ nsXPConnect::InitClassesWithNewWrappedGl
     if(protoJSObject)
     {
         if(protoJSObject != globalJSObj)
             JS_SetParent(aJSContext, protoJSObject, globalJSObj);
         JS_SetPrototype(aJSContext, protoJSObject, scope->GetPrototypeJSObject());
     }
 
     if(!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) {
+        // XPCCallContext gives us an active request needed to save/restore.
         SaveFrame sf(ccx);
         if(!nsXPCComponents::AttachNewComponentsObject(ccx, scope, globalJSObj))
             return UnexpectedFailure(NS_ERROR_FAILURE);
 
         if(XPCPerThreadData::IsMainThread(ccx))
         {
             if(!XPCNativeWrapper::AttachNewConstructorObject(ccx, globalJSObj))
                 return UnexpectedFailure(NS_ERROR_FAILURE);
--- a/js/src/xpconnect/src/xpcthreadcontext.cpp
+++ b/js/src/xpconnect/src/xpcthreadcontext.cpp
@@ -95,28 +95,31 @@ XPCJSContextStack::Pop(JSContext * *_ret
 
     if(_retval)
         *_retval = mStack[idx].cx;
 
     mStack.RemoveElementAt(idx);
     if(idx > 0)
     {
         --idx; // Advance to new top of the stack
+
         XPCJSContextInfo & e = mStack[idx];
         NS_ASSERTION(!e.frame || e.cx, "Shouldn't have frame without a cx!");
-        if(e.cx && e.frame)
-        {
-            JS_RestoreFrameChain(e.cx, e.frame);
-            e.frame = nsnull;
-        }
-
         if(e.requestDepth)
             JS_ResumeRequest(e.cx, e.requestDepth);
 
         e.requestDepth = 0;
+
+        if(e.cx && e.frame)
+        {
+            // Pop() can be called outside any request for e.cx.
+            JSAutoRequest ar(e.cx);
+            JS_RestoreFrameChain(e.cx, e.frame);
+            e.frame = nsnull;
+        }
     }
     return NS_OK;
 }
 
 static nsIPrincipal*
 GetPrincipalFromCx(JSContext *cx)
 {
     nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx);
@@ -156,17 +159,21 @@ XPCJSContextStack::Push(JSContext * cx)
                         if(equals)
                         {
                             return NS_OK;
                         }
                     }
                 }
             }
 
-            e.frame = JS_SaveFrameChain(e.cx);
+            {
+                // Push() can be called outside any request for e.cx.
+                JSAutoRequest ar(e.cx);
+                e.frame = JS_SaveFrameChain(e.cx);
+            }
 
             if(e.cx != cx && JS_GetContextThread(e.cx))
                 e.requestDepth = JS_SuspendRequest(e.cx);
         }
     }
     return NS_OK;
 }