Bug 901106 - Be more direct in nsXULPrototypeScript::Compile. r=smaug
authorBobby Holley <bobbyholley@gmail.com>
Mon, 19 Aug 2013 16:24:27 -0700
changeset 143153 a7f5e4533a8cc70227a16b3a6a64308663a4ba29
parent 143152 14eeaab1e6680474403855fff10eb5d1362f4be2
child 143154 d3b0012435d2955c43c4e22990d50e48505e5d8c
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerssmaug
bugs901106, 901162
milestone26.0a1
Bug 901106 - Be more direct in nsXULPrototypeScript::Compile. r=smaug Given that this is just the phony compilation global we're dealing with, the only thing relevant about this script context is that it defaults to the right compartment. But we can do that manually with the SafeJSContext. The CanExecuteScripts check was something I added to address review comments in bug 901162 comment 8. I now realize that it's effectively a no-op, because the nsIScriptContext here corresponds to the compilation scope, not the document, so it will never have script disabled.
content/xul/content/src/nsXULElement.cpp
content/xul/content/src/nsXULElement.h
content/xul/document/src/XULDocument.cpp
content/xul/document/src/nsXULContentSink.cpp
content/xul/document/src/nsXULPrototypeDocument.cpp
content/xul/document/src/nsXULPrototypeDocument.h
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -2589,56 +2589,39 @@ OffThreadScriptReceiverCallback(JSScript
 }
 
 nsresult
 nsXULPrototypeScript::Compile(const PRUnichar* aText,
                               int32_t aTextLength,
                               nsIURI* aURI,
                               uint32_t aLineNo,
                               nsIDocument* aDocument,
-                              nsIScriptGlobalObject* aGlobal,
+                              nsXULPrototypeDocument* aProtoDoc,
                               nsIOffThreadScriptReceiver *aOffThreadReceiver /* = nullptr */)
 {
     // We'll compile the script using the prototype document's special
     // script object as the parent. This ensures that we won't end up
     // with an uncollectable reference.
     //
     // Compiling it using (for example) the first document's global
     // object would cause JS to keep a reference via the __proto__ or
     // parent pointer to the first document's global. If that happened,
     // our script object would reference the first document, and the
     // first document would indirectly reference the prototype document
     // because it keeps the prototype cache alive. Circularity!
-    NS_ASSERTION(aGlobal, "prototype doc has no script global");
-    if (!aGlobal) {
-        return NS_ERROR_UNEXPECTED;
-    }
-
-    // Use the prototype document's special context
-    nsIScriptContext *context = aGlobal->GetScriptContext();
-    NS_ASSERTION(context, "no context for script global");
-    if (! context) {
-      return NS_ERROR_UNEXPECTED;
-    }
+    MOZ_ASSERT(aProtoDoc);
+    NS_ENSURE_TRUE(aProtoDoc->GetCompilationGlobal(), NS_ERROR_UNEXPECTED);
+    AutoSafeJSContext cx;
+    JSAutoCompartment ac(cx, aProtoDoc->GetCompilationGlobal());
 
     nsAutoCString urlspec;
     nsContentUtils::GetWrapperSafeScriptFilename(aDocument, aURI, urlspec);
 
     // Ok, compile it to create a prototype script object!
-
-    JSContext* cx = context->GetNativeContext();
-    AutoCxPusher pusher(cx);
-
-    bool ok = false;
-    nsresult rv = nsContentUtils::GetSecurityManager()->
-                    CanExecuteScripts(cx, aDocument->NodePrincipal(), &ok);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(ok, NS_OK);
     NS_ENSURE_TRUE(JSVersion(mLangVersion) != JSVERSION_UNKNOWN, NS_OK);
-
     JS::CompileOptions options(cx);
     options.setPrincipals(nsJSPrincipals::get(aDocument->NodePrincipal()))
            .setFileAndLine(urlspec.get(), aLineNo)
            .setVersion(JSVersion(mLangVersion));
     // If the script was inline, tell the JS parser to save source for
     // Function.prototype.toSource(). If it's out of line, we retrieve the
     // source from the files on demand.
     options.setSourcePolicy(mOutOfLine ? JS::CompileOptions::LAZY_SOURCE
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -35,16 +35,17 @@
 #include "nsStyledElement.h"
 #include "nsIFrameLoader.h"
 #include "jspubtd.h"
 #include "nsFrameLoader.h"
 
 class nsIDocument;
 class nsString;
 class nsIDocShell;
+class nsXULPrototypeDocument;
 
 class nsIObjectInputStream;
 class nsIObjectOutputStream;
 class nsIScriptGlobalObject;
 class nsXULPrototypeNode;
 typedef nsTArray<nsRefPtr<nsXULPrototypeNode> > nsPrototypeArray;
 
 namespace mozilla {
@@ -226,17 +227,17 @@ public:
                                  nsIURI* aDocumentURI,
                                  const nsCOMArray<nsINodeInfo> *aNodeInfos) MOZ_OVERRIDE;
     nsresult DeserializeOutOfLine(nsIObjectInputStream* aInput,
                                   nsIScriptGlobalObject* aGlobal);
 
     nsresult Compile(const PRUnichar* aText, int32_t aTextLength,
                      nsIURI* aURI, uint32_t aLineNo,
                      nsIDocument* aDocument,
-                     nsIScriptGlobalObject* aGlobal,
+                     nsXULPrototypeDocument* aProtoDoc,
                      nsIOffThreadScriptReceiver *aOffThreadReceiver = nullptr);
 
     void UnlinkJSObjects();
 
     void Set(JSScript* aObject);
 
     // It's safe to return a handle because we trace mScriptObject, no one ever
     // uses the handle (or the script object) past the point at which the
--- a/content/xul/document/src/XULDocument.cpp
+++ b/content/xul/document/src/XULDocument.cpp
@@ -3520,17 +3520,17 @@ XULDocument::OnStreamComplete(nsIStreamL
                    "XULDocument can't load multiple scripts at once");
 
         rv = nsScriptLoader::ConvertToUTF16(channel, string, stringLen,
                                             EmptyString(), this, mOffThreadCompileString);
         if (NS_SUCCEEDED(rv)) {
             rv = mCurrentScriptProto->Compile(mOffThreadCompileString.get(),
                                               mOffThreadCompileString.Length(),
                                               uri, 1, this,
-                                              mCurrentPrototype->GetScriptGlobalObject(),
+                                              mCurrentPrototype,
                                               this);
             if (NS_SUCCEEDED(rv) && !mCurrentScriptProto->GetScriptObject()) {
                 // We will be notified via OnOffThreadCompileComplete when the
                 // compile finishes. Keep the contents of the compiled script
                 // alive until the compilation finishes.
                 mOffThreadCompiling = true;
                 BlockOnload();
                 return NS_OK;
--- a/content/xul/document/src/nsXULContentSink.cpp
+++ b/content/xul/document/src/nsXULContentSink.cpp
@@ -562,18 +562,17 @@ XULContentSinkImpl::HandleEndElement(con
 
         // If given a src= attribute, we must ignore script tag content.
         if (!script->mSrcURI && !script->GetScriptObject()) {
             nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
 
             script->mOutOfLine = false;
             if (doc)
                 script->Compile(mText, mTextLength, mDocumentURL,
-                                script->mLineNo, doc,
-                                mPrototype->GetScriptGlobalObject());
+                                script->mLineNo, doc, mPrototype);
         }
 
         FlushText(false);
     }
     break;
 
     default:
         NS_ERROR("didn't expect that");
--- a/content/xul/document/src/nsXULPrototypeDocument.cpp
+++ b/content/xul/document/src/nsXULPrototypeDocument.cpp
@@ -624,16 +624,23 @@ nsXULPrototypeDocument::DocumentPrincipa
 }
 
 void
 nsXULPrototypeDocument::SetDocumentPrincipal(nsIPrincipal* aPrincipal)
 {
     mNodeInfoManager->SetDocumentPrincipal(aPrincipal);
 }
 
+JSObject*
+nsXULPrototypeDocument::GetCompilationGlobal()
+{
+  GetScriptGlobalObject()->EnsureScriptEnvironment();
+  return GetScriptGlobalObject()->GetGlobalJSObject();
+}
+
 nsNodeInfoManager*
 nsXULPrototypeDocument::GetNodeInfoManager()
 {
     return mNodeInfoManager;
 }
 
 
 nsresult
--- a/content/xul/document/src/nsXULPrototypeDocument.h
+++ b/content/xul/document/src/nsXULPrototypeDocument.h
@@ -109,16 +109,18 @@ public:
      * prototype document that the prototype has finished loading.
      * The notification is performed by calling
      * nsIXULDocument::OnPrototypeLoadDone on the registered documents.
      */
     nsresult NotifyLoadDone();
 
     nsNodeInfoManager *GetNodeInfoManager();
 
+    JSObject* GetCompilationGlobal();
+
     // nsIScriptGlobalObjectOwner methods
     virtual nsIScriptGlobalObject* GetScriptGlobalObject() MOZ_OVERRIDE;
 
     void MarkInCCGeneration(uint32_t aCCGeneration)
     {
         mCCGeneration = aCCGeneration;
     }