Bug 1442737: Use shared JSM global for compillation and privileged junk scopes. r?bholley draft
authorKris Maglione <maglione.k@gmail.com>
Sun, 24 Jun 2018 19:16:33 -0700
changeset 810053 34a6812b3fb3113f8bbb9c763f73aa2ff31496e0
parent 810044 4706148f4844738162435bee4f80e3f753303295
push id113871
push usermaglione.k@gmail.com
push dateMon, 25 Jun 2018 02:18:35 +0000
reviewersbholley
bugs1442737
milestone62.0a1
Bug 1442737: Use shared JSM global for compillation and privileged junk scopes. r?bholley MozReview-Commit-ID: 3rLgxQVtc0X
js/xpconnect/loader/ScriptPreloader.cpp
js/xpconnect/loader/ScriptPreloader.h
js/xpconnect/loader/mozJSComponentLoader.h
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
--- a/js/xpconnect/loader/ScriptPreloader.cpp
+++ b/js/xpconnect/loader/ScriptPreloader.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ScriptPreloader-inl.h"
 #include "mozilla/ScriptPreloader.h"
-#include "mozJSComponentLoader.h"
 #include "mozilla/loader/ScriptCacheActors.h"
 
 #include "mozilla/URLPreloader.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/FileUtils.h"
 #include "mozilla/Logging.h"
@@ -432,17 +431,17 @@ ScriptPreloader::InitCache(const nsAStri
 
     if (!XRE_IsParentProcess()) {
         return Ok();
     }
 
     // Grab the compilation scope before initializing the URLPreloader, since
     // it's not safe to run component loader code during its critical section.
     AutoSafeJSAPI jsapi;
-    JS::RootedObject scope(jsapi.cx(), CompilationScope(jsapi.cx()));
+    JS::RootedObject scope(jsapi.cx(), xpc::CompilationScope());
 
     // Note: Code on the main thread *must not access Omnijar in any way* until
     // this AutoBeginReading guard is destroyed.
     URLPreloader::AutoBeginReading abr;
 
     MOZ_TRY(OpenCache());
 
     return InitCacheInternal(scope);
@@ -931,22 +930,16 @@ ScriptPreloader::FinishPendingParses(Mon
 
 void
 ScriptPreloader::DoFinishOffThreadDecode()
 {
     mFinishDecodeRunnablePending = false;
     MaybeFinishOffThreadDecode();
 }
 
-JSObject*
-ScriptPreloader::CompilationScope(JSContext* cx)
-{
-    return mozJSComponentLoader::Get()->CompilationScope(cx);
-}
-
 void
 ScriptPreloader::MaybeFinishOffThreadDecode()
 {
     if (!mToken) {
         return;
     }
 
     auto cleanup = MakeScopeExit([&] () {
@@ -955,17 +948,17 @@ ScriptPreloader::MaybeFinishOffThreadDec
         mParsingScripts.clear();
 
         DecodeNextBatch(OFF_THREAD_CHUNK_SIZE);
     });
 
     AutoSafeJSAPI jsapi;
     JSContext* cx = jsapi.cx();
 
-    JSAutoRealm ar(cx, CompilationScope(cx));
+    JSAutoRealm ar(cx, xpc::CompilationScope());
     JS::Rooted<JS::ScriptVector> jsScripts(cx, JS::ScriptVector(cx));
 
     // If this fails, we still need to mark the scripts as finished. Any that
     // weren't successfully compiled in this operation (which should never
     // happen under ordinary circumstances) will be re-decoded on the main
     // thread, and raise the appropriate errors when they're executed.
     //
     // The exception from the off-thread decode operation will be reported when
@@ -1025,17 +1018,17 @@ ScriptPreloader::DecodeNextBatch(size_t 
     }
 
     if (size == 0 && mPendingScripts.isEmpty()) {
         return;
     }
 
     AutoSafeJSAPI jsapi;
     JSContext* cx = jsapi.cx();
-    JSAutoRealm ar(cx, scope ? scope : CompilationScope(cx));
+    JSAutoRealm ar(cx, scope ? scope : xpc::CompilationScope());
 
     JS::CompileOptions options(cx);
     options.setNoScriptRval(true)
            .setSourceIsLazy(true);
 
     if (!JS::CanCompileOffThread(cx, options, size) ||
         !JS::DecodeMultiOffThreadScripts(cx, options, mParsingSources,
                                          OffThreadDecodeCallback,
--- a/js/xpconnect/loader/ScriptPreloader.h
+++ b/js/xpconnect/loader/ScriptPreloader.h
@@ -389,21 +389,16 @@ private:
     JSScript* WaitForCachedScript(JSContext* cx, CachedScript* script);
 
     void DecodeNextBatch(size_t chunkSize, JS::HandleObject scope = nullptr);
 
     static void OffThreadDecodeCallback(JS::OffThreadToken* token, void* context);
     void MaybeFinishOffThreadDecode();
     void DoFinishOffThreadDecode();
 
-    // Returns the global scope object for off-thread compilation. When global
-    // sharing is enabled in the component loader, this should be the shared
-    // module global. Otherwise, it should be the XPConnect compilation scope.
-    JSObject* CompilationScope(JSContext* cx);
-
     size_t ShallowHeapSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
     {
         return (mallocSizeOf(this) + mScripts.ShallowSizeOfExcludingThis(mallocSizeOf) +
                 mallocSizeOf(mSaveThread.get()) + mallocSizeOf(mProfD.get()));
     }
 
     using ScriptHash = nsClassHashtable<nsCStringHashKey, CachedScript>;
 
--- a/js/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/xpconnect/loader/mozJSComponentLoader.h
@@ -84,17 +84,17 @@ class mozJSComponentLoader final : publi
      * Annotate the crash report with the contents of the async shutdown
      * module/component scripts.
      */
     nsresult AnnotateCrashReport();
 
  protected:
     virtual ~mozJSComponentLoader();
 
-    friend class mozilla::ScriptPreloader;
+    friend class XPCJSRuntime;
 
     JSObject* CompilationScope(JSContext* aCx)
     {
         if (mLoaderGlobal)
             return mLoaderGlobal;
         return GetSharedGlobal(aCx);
     }
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -510,23 +510,23 @@ JSObject*
 UnprivilegedJunkScope()
 {
     return XPCJSRuntime::Get()->UnprivilegedJunkScope();
 }
 
 JSObject*
 PrivilegedJunkScope()
 {
-    return XPCJSRuntime::Get()->PrivilegedJunkScope();
+    return XPCJSRuntime::Get()->LoaderGlobal();
 }
 
 JSObject*
 CompilationScope()
 {
-    return XPCJSRuntime::Get()->CompilationScope();
+    return XPCJSRuntime::Get()->LoaderGlobal();
 }
 
 nsGlobalWindowInner*
 WindowOrNull(JSObject* aObj)
 {
     MOZ_ASSERT(aObj);
     MOZ_ASSERT(!js::IsWrapper(aObj));
 
@@ -2816,18 +2816,17 @@ XPCJSRuntime::Get()
 {
     return nsXPConnect::GetRuntimeInstance();
 }
 
 void
 XPCJSRuntime::Initialize(JSContext* cx)
 {
     mUnprivilegedJunkScope.init(cx, nullptr);
-    mPrivilegedJunkScope.init(cx, nullptr);
-    mCompilationScope.init(cx, nullptr);
+    mLoaderGlobal.init(cx, nullptr);
 
     // these jsids filled in later when we have a JSContext to work with.
     mStrIDs[0] = JSID_VOID;
 
     // Unconstrain the runtime's threshold on nominal heap size, to avoid
     // triggering GC too often if operating continuously near an arbitrary
     // finite threshold (0xffffffff is infinity for uint32_t parameters).
     // This leaves the maximum-JS_malloc-bytes threshold still in effect
@@ -3067,43 +3066,35 @@ XPCJSRuntime::InitSingletonScopes()
 
     // Create the Unprivileged Junk Scope.
     SandboxOptions unprivilegedJunkScopeOptions;
     unprivilegedJunkScopeOptions.sandboxName.AssignLiteral("XPConnect Junk Compartment");
     unprivilegedJunkScopeOptions.invisibleToDebugger = true;
     rv = CreateSandboxObject(cx, &v, nullptr, unprivilegedJunkScopeOptions);
     MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
     mUnprivilegedJunkScope = js::UncheckedUnwrap(&v.toObject());
-
-    // Create the Privileged Junk Scope.
-    SandboxOptions privilegedJunkScopeOptions;
-    privilegedJunkScopeOptions.sandboxName.AssignLiteral("XPConnect Privileged Junk Compartment");
-    privilegedJunkScopeOptions.invisibleToDebugger = true;
-    privilegedJunkScopeOptions.wantComponents = false;
-    rv = CreateSandboxObject(cx, &v, nsXPConnect::SystemPrincipal(), privilegedJunkScopeOptions);
-    MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
-    mPrivilegedJunkScope = js::UncheckedUnwrap(&v.toObject());
-
-    // Create the Compilation Scope.
-    SandboxOptions compilationScopeOptions;
-    compilationScopeOptions.sandboxName.AssignLiteral("XPConnect Compilation Compartment");
-    compilationScopeOptions.invisibleToDebugger = true;
-    compilationScopeOptions.discardSource = ShouldDiscardSystemSource();
-    rv = CreateSandboxObject(cx, &v, /* principal = */ nullptr, compilationScopeOptions);
-    MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
-    mCompilationScope = js::UncheckedUnwrap(&v.toObject());
 }
 
 void
 XPCJSRuntime::DeleteSingletonScopes()
 {
     // We're pretty late in shutdown, so we call ReleaseWrapper on the scopes. This way
     // the GC can collect them immediately, and we don't rely on the CC to clean up.
     RefPtr<SandboxPrivate> sandbox = SandboxPrivate::GetPrivate(mUnprivilegedJunkScope);
     sandbox->ReleaseWrapper(sandbox);
     mUnprivilegedJunkScope = nullptr;
-    sandbox = SandboxPrivate::GetPrivate(mPrivilegedJunkScope);
-    sandbox->ReleaseWrapper(sandbox);
-    mPrivilegedJunkScope = nullptr;
-    sandbox = SandboxPrivate::GetPrivate(mCompilationScope);
-    sandbox->ReleaseWrapper(sandbox);
-    mCompilationScope = nullptr;
+    mLoaderGlobal = nullptr;
 }
+
+JSObject*
+XPCJSRuntime::LoaderGlobal()
+{
+    if (!mLoaderGlobal) {
+        RefPtr<mozJSComponentLoader> loader = mozJSComponentLoader::GetOrCreate();
+
+        JSContext* cx = XPCJSContext::Get()->Context();
+        JSAutoNullableRealm ar(cx, nullptr);
+
+        mLoaderGlobal = loader->GetSharedGlobal(cx);
+        MOZ_RELEASE_ASSERT(!JS_IsExceptionPending(cx));
+    }
+    return mLoaderGlobal;
+}
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -572,18 +572,17 @@ public:
     ~XPCJSRuntime();
 
     void AddGCCallback(xpcGCCallback cb);
     void RemoveGCCallback(xpcGCCallback cb);
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
     JSObject* UnprivilegedJunkScope() { return mUnprivilegedJunkScope; }
-    JSObject* PrivilegedJunkScope() { return mPrivilegedJunkScope; }
-    JSObject* CompilationScope() { return mCompilationScope; }
+    JSObject* LoaderGlobal();
 
     void InitSingletonScopes();
     void DeleteSingletonScopes();
 
     void SystemIsBeingShutDown();
 
 private:
     explicit XPCJSRuntime(JSContext* aCx);
@@ -608,18 +607,17 @@ private:
     nsTArray<nsISupports*> mNativesToReleaseArray;
     bool mDoingFinalization;
     XPCRootSetElem* mVariantRoots;
     XPCRootSetElem* mWrappedJSRoots;
     nsTArray<xpcGCCallback> extraGCCallbacks;
     JS::GCSliceCallback mPrevGCSliceCallback;
     JS::DoCycleCollectionCallback mPrevDoCycleCollectionCallback;
     JS::PersistentRootedObject mUnprivilegedJunkScope;
-    JS::PersistentRootedObject mPrivilegedJunkScope;
-    JS::PersistentRootedObject mCompilationScope;
+    JS::PersistentRootedObject mLoaderGlobal;
     RefPtr<AsyncFreeSnowWhite> mAsyncSnowWhiteFreer;
 
     friend class XPCJSContext;
     friend class XPCIncrementalReleaseRunnable;
 };
 
 inline JS::HandleId
 XPCJSContext::GetStringID(unsigned index) const
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -448,23 +448,26 @@ UnwrapReflectorToISupports(JSObject* ref
  *
  * If you find yourself wanting to use these compartments, you're probably doing
  * something wrong. Callers MUST consult with the XPConnect module owner before
  * using this compartment. If you don't, bholley will hunt you down.
  */
 JSObject*
 UnprivilegedJunkScope();
 
+/**
+ * This will generally be the shared JSM global, but callers should not depend
+ * on that fact.
+ */
 JSObject*
 PrivilegedJunkScope();
 
 /**
  * Shared compilation scope for XUL prototype documents and XBL
- * precompilation. This compartment has a null principal. No code may run, and
- * it is invisible to the debugger.
+ * precompilation.
  */
 JSObject*
 CompilationScope();
 
 /**
  * Returns the nsIGlobalObject corresponding to |aObj|'s JS global.
  */
 nsIGlobalObject*