Bug 1753709 - JavaScript: Add a preference to switch between delazification strategies. r=arai

This patch changes the way we parse JavaScript coming from Necko while loading
web pages, by adding an about:config flag named
javascript.options.delazification.strategy which is used to select between:

 0 - On Demand
 1 - Concurrent Depth First
 255 - Parse Everything Eagerly

Previously, we moved from On-demand delazification, to parsing everything
eagerly to improve responsiveness of the browser, but we knew that more room for
optimization exists.

This toogle is meant to explore the space of delazification strategies, such
that we can parse functions of JavaScript files on an helper thread, while the
JavaScript file is being executed on the main thread. The space of
delazification strategies goes from ordering the order in which functions are
processed, as well as filtering functions which are processed. Not all functions
have to be delazified, and if the main thread needs a function which is not
parsed yet, it will fallback to parsing it on-demand.

Differential Revision: https://phabricator.services.mozilla.com/D138034
This commit is contained in:
Nicolas B. Pierron
2022-03-01 15:00:03 +00:00
parent a1a9c5bf48
commit 49ef0b3e9d
4 changed files with 76 additions and 18 deletions

View File

@@ -42,6 +42,7 @@
#include "mozilla/net/UrlClassifierFeatureFactory.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_javascript.h"
#include "mozilla/StaticPrefs_network.h"
#include "nsAboutProtocolUtils.h"
#include "nsGkAtoms.h"
@@ -1548,16 +1549,16 @@ nsresult ScriptLoader::AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest,
} else {
MOZ_ASSERT(aRequest->IsTextSource());
if (ShouldFullParse(aRequest)) {
options.setForceFullParse();
if (ShouldApplyDelazifyStrategy(aRequest)) {
ApplyDelazifyStrategy(&options);
mTotalFullParseSize +=
aRequest->ScriptTextLength() > 0
? static_cast<uint32_t>(aRequest->ScriptTextLength())
: 0;
LOG(
("ScriptLoadRequest (%p): Full Parsing Enabled for url=%s "
"mTotalFullParseSize=%u",
("ScriptLoadRequest (%p): non-on-demand-only Parsing Enabled for "
"url=%s mTotalFullParseSize=%u",
aRequest, aRequest->mURI->GetSpecOrDefault().get(),
mTotalFullParseSize));
}
@@ -2972,20 +2973,20 @@ static bool IsInternalURIScheme(nsIURI* uri) {
uri->SchemeIs("chrome");
}
bool ScriptLoader::ShouldFullParse(ScriptLoadRequest* aRequest) {
bool ScriptLoader::ShouldApplyDelazifyStrategy(ScriptLoadRequest* aRequest) {
// Full parse everything if negative.
if (StaticPrefs::dom_script_loader_full_parse_max_size() < 0) {
if (StaticPrefs::dom_script_loader_delazification_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()) {
StaticPrefs::dom_script_loader_delazification_min_mem()) {
return false;
}
uint32_t max_size = static_cast<uint32_t>(
StaticPrefs::dom_script_loader_full_parse_max_size());
StaticPrefs::dom_script_loader_delazification_max_size());
uint32_t script_size =
aRequest->ScriptTextLength() > 0
? static_cast<uint32_t>(aRequest->ScriptTextLength())
@@ -2998,14 +2999,46 @@ bool ScriptLoader::ShouldFullParse(ScriptLoadRequest* aRequest) {
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",
("ScriptLoadRequest (%p): non-on-demand-only 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;
}
void ScriptLoader::ApplyDelazifyStrategy(JS::CompileOptions* aOptions) {
JS::DelazificationOption strategy =
JS::DelazificationOption::ParseEverythingEagerly;
uint32_t strategyIndex =
StaticPrefs::dom_script_loader_delazification_strategy();
// Assert that all enumerated values of DelazificationOption are dense between
// OnDemandOnly and ParseEverythingEagerly.
#ifdef DEBUG
uint32_t count = 0;
uint32_t mask = 0;
# define _COUNT_ENTRIES(Name) count++;
# define _MASK_ENTRIES(Name) \
mask |= 1 << uint32_t(JS::DelazificationOption::Name);
FOREACH_DELAZIFICATION_STRATEGY(_COUNT_ENTRIES);
MOZ_ASSERT(count == uint32_t(strategy) + 1);
FOREACH_DELAZIFICATION_STRATEGY(_MASK_ENTRIES);
MOZ_ASSERT(((mask + 1) & mask) == 0);
# undef _COUNT_ENTRIES
# undef _MASK_ENTRIES
#endif
// Any strategy index larger than ParseEverythingEagerly would default to
// ParseEverythingEagerly.
if (strategyIndex <= uint32_t(strategy)) {
strategy = JS::DelazificationOption(uint8_t(strategyIndex));
}
aOptions->setEagerDelazificationStrategy(strategy);
}
bool ScriptLoader::ShouldCompileOffThread(ScriptLoadRequest* aRequest) {
if (NumberOfProcessors() <= 1) {
return false;