tor-browser

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

commit 9d38131e7dde41cd6d4d432ed45a2bd763485e70
parent 122bc2e9ef7375f608e003ad841578f7dfe30654
Author: Tooru Fujisawa <arai_a@mac.com>
Date:   Tue, 11 Nov 2025 08:26:19 +0000

Bug 1997870 - Part 3: Split EncodeBytecodeAndSave into two steps. r=bthrall

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

Diffstat:
Mdom/script/ScriptLoader.cpp | 79++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mdom/script/ScriptLoader.h | 17++++++++++++++---
Mdom/script/SharedScriptCache.cpp | 19++++++++++++++++++-
3 files changed, 80 insertions(+), 35 deletions(-)

diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp @@ -3641,10 +3641,27 @@ void ScriptLoader::UpdateDiskCache() { continue; } - EncodeBytecodeAndSave(fc, loadedScript); + MOZ_ASSERT(loadedScript->HasStencil()); + + Vector<uint8_t> compressed; + if (!EncodeAndCompress(fc, loadedScript, loadedScript->GetStencil(), + loadedScript->SRIAndBytecode(), compressed)) { + loadedScript->DropDiskCacheReference(); + loadedScript->DropBytecode(); + TRACE_FOR_TEST(loadedScript, "diskcache:failed"); + continue; + } + + if (!SaveToDiskCache(loadedScript, compressed)) { + loadedScript->DropDiskCacheReference(); + loadedScript->DropBytecode(); + TRACE_FOR_TEST(loadedScript, "diskcache:failed"); + continue; + } loadedScript->DropDiskCacheReference(); loadedScript->DropBytecode(); + TRACE_FOR_TEST(loadedScript, "diskcache:saved"); } mDiskCacheQueue.Clear(); @@ -3652,25 +3669,20 @@ void ScriptLoader::UpdateDiskCache() { } /* static */ -void ScriptLoader::EncodeBytecodeAndSave( - JS::FrontendContext* aFc, JS::loader::LoadedScript* aLoadedScript) { - MOZ_ASSERT(aLoadedScript->HasDiskCacheReference()); - MOZ_ASSERT(aLoadedScript->HasStencil()); - - auto bytecodeFailed = mozilla::MakeScopeExit( - [&]() { TRACE_FOR_TEST(aLoadedScript, "diskcache:failed"); }); - - size_t SRILength = aLoadedScript->SRIAndBytecode().length(); +bool ScriptLoader::EncodeAndCompress( + JS::FrontendContext* aFc, const JS::loader::LoadedScript* aLoadedScript, + JS::Stencil* aStencil, const JS::TranscodeBuffer& aSRI, + Vector<uint8_t>& aCompressed) { + size_t SRILength = aSRI.length(); MOZ_ASSERT(JS::IsTranscodingBytecodeOffsetAligned(SRILength)); JS::TranscodeBuffer SRIAndBytecode; - if (!SRIAndBytecode.appendAll(aLoadedScript->SRIAndBytecode())) { + if (!SRIAndBytecode.appendAll(aSRI)) { LOG(("LoadedScript (%p): Cannot allocate buffer", aLoadedScript)); - return; + return false; } - JS::TranscodeResult result = - JS::EncodeStencil(aFc, aLoadedScript->GetStencil(), SRIAndBytecode); + JS::TranscodeResult result = JS::EncodeStencil(aFc, aStencil, SRIAndBytecode); if (result != JS::TranscodeResult::Ok) { // Encoding can be aborted for non-supported syntax (e.g. asm.js), or @@ -3679,37 +3691,44 @@ void ScriptLoader::EncodeBytecodeAndSave( JS::ClearFrontendErrors(aFc); LOG(("LoadedScript (%p): Cannot serialize bytecode", aLoadedScript)); - return; + return false; } - Vector<uint8_t> compressedBytecode; // TODO probably need to move this to a helper thread - if (!ScriptBytecodeCompress(SRIAndBytecode, SRILength, compressedBytecode)) { - return; + if (!ScriptBytecodeCompress(SRIAndBytecode, SRILength, aCompressed)) { + return false; } - if (compressedBytecode.length() >= UINT32_MAX) { + if (aCompressed.length() >= UINT32_MAX) { LOG( ("LoadedScript (%p): Bytecode cache is too large to be decoded " "correctly.", aLoadedScript)); - return; + return false; } + return true; +} + +/* static */ +bool ScriptLoader::SaveToDiskCache( + const JS::loader::LoadedScript* aLoadedScript, + const Vector<uint8_t>& aCompressed) { + MOZ_ASSERT(NS_IsMainThread()); + // Open the output stream to the cache entry alternate data storage. This // might fail if the stream is already open by another request, in which // case, we just ignore the current one. nsCOMPtr<nsIAsyncOutputStream> output; nsresult rv = aLoadedScript->mCacheInfo->OpenAlternativeOutputStream( BytecodeMimeTypeFor(aLoadedScript), - static_cast<int64_t>(compressedBytecode.length()), - getter_AddRefs(output)); + static_cast<int64_t>(aCompressed.length()), getter_AddRefs(output)); if (NS_FAILED(rv)) { LOG( ("LoadedScript (%p): Cannot open bytecode cache (rv = %X, output " "= %p)", aLoadedScript, unsigned(rv), output.get())); - return; + return false; } MOZ_ASSERT(output); @@ -3719,20 +3738,18 @@ void ScriptLoader::EncodeBytecodeAndSave( }); uint32_t n; - rv = output->Write(reinterpret_cast<char*>(compressedBytecode.begin()), - compressedBytecode.length(), &n); + rv = output->Write(reinterpret_cast<const char*>(aCompressed.begin()), + aCompressed.length(), &n); LOG( ("LoadedScript (%p): Write bytecode cache (rv = %X, length = %u, " "written = %u)", - aLoadedScript, unsigned(rv), unsigned(compressedBytecode.length()), n)); + aLoadedScript, unsigned(rv), unsigned(aCompressed.length()), n)); if (NS_FAILED(rv)) { - return; + return false; } - MOZ_RELEASE_ASSERT(compressedBytecode.length() == n); - - bytecodeFailed.release(); - TRACE_FOR_TEST(aLoadedScript, "diskcache:saved"); + MOZ_RELEASE_ASSERT(aCompressed.length() == n); + return true; } void ScriptLoader::GiveUpDiskCaching() { diff --git a/dom/script/ScriptLoader.h b/dom/script/ScriptLoader.h @@ -757,10 +757,21 @@ class ScriptLoader final : public JS::loader::ScriptLoaderInterface { public: /** - * Encode the stencils and save the bytecode to the necko cache. + * Encode the stencils and compress it. + * aLoadedScript is used only for logging purpose, in order to allow + * performing this off main thread. */ - static void EncodeBytecodeAndSave(JS::FrontendContext* aFc, - JS::loader::LoadedScript* aLoadedScript); + static bool EncodeAndCompress(JS::FrontendContext* aFc, + const JS::loader::LoadedScript* aLoadedScript, + JS::Stencil* aStencil, + const JS::TranscodeBuffer& aSRI, + Vector<uint8_t>& aCompressed); + + /** + * Save the bytecode to the necko cache. + */ + static bool SaveToDiskCache(const JS::loader::LoadedScript* aLoadedScript, + const Vector<uint8_t>& aCompressed); private: /** diff --git a/dom/script/SharedScriptCache.cpp b/dom/script/SharedScriptCache.cpp @@ -8,6 +8,7 @@ #include "ScriptLoadHandler.h" // ScriptLoadHandler #include "ScriptLoader.h" // ScriptLoader +#include "ScriptTrace.h" // TRACE_FOR_TEST #include "js/experimental/CompileScript.h" // JS::FrontendContext, JS::NewFrontendContext, JS::DestroyFrontendContext #include "mozilla/Maybe.h" // Maybe, Some, Nothing #include "mozilla/dom/ContentParent.h" // dom::ContentParent @@ -244,10 +245,26 @@ void SharedScriptCache::UpdateDiskCache() { } } - ScriptLoader::EncodeBytecodeAndSave(fc, loadedScript); + Vector<uint8_t> compressed; + if (!ScriptLoader::EncodeAndCompress( + fc, loadedScript, loadedScript->GetStencil(), + loadedScript->SRIAndBytecode(), compressed)) { + loadedScript->DropDiskCacheReference(); + loadedScript->DropBytecode(); + TRACE_FOR_TEST(loadedScript, "diskcache:failed"); + continue; + } + + if (!ScriptLoader::SaveToDiskCache(loadedScript, compressed)) { + loadedScript->DropDiskCacheReference(); + loadedScript->DropBytecode(); + TRACE_FOR_TEST(loadedScript, "diskcache:failed"); + continue; + } loadedScript->DropDiskCacheReference(); loadedScript->DropBytecode(); + TRACE_FOR_TEST(loadedScript, "diskcache:saved"); } if (fc) {