tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit f70e74238bc9d8ab7b816f2b66b85cc9d9c45d02
parent f211bee4de135ca2126ff3d277c19e42b6975376
Author: Tooru Fujisawa <arai_a@mac.com>
Date:   Fri, 31 Oct 2025 05:22:08 +0000

Bug 1980154 - Part 4: Use SharedScriptCache for disk cache handling when navigation cache is enabled. r=nbp

Differential Revision: https://phabricator.services.mozilla.com/D270524

Diffstat:
Mdom/base/test/browser_script_loader_js_cache.js | 44+++++++++++++++++++++++++-------------------
Mdom/script/ScriptLoader.cpp | 62+++++++++++++++++++++++++++++++++++++++++++++-----------------
Mdom/script/ScriptTrace.h | 13+++++++++++++
Mdom/script/SharedScriptCache.cpp | 29+++++++++++++++++++++++++++++
Mdom/script/SharedScriptCache.h | 1+
5 files changed, 113 insertions(+), 36 deletions(-)

diff --git a/dom/base/test/browser_script_loader_js_cache.js b/dom/base/test/browser_script_loader_js_cache.js @@ -1,9 +1,9 @@ const BASE_URL = "http://mochi.test:8888/browser/dom/base/test/"; -function ev(event, file, hasElement = true) { +function ev(event, file, hasElement = !!file) { return { event, - url: BASE_URL + file, + url: file ? BASE_URL + file : undefined, hasElement, }; } @@ -23,7 +23,7 @@ async function contentTask(item) { const event = item.events[0]; if ( event.event === param.event && - event.url === param.url && + (!param.url || event.url === param.url) && (event.hasElement ? param.id === "watchme" : !param.id) ) { dump("@@@ Got expected event: " + data + "\n"); @@ -232,6 +232,13 @@ add_task(async function testMemoryCache() { ], }); + // If in-memory cache is enabled, the disk cache is handled by the + // SharedScriptCache, and following differences happen: + // * diskcache:disabled and diskcache:register are not notified for + // each script + // * diskcache:noschedule is notified without associated script + // if there's no script to be saved + await runTests([ // A small file should be saved to the memory on the 1st load, and used on // the 2nd load. But it shouldn't be saved to the disk cache. @@ -244,7 +251,7 @@ add_task(async function testMemoryCache() { ev("load:source", "file_js_cache_small.js"), ev("memorycache:saved", "file_js_cache_small.js"), ev("evaluate:classic", "file_js_cache_small.js"), - ev("diskcache:disabled", "file_js_cache_small.js"), + ev("diskcache:noschedule"), ], }, { @@ -252,7 +259,7 @@ add_task(async function testMemoryCache() { events: [ ev("load:memorycache", "file_js_cache_small.js"), ev("evaluate:classic", "file_js_cache_small.js"), - ev("diskcache:disabled", "file_js_cache_small.js"), + ev("diskcache:noschedule"), ], }, { @@ -260,7 +267,7 @@ add_task(async function testMemoryCache() { events: [ ev("load:memorycache", "file_js_cache_small.js"), ev("evaluate:classic", "file_js_cache_small.js"), - ev("diskcache:disabled", "file_js_cache_small.js"), + ev("diskcache:noschedule"), ], }, { @@ -268,7 +275,7 @@ add_task(async function testMemoryCache() { events: [ ev("load:memorycache", "file_js_cache_small.js"), ev("evaluate:classic", "file_js_cache_small.js"), - ev("diskcache:disabled", "file_js_cache_small.js"), + ev("diskcache:noschedule"), ], }, ], @@ -288,7 +295,7 @@ add_task(async function testMemoryCache() { ev("load:source", "file_js_cache_large.js"), ev("memorycache:saved", "file_js_cache_large.js"), ev("evaluate:classic", "file_js_cache_large.js"), - ev("diskcache:disabled", "file_js_cache_large.js"), + ev("diskcache:noschedule"), ], }, { @@ -296,7 +303,7 @@ add_task(async function testMemoryCache() { events: [ ev("load:memorycache", "file_js_cache_large.js"), ev("evaluate:classic", "file_js_cache_large.js"), - ev("diskcache:disabled", "file_js_cache_large.js"), + ev("diskcache:noschedule"), ], }, { @@ -304,7 +311,7 @@ add_task(async function testMemoryCache() { events: [ ev("load:memorycache", "file_js_cache_large.js"), ev("evaluate:classic", "file_js_cache_large.js"), - ev("diskcache:disabled", "file_js_cache_large.js"), + ev("diskcache:noschedule"), ], }, { @@ -312,7 +319,6 @@ add_task(async function testMemoryCache() { events: [ ev("load:memorycache", "file_js_cache_large.js"), ev("evaluate:classic", "file_js_cache_large.js"), - ev("diskcache:register", "file_js_cache_large.js"), ev("diskcache:saved", "file_js_cache_large.js", false), ], }, @@ -321,7 +327,7 @@ add_task(async function testMemoryCache() { events: [ ev("load:memorycache", "file_js_cache_large.js"), ev("evaluate:classic", "file_js_cache_large.js"), - ev("diskcache:disabled", "file_js_cache_large.js"), + ev("diskcache:noschedule"), ], }, { @@ -329,7 +335,7 @@ add_task(async function testMemoryCache() { events: [ ev("load:memorycache", "file_js_cache_large.js"), ev("evaluate:classic", "file_js_cache_large.js"), - ev("diskcache:disabled", "file_js_cache_large.js"), + ev("diskcache:noschedule"), ], }, @@ -340,7 +346,7 @@ add_task(async function testMemoryCache() { ev("load:diskcache", "file_js_cache_large.js"), ev("memorycache:saved", "file_js_cache_large.js"), ev("evaluate:classic", "file_js_cache_large.js"), - ev("diskcache:disabled", "file_js_cache_large.js"), + ev("diskcache:noschedule"), ], }, { @@ -348,7 +354,7 @@ add_task(async function testMemoryCache() { events: [ ev("load:memorycache", "file_js_cache_large.js"), ev("evaluate:classic", "file_js_cache_large.js"), - ev("diskcache:disabled", "file_js_cache_large.js"), + ev("diskcache:noschedule"), ], }, ], @@ -362,28 +368,28 @@ add_task(async function testMemoryCache() { file: "file_js_cache_large_syntax_error.js", events: [ ev("load:source", "file_js_cache_large_syntax_error.js"), - ev("diskcache:disabled", "file_js_cache_large_syntax_error.js"), + ev("diskcache:noschedule"), ], }, { file: "file_js_cache_large_syntax_error.js", events: [ ev("load:source", "file_js_cache_large_syntax_error.js"), - ev("diskcache:disabled", "file_js_cache_large_syntax_error.js"), + ev("diskcache:noschedule"), ], }, { file: "file_js_cache_large_syntax_error.js", events: [ ev("load:source", "file_js_cache_large_syntax_error.js"), - ev("diskcache:disabled", "file_js_cache_large_syntax_error.js"), + ev("diskcache:noschedule"), ], }, { file: "file_js_cache_large_syntax_error.js", events: [ ev("load:source", "file_js_cache_large_syntax_error.js"), - ev("diskcache:disabled", "file_js_cache_large_syntax_error.js"), + ev("diskcache:noschedule"), ], }, ], diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp @@ -2778,10 +2778,13 @@ void ScriptLoader::CalculateCacheFlag(ScriptLoadRequest* aRequest) { LOG(("ScriptLoadRequest (%p): Bytecode-cache: Mark in-memory: Stencil", aRequest)); aRequest->MarkPassedConditionForMemoryCache(); - } else { - aRequest->MarkSkippedMemoryCaching(); + + // Disk cache is handled by SharedScriptCache. + return; } + aRequest->MarkSkippedMemoryCaching(); + // The following conditions apply only to the disk cache. if (aRequest->IsBytecode()) { @@ -3360,6 +3363,11 @@ nsCString& ScriptLoader::BytecodeMimeTypeFor( nsresult ScriptLoader::MaybePrepareForDiskCacheAfterExecute( ScriptLoadRequest* aRequest, nsresult aRv) { + if (mCache) { + // Disk cache is handled by SharedScriptCache. + return NS_OK; + } + if (!aRequest->PassedConditionForDiskCache() || !aRequest->HasStencil()) { LOG(("ScriptLoadRequest (%p): Bytecode-cache: disabled (rv = %X)", aRequest, unsigned(aRv))); @@ -3400,6 +3408,11 @@ nsresult ScriptLoader::MaybePrepareModuleForDiskCacheAfterExecute( ModuleLoadRequest* aRequest, nsresult aRv) { MOZ_ASSERT(aRequest->IsTopLevel()); + if (mCache) { + // Disk cache is handled by SharedScriptCache. + return NS_OK; + } + // NOTE: If a module is passed to this multiple times, it can be // enqueued multiple times. // This is okay because ScriptLoader::UpdateDiskCache filters out @@ -3520,6 +3533,7 @@ LoadedScript* ScriptLoader::GetActiveScript(JSContext* aCx) { } void ScriptLoader::RegisterForDiskCache(ScriptLoadRequest* aRequest) { + MOZ_ASSERT(!mCache); MOZ_ASSERT(aRequest->PassedConditionForDiskCache()); MOZ_ASSERT(aRequest->HasStencil()); MOZ_ASSERT(aRequest->getLoadedScript()->HasDiskCacheReference()); @@ -3545,14 +3559,6 @@ void ScriptLoader::Destroy() { } void ScriptLoader::MaybeUpdateDiskCache() { - // If we already gave up, ensure that we are not going to enqueue any script, - // and that we finalize them properly. - if (mGiveUpDiskCaching) { - LOG(("ScriptLoader (%p): Keep giving-up bytecode encoding.", this)); - GiveUpDiskCaching(); - return; - } - // We wait for the load event to be fired before saving the bytecode of // any script to the cache. It is quite common to have load event // listeners trigger more JavaScript execution, that we want to save as @@ -3562,13 +3568,6 @@ void ScriptLoader::MaybeUpdateDiskCache() { return; } - // No need to fire any event if there is no bytecode to be saved. - if (mDiskCacheQueue.IsEmpty()) { - LOG(("ScriptLoader (%p): No script in queue to be saved to the disk.", - this)); - return; - } - // Wait until all scripts are loaded before saving the bytecode, such that // we capture most of the intialization of the page. if (HasPendingRequests()) { @@ -3576,6 +3575,28 @@ void ScriptLoader::MaybeUpdateDiskCache() { return; } + if (mCache) { + if (!mCache->MaybeScheduleUpdateDiskCache()) { + TRACE_FOR_TEST_0("diskcache:noschedule"); + } + return; + } + + // If we already gave up, ensure that we are not going to enqueue any script, + // and that we finalize them properly. + if (mGiveUpDiskCaching) { + LOG(("ScriptLoader (%p): Keep giving-up bytecode encoding.", this)); + GiveUpDiskCaching(); + return; + } + + // No need to fire any event if there is no bytecode to be saved. + if (mDiskCacheQueue.IsEmpty()) { + LOG(("ScriptLoader (%p): No script in queue to be saved to the disk.", + this)); + return; + } + // Create a new runnable dedicated to encoding the content of the bytecode of // all enqueued scripts when the document is idle. In case of failure, we // give-up on encoding the bytecode. @@ -3717,6 +3738,13 @@ void ScriptLoader::EncodeBytecodeAndSave( } void ScriptLoader::GiveUpDiskCaching() { + if (mCache) { + // Disk cache is handled by SharedScriptCache. + MOZ_ASSERT(mDiskCacheQueue.IsEmpty()); + MOZ_ASSERT(mDiskCacheableDependencyModules.isEmpty()); + return; + } + // If the document went away prematurely, we still want to set this, in order // to avoid queuing more scripts. mGiveUpDiskCaching = true; diff --git a/dom/script/ScriptTrace.h b/dom/script/ScriptTrace.h @@ -19,6 +19,11 @@ mozilla::dom::script::TestingNotifyObserver(requestOrScript, str); \ PR_END_MACRO +#define TRACE_FOR_TEST_0(str) \ + PR_BEGIN_MACRO \ + mozilla::dom::script::TestingNotifyObserver(str); \ + PR_END_MACRO + namespace mozilla::dom::script { void TestingNotifyObserver(JS::loader::ScriptLoadRequest* aRequest, @@ -43,6 +48,14 @@ inline void TestingNotifyObserver(JS::loader::ScriptLoadRequest* aRequest, TestingNotifyObserver(aRequest, aRequest->getLoadedScript(), aEvent); } +inline void TestingNotifyObserver(const char* aEvent) { + if (!StaticPrefs::dom_expose_test_interfaces()) { + return; + } + + TestingNotifyObserver(nullptr, nullptr, aEvent); +} + } // namespace mozilla::dom::script #endif // mozilla_dom_ScriptTrace_h diff --git a/dom/script/SharedScriptCache.cpp b/dom/script/SharedScriptCache.cpp @@ -192,6 +192,35 @@ static bool ShouldSave(JS::loader::LoadedScript* aLoadedScript, return true; } +bool SharedScriptCache::MaybeScheduleUpdateDiskCache() { + auto strategy = ScriptLoader::GetDiskCacheStrategy(); + if (strategy.mIsDisabled) { + return false; + } + + bool hasSaveable = false; + for (auto iter = mComplete.Iter(); !iter.Done(); iter.Next()) { + JS::loader::LoadedScript* loadedScript = iter.Data().mResource; + if (ShouldSave(loadedScript, strategy)) { + hasSaveable = true; + break; + } + } + + if (!hasSaveable) { + return false; + } + + // TODO: Apply more flexible scheduling (bug 1902951) + + nsCOMPtr<nsIRunnable> updater = + NewRunnableMethod("SharedScriptCache::UpdateDiskCache", this, + &SharedScriptCache::UpdateDiskCache); + (void)NS_DispatchToCurrentThreadQueue(updater.forget(), + EventQueuePriority::Idle); + return true; +} + void SharedScriptCache::UpdateDiskCache() { auto strategy = ScriptLoader::GetDiskCacheStrategy(); if (strategy.mIsDisabled) { diff --git a/dom/script/SharedScriptCache.h b/dom/script/SharedScriptCache.h @@ -193,6 +193,7 @@ class SharedScriptCache final SharedScriptCache(); void Init(); + bool MaybeScheduleUpdateDiskCache(); void UpdateDiskCache(); // This has to be static because it's also called for loaders that don't have