diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp index 657e782d80a0..ba124e732a23 100644 --- a/dom/script/ScriptLoader.cpp +++ b/dom/script/ScriptLoader.cpp @@ -227,6 +227,8 @@ ScriptLoader::ScriptLoader(Document* aDocument) mParserBlockingBlockerCount(0), mBlockerCount(0), mNumberOfProcessors(0), + mTotalFullParseSize(0), + mPhysicalSizeOfMemory(-1), mEnabled(true), mDeferEnabled(false), mSpeculativeOMTParsingEnabled(false), @@ -2582,14 +2584,25 @@ nsresult ScriptLoader::AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest, } } else { MOZ_ASSERT(aRequest->IsTextSource()); + + if (ShouldFullParse(aRequest)) { + options.setForceFullParse(); + mTotalFullParseSize += + aRequest->ScriptTextLength() > 0 + ? static_cast(aRequest->ScriptTextLength()) + : 0; + + LOG( + ("ScriptLoadRequest (%p): Full Parsing Enabled for url=%s " + "mTotalFullParseSize=%u", + aRequest, aRequest->mURI->GetSpecOrDefault().get(), + mTotalFullParseSize)); + } + MaybeSourceText maybeSource; nsresult rv = GetScriptSource(cx, aRequest, &maybeSource); NS_ENSURE_SUCCESS(rv, rv); - if (StaticPrefs::dom_script_loader_full_parse()) { - options.setForceFullParse(); - } - aRequest->mOffThreadToken = maybeSource.constructed>() ? JS::CompileOffThread( @@ -4083,18 +4096,69 @@ void ScriptLoader::ContinueParserAsync( } uint32_t ScriptLoader::NumberOfProcessors() { - if (mNumberOfProcessors > 0) return mNumberOfProcessors; + if (mNumberOfProcessors > 0) { + return mNumberOfProcessors; + } int32_t numProcs = PR_GetNumberOfProcessors(); - if (numProcs > 0) mNumberOfProcessors = numProcs; + if (numProcs > 0) { + mNumberOfProcessors = numProcs; + } return mNumberOfProcessors; } +int32_t ScriptLoader::PhysicalSizeOfMemoryInGB() { + // 0 is a valid result from PR_GetPhysicalMemorySize() which + // means a failure occured. + if (mPhysicalSizeOfMemory >= 0) { + return mPhysicalSizeOfMemory; + } + + // Save the size in GB. + mPhysicalSizeOfMemory = + static_cast(PR_GetPhysicalMemorySize() >> 30); + return mPhysicalSizeOfMemory; +} + static bool IsInternalURIScheme(nsIURI* uri) { return uri->SchemeIs("moz-extension") || uri->SchemeIs("resource") || uri->SchemeIs("chrome"); } +bool ScriptLoader::ShouldFullParse(ScriptLoadRequest* aRequest) { + // Full parse everything if negative. + if (StaticPrefs::dom_script_loader_full_parse_max_size() < 0) { + return true; + } + + // Be conservative on machines with 2GB or less of memory. + if (PhysicalSizeOfMemoryInGB() <= + StaticPrefs::dom_script_loader_full_parse_min_mem()) { + return false; + } + + uint32_t max_size = static_cast( + StaticPrefs::dom_script_loader_full_parse_max_size()); + uint32_t script_size = + aRequest->ScriptTextLength() > 0 + ? static_cast(aRequest->ScriptTextLength()) + : 0; + + if (mTotalFullParseSize + script_size < max_size) { + return true; + } + + if (LOG_ENABLED()) { + nsCString url = aRequest->mURI->GetSpecOrDefault(); + LOG( + ("ScriptLoadRequest (%p): Full Parsing Disabled for (%s) with size=%u" + " because mTotalFullParseSize=%u would exceed max_size=%u", + aRequest, url.get(), script_size, mTotalFullParseSize, max_size)); + } + + return false; +} + bool ScriptLoader::ShouldCompileOffThread(ScriptLoadRequest* aRequest) { if (NumberOfProcessors() <= 1) { return false; diff --git a/dom/script/ScriptLoader.h b/dom/script/ScriptLoader.h index 26413b5781ae..81200bad4ba1 100644 --- a/dom/script/ScriptLoader.h +++ b/dom/script/ScriptLoader.h @@ -623,6 +623,8 @@ class ScriptLoader final : public nsISupports { JS::MutableHandle aIntroductionScript); uint32_t NumberOfProcessors(); + int32_t PhysicalSizeOfMemoryInGB(); + nsresult PrepareLoadedRequest(ScriptLoadRequest* aRequest, nsIIncrementalStreamLoader* aLoader, nsresult aStatus); @@ -631,6 +633,7 @@ class ScriptLoader final : public nsISupports { void AddAsyncRequest(ScriptLoadRequest* aRequest); bool MaybeRemovedDeferRequests(); + bool ShouldFullParse(ScriptLoadRequest* aRequest); bool ShouldCompileOffThread(ScriptLoadRequest* aRequest); void MaybeMoveToLoadedList(ScriptLoadRequest* aRequest); @@ -730,6 +733,8 @@ class ScriptLoader final : public nsISupports { uint32_t mParserBlockingBlockerCount; uint32_t mBlockerCount; uint32_t mNumberOfProcessors; + uint32_t mTotalFullParseSize; + int32_t mPhysicalSizeOfMemory; bool mEnabled; bool mDeferEnabled; bool mSpeculativeOMTParsingEnabled; diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 839ebec93efe..7e3b22c561fb 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -3039,10 +3039,17 @@ value: 0 mirror: always -# Force full parse on any external JS scripts that is being compiled off thread. -- name: dom.script_loader.full_parse - type: bool - value: false +# Maximum total size for all full parsed scripts in each ScriptLoader instance. +# -1 implies full parse everything. Default value is 10MB for utf8 scripts. +- name: dom.script_loader.full_parse_max_size + type: int32_t + value: 10485760 + mirror: always + +# Minimum memory, in GB, required to enable full parsing. +- name: dom.script_loader.full_parse_min_mem + type: int32_t + value: 2 mirror: always # Is support for decoding external (non-inline) classic or module DOM scripts