Bug 1381976: Part 1 - Use the shared module global for script pre-compilation. r=mccr8

When we pre-compile scripts for a different global than they are eventually
executed in, we need to clone them into the new global before we can execute
them, which can be expensive. This also prevents us from using lazy parsing,
since lazy functions are currently eagerly compiled when cloned.

Since the vast majority of the scripts compiled by the preloader are executed
in the shared modules scope, initially compiling them there removes a lot of
startup overhead. For the few that aren't, we don't lose anything by compiling
them in the shared module global, but we also don't gain anything over
compiling them in the XPConnect compilation scope.

MozReview-Commit-ID: CEh42BmIMhL

--HG--
extra : rebase_source : 93f639022375dd3f0b8e06533e829ce4089d46b7
This commit is contained in:
Kris Maglione 2017-08-25 19:36:44 -07:00
Родитель 4ebd2fb5c9
Коммит 3529438886
4 изменённых файлов: 72 добавлений и 26 удалений

Просмотреть файл

@ -6,6 +6,7 @@
#include "ScriptPreloader-inl.h"
#include "mozilla/ScriptPreloader.h"
#include "mozJSComponentLoader.h"
#include "mozilla/loader/ScriptCacheActors.h"
#include "mozilla/URLPreloader.h"
@ -907,6 +908,12 @@ ScriptPreloader::DoFinishOffThreadDecode()
MaybeFinishOffThreadDecode();
}
JSObject*
ScriptPreloader::CompilationScope(JSContext* cx)
{
return mozJSComponentLoader::Get()->CompilationScope(cx);
}
void
ScriptPreloader::MaybeFinishOffThreadDecode()
{
@ -922,10 +929,10 @@ ScriptPreloader::MaybeFinishOffThreadDecode()
DecodeNextBatch(OFF_THREAD_CHUNK_SIZE);
});
AutoJSAPI jsapi;
MOZ_RELEASE_ASSERT(jsapi.Init(xpc::CompilationScope()));
AutoSafeJSAPI jsapi;
JSContext* cx = jsapi.cx();
JSAutoCompartment ac(cx, CompilationScope(cx));
JS::Rooted<JS::ScriptVector> jsScripts(cx, JS::ScriptVector(cx));
// If this fails, we still need to mark the scripts as finished. Any that
@ -993,9 +1000,9 @@ ScriptPreloader::DecodeNextBatch(size_t chunkSize)
return;
}
AutoJSAPI jsapi;
MOZ_RELEASE_ASSERT(jsapi.Init(xpc::CompilationScope()));
AutoSafeJSAPI jsapi;
JSContext* cx = jsapi.cx();
JSAutoCompartment ac(cx, CompilationScope(cx));
JS::CompileOptions options(cx, JSVERSION_DEFAULT);
options.setNoScriptRval(true)

Просмотреть файл

@ -390,6 +390,11 @@ private:
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) +

Просмотреть файл

@ -301,6 +301,8 @@ NS_IMPL_ISUPPORTS(mozJSComponentLoader,
nsresult
mozJSComponentLoader::ReallyInit()
{
MOZ_ASSERT(!mInitialized);
mShareLoaderGlobal = Preferences::GetBool("jsloader.shareGlobal");
nsresult rv;
@ -468,7 +470,7 @@ mozJSComponentLoader::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
void
mozJSComponentLoader::CreateLoaderGlobal(JSContext* aCx,
nsACString& aLocation,
const nsACString& aLocation,
JSAddonId* aAddonID,
MutableHandleObject aGlobal)
{
@ -550,6 +552,31 @@ mozJSComponentLoader::ReuseGlobal(bool aIsAddon, nsIURI* aURI)
return true;
}
JSObject*
mozJSComponentLoader::GetSharedGlobal(JSContext* aCx)
{
if (!mLoaderGlobal) {
MOZ_ASSERT(mShareLoaderGlobal);
JS::RootedObject globalObj(aCx);
CreateLoaderGlobal(aCx, NS_LITERAL_CSTRING("shared JSM global"),
nullptr, &globalObj);
// If we fail to create a module global this early, we're not going to
// get very far, so just bail out now.
MOZ_RELEASE_ASSERT(globalObj);
mLoaderGlobal = globalObj;
// AutoEntryScript required to invoke debugger hook, which is a
// Gecko-specific concept at present.
dom::AutoEntryScript aes(globalObj,
"component loader report global");
JS_FireOnNewGlobalObject(aes.cx(), globalObj);
}
return mLoaderGlobal;
}
JSObject*
mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
nsIFile* aComponentFile,
@ -567,25 +594,10 @@ mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
bool createdNewGlobal = false;
RootedObject globalObj(aCx);
if (reuseGlobal)
globalObj = mLoaderGlobal;
if (!globalObj) {
nsAutoCString globalLocation;
if (reuseGlobal) {
globalLocation.AssignLiteral("shared JSM global");
} else {
globalLocation.Assign(nativePath);
}
CreateLoaderGlobal(aCx, globalLocation,
addonId, &globalObj);
NS_ENSURE_TRUE(globalObj, nullptr);
if (reuseGlobal) {
mLoaderGlobal = globalObj;
}
if (reuseGlobal) {
globalObj = GetSharedGlobal(aCx);
} else if (!globalObj) {
CreateLoaderGlobal(aCx, nativePath, addonId, &globalObj);
createdNewGlobal = true;
}

Просмотреть файл

@ -20,12 +20,18 @@
#include "jsapi.h"
#include "xpcIJSGetFactory.h"
#include "xpcpublic.h"
class nsIFile;
class nsIPrincipal;
class nsIXPConnectJSObjectHolder;
class ComponentLoaderInfo;
namespace mozilla {
class ScriptPreloader;
} // namespace mozilla
/* 6bd13476-1dd2-11b2-bbef-f0ccb5fa64b6 (thanks, mozbot) */
#define MOZJSCOMPONENTLOADER_CID \
@ -71,12 +77,28 @@ class mozJSComponentLoader : public mozilla::ModuleLoader,
void UnloadModules();
void CreateLoaderGlobal(JSContext* aCx,
nsACString& aLocation,
const nsACString& aLocation,
JSAddonId* aAddonID,
JS::MutableHandleObject aGlobal);
bool ReuseGlobal(bool aIsAddon, nsIURI* aComponent);
friend class mozilla::ScriptPreloader;
JSObject* CompilationScope(JSContext* aCx)
{
if (mLoaderGlobal)
return mLoaderGlobal;
if ((mInitialized || NS_SUCCEEDED(ReallyInit())) &&
mShareLoaderGlobal)
{
return GetSharedGlobal(aCx);
}
return xpc::CompilationScope();
}
JSObject* GetSharedGlobal(JSContext* aCx);
JSObject* PrepareObjectForLocation(JSContext* aCx,
nsIFile* aComponentFile,
nsIURI* aComponent,