Bug 1442737: Use shared JSM global for compillation and privileged junk scopes. r?bholley
MozReview-Commit-ID: 3rLgxQVtc0X
--- 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*