Bug 1898677 - Cache the result of bytecode encoding condition. r=nbp

Differential Revision: https://phabricator.services.mozilla.com/D211517
This commit is contained in:
Tooru Fujisawa 2024-05-27 06:31:16 +00:00
parent ad246a46f8
commit 071e366ef9
6 changed files with 73 additions and 41 deletions

View file

@ -193,6 +193,10 @@ void ModuleLoader::OnModuleLoadComplete(ModuleLoadRequest* aRequest) {
nsresult ModuleLoader::CompileFetchedModule(
JSContext* aCx, JS::Handle<JSObject*> aGlobal, JS::CompileOptions& aOptions,
ModuleLoadRequest* aRequest, JS::MutableHandle<JSObject*> aModuleOut) {
if (aRequest->IsTextSource()) {
ScriptLoader::CalculateBytecodeCacheFlag(aRequest);
}
if (aRequest->GetScriptLoadContext()->mWasCompiledOMT) {
JS::InstantiationStorage storage;
RefPtr<JS::Stencil> stencil =
@ -209,7 +213,7 @@ nsresult ModuleLoader::CompileFetchedModule(
}
if (aRequest->IsTextSource() &&
ScriptLoader::ShouldCacheBytecode(aRequest)) {
aRequest->PassedConditionForBytecodeEncoding()) {
if (!JS::StartIncrementalEncoding(aCx, std::move(stencil))) {
return NS_ERROR_FAILURE;
}
@ -257,7 +261,8 @@ nsresult ModuleLoader::CompileFetchedModule(
return NS_ERROR_FAILURE;
}
if (aRequest->IsTextSource() && ScriptLoader::ShouldCacheBytecode(aRequest)) {
if (aRequest->IsTextSource() &&
aRequest->PassedConditionForBytecodeEncoding()) {
if (!JS::StartIncrementalEncoding(aCx, std::move(stencil))) {
return NS_ERROR_FAILURE;
}

View file

@ -2368,7 +2368,7 @@ nsresult ScriptLoader::FillCompileOptionsForRequest(
}
/* static */
bool ScriptLoader::ShouldCacheBytecode(ScriptLoadRequest* aRequest) {
void ScriptLoader::CalculateBytecodeCacheFlag(ScriptLoadRequest* aRequest) {
using mozilla::TimeDuration;
using mozilla::TimeStamp;
@ -2378,7 +2378,8 @@ bool ScriptLoader::ShouldCacheBytecode(ScriptLoadRequest* aRequest) {
if (!aRequest->mCacheInfo) {
LOG(("ScriptLoadRequest (%p): Cannot cache anything (cacheInfo = %p)",
aRequest, aRequest->mCacheInfo.get()));
return false;
aRequest->MarkSkippedBytecodeEncoding();
return;
}
// Look at the preference to know which strategy (parameters) should be used
@ -2398,7 +2399,8 @@ bool ScriptLoader::ShouldCacheBytecode(ScriptLoadRequest* aRequest) {
// Reader mode, keep requesting alternate data but no longer save it.
LOG(("ScriptLoadRequest (%p): Bytecode-cache: Encoding disabled.",
aRequest));
return false;
aRequest->MarkSkippedBytecodeEncoding();
return;
}
case -1: {
// Eager mode, skip heuristics!
@ -2430,7 +2432,8 @@ bool ScriptLoader::ShouldCacheBytecode(ScriptLoadRequest* aRequest) {
if (sourceLength < minLength) {
LOG(("ScriptLoadRequest (%p): Bytecode-cache: Script is too small.",
aRequest));
return false;
aRequest->MarkSkippedBytecodeEncoding();
return;
}
}
@ -2442,17 +2445,19 @@ bool ScriptLoader::ShouldCacheBytecode(ScriptLoadRequest* aRequest) {
if (NS_FAILED(aRequest->mCacheInfo->GetCacheTokenFetchCount(&fetchCount))) {
LOG(("ScriptLoadRequest (%p): Bytecode-cache: Cannot get fetchCount.",
aRequest));
return false;
aRequest->MarkSkippedBytecodeEncoding();
return;
}
LOG(("ScriptLoadRequest (%p): Bytecode-cache: fetchCount = %d.", aRequest,
fetchCount));
if (fetchCount < fetchCountMin) {
return false;
aRequest->MarkSkippedBytecodeEncoding();
return;
}
}
LOG(("ScriptLoadRequest (%p): Bytecode-cache: Trigger encoding.", aRequest));
return true;
aRequest->MarkPassedConditionForBytecodeEncoding();
}
class MOZ_RAII AutoSetProcessingScriptTag {
@ -2580,8 +2585,8 @@ nsresult ScriptLoader::CompileOrDecodeClassicScript(
}
MOZ_ASSERT(aRequest->IsSource());
bool encodeBytecode = ShouldCacheBytecode(aRequest);
aExec.SetEncodeBytecode(encodeBytecode);
CalculateBytecodeCacheFlag(aRequest);
aExec.SetEncodeBytecode(aRequest->PassedConditionForBytecodeEncoding());
if (aRequest->GetScriptLoadContext()->mCompileOrDecodeTask) {
// Off-main-thread parsing.
@ -2624,11 +2629,11 @@ nsCString& ScriptLoader::BytecodeMimeTypeFor(ScriptLoadRequest* aRequest) {
void ScriptLoader::MaybePrepareForBytecodeEncodingBeforeExecute(
ScriptLoadRequest* aRequest, JS::Handle<JSScript*> aScript) {
if (!ShouldCacheBytecode(aRequest)) {
if (!aRequest->PassedConditionForBytecodeEncoding()) {
return;
}
aRequest->MarkForBytecodeEncoding(aScript);
aRequest->MarkScriptForBytecodeEncoding(aScript);
}
nsresult ScriptLoader::MaybePrepareForBytecodeEncodingAfterExecute(
@ -2674,7 +2679,7 @@ void ScriptLoader::MaybePrepareModuleForBytecodeEncodingBeforeExecute(
return;
}
if (ShouldCacheBytecode(aRequest)) {
if (aRequest->PassedConditionForBytecodeEncoding()) {
aRequest->MarkModuleForBytecodeEncoding();
}
}

View file

@ -686,7 +686,7 @@ class ScriptLoader final : public JS::loader::ScriptLoaderInterface {
// Returns wether we should save the bytecode of this script after the
// execution of the script.
static bool ShouldCacheBytecode(ScriptLoadRequest* aRequest);
static void CalculateBytecodeCacheFlag(ScriptLoadRequest* aRequest);
void RunScriptWhenSafe(ScriptLoadRequest* aRequest);

View file

@ -87,13 +87,7 @@ class ModuleLoadRequest final : public ScriptLoadRequest {
return mRootModule;
}
bool IsModuleMarkedForBytecodeEncoding() const {
return mIsMarkedForBytecodeEncoding;
}
void MarkModuleForBytecodeEncoding() {
MOZ_ASSERT(!IsModuleMarkedForBytecodeEncoding());
mIsMarkedForBytecodeEncoding = true;
}
void MarkModuleForBytecodeEncoding() { MarkForBytecodeEncoding(); }
// Convenience methods to call into the module loader for this request.
@ -137,11 +131,6 @@ class ModuleLoadRequest final : public ScriptLoadRequest {
// Is this the top level request for a dynamic module import?
const bool mIsDynamicImport;
// True if this module is planned to be saved in the bytecode cache.
// ModuleLoadRequest doesn't use ScriptLoadRequest::mScriptForBytecodeEncoding
// field because the JSScript reference isn't always avaialble for module.
bool mIsMarkedForBytecodeEncoding = false;
// Pointer to the script loader, used to trigger actions when the module load
// finishes.
RefPtr<ModuleLoaderBase> mLoader;

View file

@ -181,21 +181,14 @@ void ScriptLoadRequest::SetPendingFetchingError() {
mState = State::PendingFetchingError;
}
void ScriptLoadRequest::MarkForBytecodeEncoding(JSScript* aScript) {
void ScriptLoadRequest::MarkScriptForBytecodeEncoding(JSScript* aScript) {
MOZ_ASSERT(!IsModuleRequest());
MOZ_ASSERT(!IsMarkedForBytecodeEncoding());
MOZ_ASSERT(!mScriptForBytecodeEncoding);
MarkForBytecodeEncoding();
mScriptForBytecodeEncoding = aScript;
HoldJSObjects(this);
}
bool ScriptLoadRequest::IsMarkedForBytecodeEncoding() const {
if (IsModuleRequest()) {
return AsModuleRequest()->IsModuleMarkedForBytecodeEncoding();
}
return !!mScriptForBytecodeEncoding;
}
static bool IsInternalURIScheme(nsIURI* uri) {
return uri->SchemeIs("moz-extension") || uri->SchemeIs("resource") ||
uri->SchemeIs("chrome");

View file

@ -182,9 +182,33 @@ class ScriptLoadRequest : public nsISupports,
void SetPendingFetchingError();
void MarkForBytecodeEncoding(JSScript* aScript);
bool PassedConditionForBytecodeEncoding() const {
return mBytecodeEncodingPlan == BytecodeEncodingPlan::PassedCondition ||
mBytecodeEncodingPlan == BytecodeEncodingPlan::MarkedForEncode;
}
bool IsMarkedForBytecodeEncoding() const;
void MarkSkippedBytecodeEncoding() {
MOZ_ASSERT(mBytecodeEncodingPlan == BytecodeEncodingPlan::Uninitialized);
mBytecodeEncodingPlan = BytecodeEncodingPlan::Skipped;
}
void MarkPassedConditionForBytecodeEncoding() {
MOZ_ASSERT(mBytecodeEncodingPlan == BytecodeEncodingPlan::Uninitialized);
mBytecodeEncodingPlan = BytecodeEncodingPlan::PassedCondition;
}
bool IsMarkedForBytecodeEncoding() const {
return mBytecodeEncodingPlan == BytecodeEncodingPlan::MarkedForEncode;
}
protected:
void MarkForBytecodeEncoding() {
MOZ_ASSERT(mBytecodeEncodingPlan == BytecodeEncodingPlan::PassedCondition);
mBytecodeEncodingPlan = BytecodeEncodingPlan::MarkedForEncode;
}
public:
void MarkScriptForBytecodeEncoding(JSScript* aScript);
mozilla::CORSMode CORSMode() const { return mFetchOptions->mCORSMode; }
@ -218,6 +242,23 @@ class ScriptLoadRequest : public nsISupports,
State mState; // Are we still waiting for a load to complete?
bool mFetchSourceOnly; // Request source, not cached bytecode.
enum class BytecodeEncodingPlan : uint8_t {
// This is not yet considered for encoding.
Uninitialized,
// This is marked for skipping the encoding.
Skipped,
// This fits the condition for the encoding (e.g. file size, fetch count).
PassedCondition,
// This is marked for encoding, with setting sufficient input,
// e.g. mScriptForBytecodeEncoding for script.
MarkedForEncode,
};
BytecodeEncodingPlan mBytecodeEncodingPlan =
BytecodeEncodingPlan::Uninitialized;
// The referrer policy used for the initial fetch and for fetching any
// imported modules
enum mozilla::dom::ReferrerPolicy mReferrerPolicy;
@ -247,10 +288,9 @@ class ScriptLoadRequest : public nsISupports,
RefPtr<LoadedScript> mLoadedScript;
// Holds the top-level JSScript that corresponds to the current source, once
// it is parsed, and planned to be saved in the bytecode cache.
// it is parsed, and marked to be saved in the bytecode cache.
//
// NOTE: This field is not used for ModuleLoadRequest.
// See ModuleLoadRequest::mIsMarkedForBytecodeEncoding.
JS::Heap<JSScript*> mScriptForBytecodeEncoding;
// Holds the Cache information, which is used to register the bytecode