Bug 940718 - Create the first safe JSContext in a GC safe location; r=bholley
authorTerrence Cole <terrence@mozilla.com>
Wed, 20 Nov 2013 12:12:11 -0800
changeset 156655 2267eab2fde37e183b87f8821ed6465e648dbcd5
parent 156654 1b04002bea94f11ac5a881a2a8b44e5b5a786cc9
child 156656 1e0009c38c5001a8abc2be368a6f2788886db260
push idunknown
push userunknown
push dateunknown
reviewersbholley
bugs940718
milestone28.0a1
Bug 940718 - Create the first safe JSContext in a GC safe location; r=bholley
content/base/src/nsContentUtils.cpp
js/xpconnect/idl/nsIXPConnect.idl
js/xpconnect/src/XPCJSContextStack.cpp
js/xpconnect/src/nsCxPusher.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -374,26 +374,29 @@ nsContentUtils::Init()
 
   sXPConnect = nsXPConnect::XPConnect();
 
   sSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager();
   if(!sSecurityManager)
     return NS_ERROR_FAILURE;
   NS_ADDREF(sSecurityManager);
 
+  // Getting the first context can trigger GC, so do this non-lazily.
+  sXPConnect->InitSafeJSContext();
+
   rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
   if (NS_FAILED(rv)) {
     // This makes life easier, but we can live without it.
 
     sIOService = nullptr;
   }
 
   rv = CallGetService(NS_LBRK_CONTRACTID, &sLineBreaker);
   NS_ENSURE_SUCCESS(rv, rv);
-  
+
   rv = CallGetService(NS_WBRK_CONTRACTID, &sWordBreaker);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!InitializeEventTable())
     return NS_ERROR_FAILURE;
 
   if (!sEventListenerManagersHash.ops) {
     static const PLDHashTableOps hash_table_ops =
--- a/js/xpconnect/idl/nsIXPConnect.idl
+++ b/js/xpconnect/idl/nsIXPConnect.idl
@@ -268,25 +268,26 @@ interface nsIXPCWrappedJSObjectGetter : 
 [uuid(f5f84b70-92eb-41f1-a1dd-2eaac0ed564c)]
 interface nsIXPCFunctionThisTranslator : nsISupports
 {
     nsISupports TranslateThis(in nsISupports aInitialThis);
 };
 
 /***************************************************************************/
 
+
 %{ C++
 // For use with the service manager
 // {CB6593E0-F9B2-11d2-BDD6-000064657374}
 #define NS_XPCONNECT_CID \
 { 0xcb6593e0, 0xf9b2, 0x11d2, \
     { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
 %}
 
-[uuid(c4d0187c-6a78-4bdf-9cd9-d218644b715a)]
+[uuid(880be309-88a1-4e98-8621-7f7e42681b20)]
 interface nsIXPConnect : nsISupports
 {
 %{ C++
   NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCONNECT_CID)
 %}
 
     /**
      * Initializes classes on a global object that has already been created.
@@ -441,16 +442,17 @@ interface nsIXPConnect : nsISupports
     createStackFrameLocation(in uint32_t       aLanguage,
                              in string         aFilename,
                              in string         aFunctionName,
                              in int32_t        aLineNumber,
                              in nsIStackFrame  aCaller);
 
 
     [noscript,notxpcom,nostdcall] JSContextPtr getCurrentJSContext();
+    [noscript,notxpcom,nostdcall] JSContextPtr initSafeJSContext();
     [noscript,notxpcom,nostdcall] JSContextPtr getSafeJSContext();
 
     readonly attribute nsIStackFrame                CurrentJSStack;
     readonly attribute nsAXPCNativeCallContextPtr   CurrentNativeCallContext;
 
     void debugDump(in short depth);
     void debugDumpObject(in nsISupports aCOMObj, in short depth);
     void debugDumpJSStack(in boolean showArgs,
--- a/js/xpconnect/src/XPCJSContextStack.cpp
+++ b/js/xpconnect/src/XPCJSContextStack.cpp
@@ -129,18 +129,24 @@ const JSClass xpc::SafeJSContextGlobalCl
     JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, SafeGlobalResolve, JS_ConvertStub, SafeFinalize,
     nullptr, nullptr, nullptr, nullptr, TraceXPCGlobal
 };
 
 JSContext*
 XPCJSContextStack::GetSafeJSContext()
 {
-    if (mSafeJSContext)
-        return mSafeJSContext;
+    MOZ_ASSERT(mSafeJSContext);
+    return mSafeJSContext;
+}
+
+JSContext*
+XPCJSContextStack::InitSafeJSContext()
+{
+    MOZ_ASSERT(!mSafeJSContext);
 
     // Start by getting the principal holder and principal for this
     // context.  If we can't manage that, don't bother with the rest.
     nsRefPtr<nsNullPrincipal> principal = new nsNullPrincipal();
     nsresult rv = principal->Init();
     if (NS_FAILED(rv))
         MOZ_CRASH();
 
--- a/js/xpconnect/src/nsCxPusher.cpp
+++ b/js/xpconnect/src/nsCxPusher.cpp
@@ -172,16 +172,17 @@ AutoJSContext::AutoJSContext(bool aSafe 
   : mCx(nullptr)
 {
   Init(aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT);
 }
 
 void
 AutoJSContext::Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
 {
+  JS::AutoAssertNoGC nogc;
   MOZ_ASSERT(!mCx, "mCx should not be initialized!");
 
   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 
   nsXPConnect *xpc = nsXPConnect::XPConnect();
   if (!aSafe) {
     mCx = xpc->GetCurrentJSContext();
   }
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -1277,16 +1277,23 @@ xpc_ActivateDebugMode()
 JSContext*
 nsXPConnect::GetCurrentJSContext()
 {
     return GetRuntime()->GetJSContextStack()->Peek();
 }
 
 /* virtual */
 JSContext*
+nsXPConnect::InitSafeJSContext()
+{
+    return GetRuntime()->GetJSContextStack()->InitSafeJSContext();
+}
+
+/* virtual */
+JSContext*
 nsXPConnect::GetSafeJSContext()
 {
     return GetRuntime()->GetJSContextStack()->GetSafeJSContext();
 }
 
 namespace xpc {
 
 bool
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3028,16 +3028,17 @@ public:
         return mStack.Length();
     }
 
     JSContext *Peek()
     {
         return mStack.IsEmpty() ? nullptr : mStack[mStack.Length() - 1].cx;
     }
 
+    JSContext *InitSafeJSContext();
     JSContext *GetSafeJSContext();
     bool HasJSContext(JSContext *cx);
 
     const InfallibleTArray<XPCJSContextInfo>* GetStack()
     { return &mStack; }
 
 private:
     friend class mozilla::AutoCxPusher;