diff --git a/dom/canvas/WebGLChild.h b/dom/canvas/WebGLChild.h index 2cff42045bac..330ed441a0a0 100644 --- a/dom/canvas/WebGLChild.h +++ b/dom/canvas/WebGLChild.h @@ -11,16 +11,6 @@ #include "mozilla/dom/PWebGLChild.h" #include "mozilla/dom/IpdlQueue.h" -// This is a bit weird. Nothing directly in WebGLChild.h necessitates including -// WebGLParent.h, but if we don't do this, we get compiler errors in the -// generated code inside PWebGLChild.cpp. The error is due to a complex -// dependency chain involving IpdlQueue, which I won't go into here. Including -// WebGLParent.h inside WebGLChild.h is the simplest way we could think of to -// avoid this issue. Including it in any of the code more directly involved in -// the breaking dependency chain unfortunately introduces a cyclical dependency -// between WebGLParent.h and PWebGLParent.h. -#include "mozilla/dom/WebGLParent.h" - namespace mozilla { class ClientWebGLContext; diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 7397bd7b2914..510aab718c57 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -98,7 +98,6 @@ #include "mozilla/plugins/PluginInstanceParent.h" #include "mozilla/plugins/PluginModuleParent.h" #include "mozilla/RemoteLazyInputStreamChild.h" -#include "mozilla/scache/StartupCacheChild.h" #include "mozilla/widget/ScreenManager.h" #include "mozilla/widget/WidgetMessageUtils.h" #include "nsBaseDragService.h" @@ -1921,23 +1920,6 @@ mozilla::ipc::IPCResult ContentChild::RecvPScriptCacheConstructor( return IPC_OK(); } -scache::PStartupCacheChild* ContentChild::AllocPStartupCacheChild( - const bool& wantCacheData) { - return new scache::StartupCacheChild(); -} - -bool ContentChild::DeallocPStartupCacheChild( - scache::PStartupCacheChild* cache) { - delete static_cast(cache); - return true; -} - -mozilla::ipc::IPCResult ContentChild::RecvPStartupCacheConstructor( - scache::PStartupCacheChild* actor, const bool& wantCacheData) { - static_cast(actor)->Init(wantCacheData); - return IPC_OK(); -} - PNeckoChild* ContentChild::AllocPNeckoChild() { return new NeckoChild(); } mozilla::ipc::IPCResult ContentChild::RecvNetworkLinkTypeChange( diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index f3b261aa85eb..d4aa51618b25 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -238,13 +238,6 @@ class ContentChild final : public PContentChild, PScriptCacheChild*, const FileDescOrError& cacheFile, const bool& wantCacheData) override; - PStartupCacheChild* AllocPStartupCacheChild(const bool& wantCacheData); - - bool DeallocPStartupCacheChild(PStartupCacheChild*); - - virtual mozilla::ipc::IPCResult RecvPStartupCacheConstructor( - PStartupCacheChild*, const bool& wantCacheData) override; - PNeckoChild* AllocPNeckoChild(); bool DeallocPNeckoChild(PNeckoChild*); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 5ae6149833b3..12c1805cb472 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -66,7 +66,6 @@ #include "mozilla/ProcessHangMonitorIPC.h" #include "mozilla/RDDProcessManager.h" #include "mozilla/ScopeExit.h" -#include "mozilla/scache/StartupCache.h" #include "mozilla/ScriptPreloader.h" #include "mozilla/Services.h" #include "mozilla/Sprintf.h" @@ -156,7 +155,6 @@ #include "mozilla/plugins/PluginBridge.h" #include "mozilla/RemoteLazyInputStreamParent.h" #include "mozilla/widget/ScreenManager.h" -#include "mozilla/scache/StartupCacheParent.h" #include "nsAnonymousTemporaryFile.h" #include "nsAppRunner.h" #include "nsCExternalHandlerService.h" @@ -2302,11 +2300,6 @@ bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority) { } mPrefSerializer->AddSharedPrefCmdLineArgs(*mSubprocess, extraArgs); - auto startupCache = mozilla::scache::StartupCache::GetSingleton(); - if (startupCache) { - startupCache->AddStartupCacheCmdLineArgs(*mSubprocess, extraArgs); - } - // Register ContentParent as an observer for changes to any pref // whose prefix matches the empty string, i.e. all of them. The // observation starts here in order to capture pref updates that @@ -2740,7 +2733,6 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) { Unused << SendRemoteType(mRemoteType); ScriptPreloader::InitContentChild(*this); - scache::StartupCache::InitContentChild(*this); // Initialize the message manager (and load delayed scripts) now that we // have established communications with the child. @@ -3837,16 +3829,6 @@ bool ContentParent::DeallocPScriptCacheParent(PScriptCacheParent* cache) { return true; } -PStartupCacheParent* ContentParent::AllocPStartupCacheParent( - const bool& wantCacheData) { - return new scache::StartupCacheParent(wantCacheData); -} - -bool ContentParent::DeallocPStartupCacheParent(PStartupCacheParent* cache) { - delete static_cast(cache); - return true; -} - PNeckoParent* ContentParent::AllocPNeckoParent() { return new NeckoParent(); } bool ContentParent::DeallocPNeckoParent(PNeckoParent* necko) { diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 963d74945129..c3dbe37a06fb 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -86,7 +86,6 @@ class PreallocatedProcessManagerImpl; class BenchmarkStorageParent; using mozilla::loader::PScriptCacheParent; -using mozilla::scache::PStartupCacheParent; namespace embedding { class PrintingParent; @@ -927,10 +926,6 @@ class ContentParent final bool DeallocPScriptCacheParent(PScriptCacheParent* shell); - PStartupCacheParent* AllocPStartupCacheParent(const bool& wantCacheData); - - bool DeallocPStartupCacheParent(PStartupCacheParent* shell); - bool DeallocPNeckoParent(PNeckoParent* necko); already_AddRefed AllocPExternalHelperAppParent( diff --git a/dom/ipc/ContentProcess.cpp b/dom/ipc/ContentProcess.cpp index 9191e001a3d6..c3404a0c860c 100644 --- a/dom/ipc/ContentProcess.cpp +++ b/dom/ipc/ContentProcess.cpp @@ -84,8 +84,6 @@ bool ContentProcess::Init(int aArgc, char* aArgv[]) { char* prefMapHandle = nullptr; char* prefsLen = nullptr; char* prefMapSize = nullptr; - char* scacheHandle = nullptr; - char* scacheSize = nullptr; #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) nsCOMPtr profileDir; #endif @@ -129,11 +127,6 @@ bool ContentProcess::Init(int aArgc, char* aArgv[]) { return false; } prefMapHandle = aArgv[i]; - } else if (strcmp(aArgv[i], "-scacheHandle") == 0) { - if (++i == aArgc) { - return false; - } - scacheHandle = aArgv[i]; #endif } else if (strcmp(aArgv[i], "-prefsLen") == 0) { @@ -146,11 +139,6 @@ bool ContentProcess::Init(int aArgc, char* aArgv[]) { return false; } prefMapSize = aArgv[i]; - } else if (strcmp(aArgv[i], "-scacheSize") == 0) { - if (++i == aArgc) { - return false; - } - scacheSize = aArgv[i]; } else if (strcmp(aArgv[i], "-safeMode") == 0) { gSafeMode = true; @@ -187,9 +175,6 @@ bool ContentProcess::Init(int aArgc, char* aArgv[]) { return false; } - Unused << mozilla::scache::StartupCache::InitChildSingleton(scacheHandle, - scacheSize); - mContent.Init(IOThreadChild::message_loop(), ParentPid(), *parentBuildID, IOThreadChild::TakeChannel(), *childID, *isForBrowser); diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index a272b8275a48..f1cf8c8970f1 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -44,7 +44,6 @@ include protocol PVRManager; include protocol PRemoteDecoderManager; include protocol PProfiler; include protocol PScriptCache; -include protocol PStartupCache; include protocol PSessionStorageObserver; include protocol PBenchmarkStorage; include DOMTypes; @@ -413,7 +412,6 @@ nested(upto inside_cpow) sync protocol PContent manages PURLClassifier; manages PURLClassifierLocal; manages PScriptCache; - manages PStartupCache; manages PLoginReputation; manages PSessionStorageObserver; manages PBenchmarkStorage; @@ -541,8 +539,6 @@ child: async PScriptCache(FileDescOrError cacheFile, bool wantCacheData); - async PStartupCache(bool wantCacheData); - async RegisterChrome(ChromePackage[] packages, SubstitutionMapping[] substitutions, OverrideMapping[] overrides, nsCString locale, bool reset); async RegisterChromeItem(ChromeRegistryItem item); diff --git a/gfx/thebes/gfxFT2FontList.cpp b/gfx/thebes/gfxFT2FontList.cpp index 14ac23aad3b8..06c19a889784 100644 --- a/gfx/thebes/gfxFT2FontList.cpp +++ b/gfx/thebes/gfxFT2FontList.cpp @@ -95,14 +95,14 @@ already_AddRefed FT2FontEntry::GetFTFace(bool aCommit) { // here would be memory allocation, in which case mFace remains null. RefPtr face; if (mFilename[0] != '/') { - RefPtr reader = Omnijar::GetReader(Omnijar::Type::GRE); + RefPtr reader = Omnijar::GetReader(Omnijar::Type::GRE); nsZipItem* item = reader->GetItem(mFilename.get()); NS_ASSERTION(item, "failed to find zip entry"); uint32_t bufSize = item->RealSize(); uint8_t* fontDataBuf = static_cast(malloc(bufSize)); if (fontDataBuf) { - CacheAwareZipCursor cursor(item, reader, fontDataBuf, bufSize); + nsZipCursor cursor(item, reader, fontDataBuf, bufSize); cursor.Copy(&bufSize); NS_ASSERTION(bufSize == item->RealSize(), "error reading bundled font"); RefPtr ufd = new FTUserFontData(fontDataBuf, bufSize); @@ -458,8 +458,7 @@ hb_blob_t* FT2FontEntry::GetFontTable(uint32_t aTableTag) { } else { // A relative path means an omnijar resource, which we may need to // decompress to a temporary buffer. - RefPtr reader = - Omnijar::GetReader(Omnijar::Type::GRE); + RefPtr reader = Omnijar::GetReader(Omnijar::Type::GRE); nsZipItem* item = reader->GetItem(mFilename.get()); MOZ_ASSERT(item, "failed to find zip entry"); if (item) { @@ -470,7 +469,7 @@ hb_blob_t* FT2FontEntry::GetFontTable(uint32_t aTableTag) { uint32_t length = item->RealSize(); uint8_t* buffer = static_cast(malloc(length)); if (buffer) { - CacheAwareZipCursor cursor(item, reader, buffer, length); + nsZipCursor cursor(item, reader, buffer, length); cursor.Copy(&length); MOZ_ASSERT(length == item->RealSize(), "error reading font"); if (length == item->RealSize()) { @@ -1160,7 +1159,7 @@ void gfxFT2FontList::FindFontsInOmnijar(FontNameCache* aCache) { static const char* sJarSearchPaths[] = { "res/fonts/*.ttf$", }; - RefPtr reader = Omnijar::GetReader(Omnijar::Type::GRE); + RefPtr reader = Omnijar::GetReader(Omnijar::Type::GRE); for (unsigned i = 0; i < ArrayLength(sJarSearchPaths); i++) { nsZipFind* find; if (NS_SUCCEEDED(reader->FindInit(sJarSearchPaths[i], &find))) { @@ -1275,7 +1274,7 @@ void gfxFT2FontList::AddFaceToList(const nsCString& aEntryName, uint32_t aIndex, } } -void gfxFT2FontList::AppendFacesFromOmnijarEntry(CacheAwareZipReader* aArchive, +void gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive, const nsCString& aEntryName, FontNameCache* aCache, bool aJarChanged) { @@ -1314,7 +1313,7 @@ void gfxFT2FontList::AppendFacesFromOmnijarEntry(CacheAwareZipReader* aArchive, return; } - CacheAwareZipCursor cursor(item, aArchive, (uint8_t*)buffer, bufSize); + nsZipCursor cursor(item, aArchive, (uint8_t*)buffer, bufSize); uint8_t* data = cursor.Copy(&bufSize); MOZ_ASSERT(data && bufSize == item->RealSize(), "error reading bundled font"); if (!data) { diff --git a/gfx/thebes/gfxFT2FontList.h b/gfx/thebes/gfxFT2FontList.h index 59aacbc51864..79adff003346 100644 --- a/gfx/thebes/gfxFT2FontList.h +++ b/gfx/thebes/gfxFT2FontList.h @@ -11,9 +11,6 @@ #include "gfxPlatformFontList.h" namespace mozilla { - -class CacheAwareZipReader; - namespace dom { class SystemFontListEntry; }; @@ -177,7 +174,7 @@ class gfxFT2FontList final : public gfxPlatformFontList { void AppendFacesFromFontFile(const nsCString& aFileName, FontNameCache* aCache, StandardFile aStdFile); - void AppendFacesFromOmnijarEntry(mozilla::CacheAwareZipReader* aArchive, + void AppendFacesFromOmnijarEntry(nsZipArchive* aReader, const nsCString& aEntryName, FontNameCache* aCache, bool aJarChanged); diff --git a/intl/hyphenation/glue/nsHyphenationManager.cpp b/intl/hyphenation/glue/nsHyphenationManager.cpp index 53ebfef994cb..b2058ac6eadc 100644 --- a/intl/hyphenation/glue/nsHyphenationManager.cpp +++ b/intl/hyphenation/glue/nsHyphenationManager.cpp @@ -228,7 +228,7 @@ void nsHyphenationManager::LoadPatternListFromOmnijar(Omnijar::Type aType) { return; } - RefPtr zip = Omnijar::GetReader(aType); + RefPtr zip = Omnijar::GetReader(aType); if (!zip) { return; } diff --git a/intl/hyphenation/glue/nsHyphenator.cpp b/intl/hyphenation/glue/nsHyphenator.cpp index 93ed5e32d62c..a92b747a9cfa 100644 --- a/intl/hyphenation/glue/nsHyphenator.cpp +++ b/intl/hyphenation/glue/nsHyphenator.cpp @@ -41,11 +41,20 @@ static const void* GetItemPtrFromJarURI(nsIJARURI* aJAR, uint32_t* aLength) { if (!file) { return nullptr; } - RefPtr archive = Omnijar::GetReader(file); + RefPtr archive = Omnijar::GetReader(file); if (archive) { nsCString path; aJAR->GetJAREntry(path); - return archive->GetData(path.get(), aLength); + nsZipItem* item = archive->GetItem(path.get()); + if (item && item->Compression() == 0 && item->Size() > 0) { + // We do NOT own this data, but it won't go away until the omnijar + // file is closed during shutdown. + const uint8_t* data = archive->GetData(item); + if (data) { + *aLength = item->Size(); + return data; + } + } } return nullptr; } diff --git a/intl/locale/LocaleService.cpp b/intl/locale/LocaleService.cpp index 204f551ebc4c..59a5fc64f4f3 100644 --- a/intl/locale/LocaleService.cpp +++ b/intl/locale/LocaleService.cpp @@ -295,14 +295,13 @@ bool LocaleService::IsServer() { return mIsServer; } static bool GetGREFileContents(const char* aFilePath, nsCString* aOutString) { // Look for the requested file in omnijar. - RefPtr zip = Omnijar::GetReader(Omnijar::GRE); + RefPtr zip = Omnijar::GetReader(Omnijar::GRE); if (zip) { - uint32_t length; - const uint8_t* data = zip->GetData(aFilePath, &length); - if (!data) { + nsZipItemPtr item(zip, aFilePath); + if (!item) { return false; } - aOutString->Assign(reinterpret_cast(data), length); + aOutString->Assign(item.Buffer(), item.Length()); return true; } diff --git a/js/xpconnect/loader/IOBuffers.h b/js/xpconnect/loader/IOBuffers.h index eb8073fd164c..e26b0c3bca82 100644 --- a/js/xpconnect/loader/IOBuffers.h +++ b/js/xpconnect/loader/IOBuffers.h @@ -64,82 +64,6 @@ class OutputBuffer { size_t cursor_ = 0; }; -// This is similar to OutputBuffer, but with a fixed-size buffer, rather than -// a dynamically growing one. This is currently used in order to share -// StartupCache data across processes. -class PreallocatedOutputBuffer { - public: - explicit PreallocatedOutputBuffer(Range& buffer) : data(buffer) {} - - uint8_t* write(size_t size) { - MOZ_ASSERT(checkCapacity(size)); - - auto buf = &data[cursor_]; - cursor_ += size; - return buf; - } - - bool codeUint8(const uint8_t& val) { - if (checkCapacity(sizeof val)) { - *write(sizeof val) = val; - } - return !error_; - } - - template - bool codeUint8(const EnumSet& val) { - return codeUint8(val.serialize()); - } - - bool codeUint16(const uint16_t& val) { - if (checkCapacity(sizeof val)) { - LittleEndian::writeUint16(write(sizeof val), val); - } - return !error_; - } - - bool codeUint32(const uint32_t& val) { - if (checkCapacity(sizeof val)) { - LittleEndian::writeUint32(write(sizeof val), val); - } - return !error_; - } - - bool codeString(const nsCString& str) { - uint16_t len = CheckedUint16(str.Length()).value(); - if (codeUint16(len)) { - if (checkCapacity(len)) { - memcpy(write(len), str.get(), len); - } - } - return !error_; - } - - bool error() { return error_; } - - bool finished() { return error_ || !remainingCapacity(); } - - size_t remainingCapacity() { return data.length() - cursor_; } - - size_t cursor() const { return cursor_; } - - const uint8_t* Get() const { return data.begin().get(); } - - private: - bool checkCapacity(size_t size) { - if (size > remainingCapacity()) { - error_ = true; - } - return !error_; - } - - bool error_ = false; - - public: - Range& data; - size_t cursor_ = 0; -}; - class InputBuffer { public: explicit InputBuffer(const Range& buffer) : data(buffer) {} diff --git a/js/xpconnect/loader/URLPreloader.cpp b/js/xpconnect/loader/URLPreloader.cpp index a683558823be..aa79ccd5eddd 100644 --- a/js/xpconnect/loader/URLPreloader.cpp +++ b/js/xpconnect/loader/URLPreloader.cpp @@ -322,7 +322,7 @@ void URLPreloader::BackgroundReadFiles() { mReaderThread = nullptr; }); - Vector cursors; + Vector cursors; LinkedList pendingURLs; { MonitorAutoLock mal(mMonitor); @@ -352,14 +352,14 @@ void URLPreloader::BackgroundReadFiles() { continue; } - RefPtr zip = entry->Archive(); + RefPtr zip = entry->Archive(); if (!zip) { MOZ_CRASH_UNSAFE_PRINTF( "Failed to get Omnijar %s archive for entry (path: \"%s\")", entry->TypeString(), entry->mPath.get()); } - auto* item = zip->GetItem(entry->mPath.get()); + auto item = zip->GetItem(entry->mPath.get()); if (!item) { entry->mResultCode = NS_ERROR_FILE_NOT_FOUND; continue; @@ -495,25 +495,25 @@ Result URLPreloader::ReadURIInternal( } /* static */ Result URLPreloader::ReadZip( - CacheAwareZipReader* archive, const nsACString& path, ReadType readType) { + nsZipArchive* zip, const nsACString& path, ReadType readType) { // If the zip archive belongs to an Omnijar location, map it to a cache // entry, and cache it as normal. Otherwise, simply read the entry // synchronously, since other JAR archives are currently unsupported by the // cache. - RefPtr reader = Omnijar::GetReader(Omnijar::GRE); - if (reader == archive) { + RefPtr reader = Omnijar::GetReader(Omnijar::GRE); + if (zip == reader) { CacheKey key(CacheKey::TypeGREJar, path); return Read(key, readType); } reader = Omnijar::GetReader(Omnijar::APP); - if (reader == archive) { + if (zip == reader) { CacheKey key(CacheKey::TypeAppJar, path); return Read(key, readType); } // Not an Omnijar archive, so just read it directly. - FileLocation location(archive, PromiseFlatCString(path).BeginReading()); + FileLocation location(zip, PromiseFlatCString(path).BeginReading()); return URLEntry::ReadLocation(location); } @@ -581,7 +581,7 @@ Result URLPreloader::CacheKey::ToFileLocation() { return FileLocation(file); } - RefPtr zip = Archive(); + RefPtr zip = Archive(); return FileLocation(zip, mPath.get()); } diff --git a/js/xpconnect/loader/URLPreloader.h b/js/xpconnect/loader/URLPreloader.h index 7a13b6dbe059..a3fa931a4a40 100644 --- a/js/xpconnect/loader/URLPreloader.h +++ b/js/xpconnect/loader/URLPreloader.h @@ -26,6 +26,8 @@ #include "nsIThread.h" #include "nsReadableUtils.h" +class nsZipArchive; + namespace mozilla { namespace loader { class InputBuffer; @@ -75,7 +77,7 @@ class URLPreloader final : public nsIObserver, public nsIMemoryReporter { static Result ReadFile(nsIFile* file, ReadType readType = Forget); - static Result ReadZip(CacheAwareZipReader* archive, + static Result ReadZip(nsZipArchive* archive, const nsACString& path, ReadType readType = Forget); @@ -196,7 +198,7 @@ class URLPreloader final : public nsIObserver, public nsIMemoryReporter { return ""; } - already_AddRefed Archive() { + already_AddRefed Archive() { return Omnijar::GetReader(OmnijarType()); } diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp index f7217820e7c3..4a27ea405961 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -51,7 +51,6 @@ #include "mozilla/scache/StartupCacheUtils.h" #include "mozilla/MacroForEach.h" #include "mozilla/Preferences.h" -#include "mozilla/Omnijar.h" #include "mozilla/ResultExtensions.h" #include "mozilla/ScriptPreloader.h" #include "mozilla/ScopeExit.h" @@ -671,10 +670,6 @@ JSObject* mozJSComponentLoader::PrepareObjectForLocation( static mozilla::Result ReadScript( ComponentLoaderInfo& aInfo) { - // We're going to cache the XDR encoded script data - suspend writes via the - // CacheAwareZipReader, otherwise we'll end up redundantly caching scripts. - AutoSuspendStartupCacheWrites suspendScache; - MOZ_TRY(aInfo.EnsureScriptChannel()); nsCOMPtr scriptStream; @@ -736,15 +731,7 @@ nsresult mozJSComponentLoader::ObjectForLocation( // to loading the script, since we can always slow-load. bool writeToCache = false; - - // Since we are intending to cache these buffers in the script preloader - // already, caching them in the StartupCache tends to be redundant. This - // ought to be addressed, but as in bug 1627075 we extended the - // StartupCache to be multi-process, we just didn't want to propagate - // this problem into yet more processes, so we pretend the StartupCache - // doesn't exist if we're not the parent process. - StartupCache* cache = - XRE_IsParentProcess() ? StartupCache::GetSingleton() : nullptr; + StartupCache* cache = StartupCache::GetSingleton(); aInfo.EnsureResolvedURI(); diff --git a/js/xpconnect/loader/mozJSSubScriptLoader.cpp b/js/xpconnect/loader/mozJSSubScriptLoader.cpp index 3b022b0dcd9b..853e30bc2f39 100644 --- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp +++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp @@ -24,7 +24,6 @@ #include "mozilla/ContentPrincipal.h" #include "mozilla/dom/ScriptLoader.h" -#include "mozilla/Omnijar.h" #include "mozilla/ScriptPreloader.h" #include "mozilla/SystemPrincipal.h" #include "mozilla/scache/StartupCache.h" @@ -249,10 +248,6 @@ bool mozJSSubScriptLoader::ReadScript(JS::MutableHandle script, const char* uriStr, nsIIOService* serv, bool wantReturnValue, bool useCompilationScope) { - // We're going to cache the XDR encoded script data - suspend writes via the - // CacheAwareZipReader, otherwise we'll end up redundantly caching scripts. - AutoSuspendStartupCacheWrites suspendScache; - // We create a channel and call SetContentType, to avoid expensive MIME type // lookups (bug 632490). nsCOMPtr chan; @@ -455,15 +450,7 @@ nsresult mozJSSubScriptLoader::DoLoadSubScriptWithOptions( bool ignoreCache = options.ignoreCache || !isSystem || scheme.EqualsLiteral("blob"); - // Since we are intending to cache these buffers in the script preloader - // already, caching them in the StartupCache tends to be redundant. This - // ought to be addressed, but as in bug 1627075 we extended the - // StartupCache to be multi-process, we just didn't want to propagate - // this problem into yet more processes, so we pretend the StartupCache - // doesn't exist if we're not the parent process. - StartupCache* cache = (ignoreCache || !XRE_IsParentProcess()) - ? nullptr - : StartupCache::GetSingleton(); + StartupCache* cache = ignoreCache ? nullptr : StartupCache::GetSingleton(); nsAutoCString cachePath; SubscriptCachePath(cx, uri, targetObj, cachePath); diff --git a/modules/libjar/nsJAR.cpp b/modules/libjar/nsJAR.cpp index ddc039a86c5a..4b7178de6d23 100644 --- a/modules/libjar/nsJAR.cpp +++ b/modules/libjar/nsJAR.cpp @@ -26,7 +26,7 @@ using namespace mozilla; // The following initialization makes a guess of 10 entries per jarfile. nsJAR::nsJAR() - : mZip(nullptr), + : mZip(new nsZipArchive()), mReleaseTime(PR_INTERVAL_NO_TIMEOUT), mCache(nullptr), mLock("nsJAR::mLock"), @@ -87,13 +87,12 @@ nsJAR::Open(nsIFile* zipFile) { // The omnijar is special, it is opened early on and closed late // this avoids reopening it - RefPtr zip = mozilla::Omnijar::GetReader(zipFile); + RefPtr zip = mozilla::Omnijar::GetReader(zipFile); if (zip) { mZip = zip; mSkipArchiveClosing = true; return NS_OK; } - mZip = new CacheAwareZipReader(); return mZip->OpenArchive(zipFile); } @@ -103,7 +102,7 @@ nsJAR::OpenInner(nsIZipReader* aZipReader, const nsACString& aZipEntry) { if (mOpened) return NS_ERROR_FAILURE; // Already open! nsJAR* outerJAR = static_cast(aZipReader); - RefPtr innerZip = + RefPtr innerZip = mozilla::Omnijar::GetInnerReader(outerJAR->mZipFile, aZipEntry); if (innerZip) { mOpened = true; @@ -125,12 +124,11 @@ nsJAR::OpenInner(nsIZipReader* aZipReader, const nsACString& aZipEntry) { mOuterZipEntry.Assign(aZipEntry); RefPtr handle; - rv = nsZipHandle::Init(static_cast(aZipReader)->mZip->GetZipArchive(), + rv = nsZipHandle::Init(static_cast(aZipReader)->mZip.get(), PromiseFlatCString(aZipEntry).get(), getter_AddRefs(handle)); if (NS_FAILED(rv)) return rv; - mZip = new CacheAwareZipReader(); return mZip->OpenArchive(handle); } @@ -146,7 +144,6 @@ nsJAR::OpenMemory(void* aData, uint32_t aLength) { getter_AddRefs(handle)); if (NS_FAILED(rv)) return rv; - mZip = new CacheAwareZipReader(); return mZip->OpenArchive(handle); } @@ -168,7 +165,7 @@ nsJAR::Close() { if (mSkipArchiveClosing) { // Reset state, but don't close the omnijar because we did not open it. mSkipArchiveClosing = false; - mZip = nullptr; + mZip = new nsZipArchive(); return NS_OK; } @@ -304,7 +301,7 @@ nsresult nsJAR::GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc) { return NS_ERROR_FAILURE; } - RefPtr handle = mZip->GetZipArchive()->GetFD(); + RefPtr handle = mZip->GetFD(); if (!handle) { return NS_ERROR_FAILURE; } diff --git a/modules/libjar/nsJAR.h b/modules/libjar/nsJAR.h index 58ef9e6834e7..88abf6119ac4 100644 --- a/modules/libjar/nsJAR.h +++ b/modules/libjar/nsJAR.h @@ -23,17 +23,13 @@ #include "nsRefPtrHashtable.h" #include "nsTHashtable.h" #include "nsIZipReader.h" +#include "nsZipArchive.h" #include "nsWeakReference.h" #include "nsIObserver.h" #include "mozilla/Attributes.h" -#include "nsZipArchive.h" class nsZipReaderCache; -namespace mozilla { -class CacheAwareZipReader; -} // namespace mozilla - /*------------------------------------------------------------------------- * Class nsJAR declaration. * nsJAR serves as an XPCOM wrapper for nsZipArchive with the addition of @@ -76,9 +72,9 @@ class nsJAR final : public nsIZipReader { protected: //-- Private data members - nsCOMPtr mZipFile; // The zip/jar file on disk - nsCString mOuterZipEntry; // The entry in the zip this zip is reading from - RefPtr mZip; // The underlying zip archive + nsCOMPtr mZipFile; // The zip/jar file on disk + nsCString mOuterZipEntry; // The entry in the zip this zip is reading from + RefPtr mZip; // The underlying zip archive PRIntervalTime mReleaseTime; // used by nsZipReaderCache for flushing entries nsZipReaderCache* mCache; // if cached, this points to the cache it's contained in diff --git a/modules/libjar/nsJARInputStream.cpp b/modules/libjar/nsJARInputStream.cpp index 923d9432935a..7dd4b28720f1 100644 --- a/modules/libjar/nsJARInputStream.cpp +++ b/modules/libjar/nsJARInputStream.cpp @@ -67,15 +67,8 @@ nsresult nsJARInputStream::InitFile(nsJAR* aJar, nsZipItem* item) { // Must keep handle to filepointer and mmap structure as long as we need // access to the mmapped data - rv = aJar->mZip->GetPersistentHandle(item, &mItemHandle, - CacheAwareZipReader::DeferCaching); - if (NS_FAILED(rv)) { - return rv; - } - - mZs.next_in = - (Bytef*)aJar->mZip->GetData(item, CacheAwareZipReader::DeferCaching); - + mFd = aJar->mZip->GetFD(); + mZs.next_in = (Bytef*)aJar->mZip->GetData(item); if (!mZs.next_in) { return NS_ERROR_FILE_CORRUPTED; } @@ -199,7 +192,7 @@ nsJARInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytesRead) { *aBytesRead = 0; nsresult rv = NS_OK; - MMAP_FAULT_HANDLER_BEGIN_HANDLE(mItemHandle.UnderlyingFD()) + MMAP_FAULT_HANDLER_BEGIN_HANDLE(mFd) switch (mMode) { case MODE_NOTINITED: return NS_OK; @@ -218,15 +211,15 @@ nsJARInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytesRead) { rv = ContinueInflate(aBuffer, aCount, aBytesRead); } // be aggressive about releasing the file! - // note that sometimes, we will release mItemHandle before we've finished + // note that sometimes, we will release mFd before we've finished // deflating - this is because zlib buffers the input if (mZs.avail_in == 0) { - mItemHandle.ReleaseHandle(); + mFd = nullptr; } break; case MODE_COPY: - if (mItemHandle) { + if (mFd) { uint32_t count = std::min(aCount, mOutSize - uint32_t(mZs.total_out)); if (count) { memcpy(aBuffer, mZs.next_in + mZs.total_out, count); @@ -235,10 +228,9 @@ nsJARInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytesRead) { *aBytesRead = count; } // be aggressive about releasing the file! - // note that sometimes, we will release mItemHandle before we've finished - // copying. + // note that sometimes, we will release mFd before we've finished copying. if (mZs.total_out >= mOutSize) { - mItemHandle.ReleaseHandle(); + mFd = nullptr; } break; } @@ -270,7 +262,7 @@ nsJARInputStream::Close() { } #endif mMode = MODE_CLOSED; - mItemHandle.ReleaseHandle(); + mFd = nullptr; return NS_OK; } diff --git a/modules/libjar/nsJARInputStream.h b/modules/libjar/nsJARInputStream.h index 65639134470a..a69bc8c28a79 100644 --- a/modules/libjar/nsJARInputStream.h +++ b/modules/libjar/nsJARInputStream.h @@ -11,7 +11,6 @@ #include "nsJAR.h" #include "nsTArray.h" #include "mozilla/Attributes.h" -#include "mozilla/Omnijar.h" #ifdef MOZ_JAR_BROTLI struct BrotliDecoderStateStruct; @@ -52,11 +51,11 @@ class nsJARInputStream final : public nsIInputStream { private: ~nsJARInputStream() { Close(); } - mozilla::CacheAwareZipHandle mItemHandle; // handle for reading - uint32_t mOutSize; // inflated size - uint32_t mInCrc; // CRC as provided by the zipentry - uint32_t mOutCrc; // CRC as calculated by me - z_stream mZs; // zip data structure + RefPtr mFd; // handle for reading + uint32_t mOutSize; // inflated size + uint32_t mInCrc; // CRC as provided by the zipentry + uint32_t mOutCrc; // CRC as calculated by me + z_stream mZs; // zip data structure #ifdef MOZ_JAR_BROTLI BrotliDecoderStateStruct* mBrotliState; // Brotli decoder state #endif diff --git a/modules/libjar/nsZipArchive.cpp b/modules/libjar/nsZipArchive.cpp index fb90f676636a..fc7d467cbda1 100644 --- a/modules/libjar/nsZipArchive.cpp +++ b/modules/libjar/nsZipArchive.cpp @@ -341,21 +341,11 @@ nsZipHandle::~nsZipHandle() { //--------------------------------------------- // nsZipArchive::OpenArchive //--------------------------------------------- -nsresult nsZipArchive::OpenArchive(nsZipHandle* aZipHandle, PRFileDesc* aFd, - Span aCachedCentral) { +nsresult nsZipArchive::OpenArchive(nsZipHandle* aZipHandle, PRFileDesc* aFd) { mFd = aZipHandle; //-- get table of contents for archive - nsresult rv = NS_OK; - if (!mBuiltFileList) { - if (!aCachedCentral.IsEmpty()) { - auto* start = aCachedCentral.Elements(); - auto* end = start + aCachedCentral.Length(); - rv = BuildFileListFromBuffer(start, end); - } else { - rv = BuildFileList(aFd); - } - } + nsresult rv = BuildFileList(aFd); if (NS_SUCCEEDED(rv)) { if (aZipHandle->mFile && XRE_IsParentProcess()) { static char* env = PR_GetEnv("MOZ_JAR_LOG_FILE"); @@ -409,8 +399,7 @@ nsresult nsZipArchive::OpenArchive(nsZipHandle* aZipHandle, PRFileDesc* aFd, return rv; } -nsresult nsZipArchive::OpenArchive(nsIFile* aFile, - Span aCachedCentral) { +nsresult nsZipArchive::OpenArchive(nsIFile* aFile) { RefPtr handle; #if defined(XP_WIN) mozilla::AutoFDClose fd; @@ -421,9 +410,9 @@ nsresult nsZipArchive::OpenArchive(nsIFile* aFile, if (NS_FAILED(rv)) return rv; #if defined(XP_WIN) - return OpenArchive(handle, fd.get(), aCachedCentral); + return OpenArchive(handle, fd.get()); #else - return OpenArchive(handle, nullptr, aCachedCentral); + return OpenArchive(handle); #endif } @@ -473,75 +462,13 @@ nsresult nsZipArchive::CloseArchive() { // Let us also cleanup the mFiles table for re-use on the next 'open' call memset(mFiles, 0, sizeof(mFiles)); mBuiltSynthetics = false; - - AutoWriteLock lock(mLazyOpenLock); - mLazyOpenParams = Nothing(); - return NS_OK; } -nsresult nsZipArchive::EnsureArchiveOpenedOnDisk() { - { - AutoReadLock lock(mLazyOpenLock); - if (!mLazyOpenParams) { - return NS_OK; - } - } - - AutoWriteLock lock(mLazyOpenLock); - if (!mLazyOpenParams) { - // Another thread beat us to opening the archive while we were waiting on - // the mutex. - return NS_OK; - } - - nsresult rv = OpenArchive(mLazyOpenParams->mFile); - if (NS_WARN_IF(NS_FAILED(rv))) { - return NS_ERROR_UNEXPECTED; - } - mLazyOpenParams = Nothing(); - - return NS_OK; -} - -nsresult nsZipArchive::EnsureFileListBuilt() { - { - AutoReadLock lock(mLazyOpenLock); - if (!mLazyOpenParams || mBuiltFileList) { - return NS_OK; - } - } - - AutoWriteLock lock(mLazyOpenLock); - if (!mLazyOpenParams || mBuiltFileList) { - // Another thread beat us to building the file list while we were waiting - // on the mutex. - return NS_OK; - } - - nsresult rv; - if (!mLazyOpenParams->mCachedCentral.IsEmpty()) { - auto* start = mLazyOpenParams->mCachedCentral.Elements(); - auto* end = start + mLazyOpenParams->mCachedCentral.Length(); - rv = BuildFileListFromBuffer(start, end); - } else { - rv = OpenArchive(mLazyOpenParams->mFile); - mLazyOpenParams = Nothing(); - } - - return rv; -} - //--------------------------------------------- // nsZipArchive::GetItem //--------------------------------------------- nsZipItem* nsZipArchive::GetItem(const char* aEntryName) { - nsresult rv = EnsureFileListBuilt(); - - if (NS_WARN_IF(NS_FAILED(rv))) { - return nullptr; - } - if (aEntryName) { uint32_t len = strlen(aEntryName); //-- If the request is for a directory, make sure that synthetic entries @@ -625,12 +552,6 @@ nsresult nsZipArchive::ExtractFile(nsZipItem* item, nsIFile* outFile, nsresult nsZipArchive::FindInit(const char* aPattern, nsZipFind** aFind) { if (!aFind) return NS_ERROR_ILLEGAL_VALUE; - nsresult rv = EnsureFileListBuilt(); - - if (NS_WARN_IF(NS_FAILED(rv))) { - return NS_ERROR_UNEXPECTED; - } - // null out param in case an error happens *aFind = nullptr; @@ -638,7 +559,7 @@ nsresult nsZipArchive::FindInit(const char* aPattern, nsZipFind** aFind) { char* pattern = 0; // Create synthetic directory entries on demand - rv = BuildSynthetics(); + nsresult rv = BuildSynthetics(); if (rv != NS_OK) return rv; // validate the pattern @@ -682,12 +603,7 @@ nsresult nsZipFind::FindNext(const char** aResult, uint16_t* aNameLen) { *aResult = 0; *aNameLen = 0; - - // NOTE: don't use GetFD here. if mFd is not null, then we need to have this - // fault handler, as we may be reading from the memory mapped file. However - // if it is null, then we can guarantee that we're reading here from a cached - // buffer, which we assume is not mapped to a file. - MMAP_FAULT_HANDLER_BEGIN_HANDLE(mArchive->mFd) + MMAP_FAULT_HANDLER_BEGIN_HANDLE(mArchive->GetFD()) // we start from last match, look for next while (mSlot < ZIP_TABSIZE) { // move to next in current chain, or move to new slot @@ -733,13 +649,10 @@ nsZipItem* nsZipArchive::CreateZipItem() { // nsZipArchive::BuildFileList //--------------------------------------------- nsresult nsZipArchive::BuildFileList(PRFileDesc* aFd) { - mBuiltFileList = true; // Get archive size using end pos const uint8_t* buf; const uint8_t* startp = mFd->mFileData; const uint8_t* endp = startp + mFd->mLen; - - nsresult rv; MMAP_FAULT_HANDLER_BEGIN_HANDLE(mFd) uint32_t centralOffset = 4; // Only perform readahead in the parent process. Children processes @@ -764,63 +677,20 @@ nsresult nsZipArchive::BuildFileList(PRFileDesc* aFd) { return NS_ERROR_FILE_CORRUPTED; } - uintptr_t startpInt = reinterpret_cast(startp); - if (startpInt + centralOffset < startpInt || centralOffset > mFd->mLen) { + buf = startp + centralOffset; + + // avoid overflow of startp + centralOffset. + if (buf < startp) { return NS_ERROR_FILE_CORRUPTED; } - buf = startp + centralOffset; - - mZipCentralOffset = centralOffset; - rv = BuildFileListFromBuffer(buf, endp); - - MMAP_FAULT_HANDLER_CATCH(NS_ERROR_FAILURE) - return rv; -} - -UniquePtr nsZipArchive::CopyCentralDirectoryBuffer(size_t* aSize) { - *aSize = 0; - - // mZipCentralOffset could in theory be 0. In practice though, we likely - // won't ever see this. If the end result is that we can't cache the buffer - // in these cases, that's fine. - if (!mZipCentralOffset || !mZipCentralSize) { - return nullptr; - } - - const uint8_t* buf; - const uint8_t* startp = mFd->mFileData; - buf = startp + mZipCentralOffset; - - // Just a sanity check to make sure these values haven't overflowed the - // buffer mapped to our file. Technically the pointer could overflow the max - // pointer value, but that could only happen with this check succeeding if - // mFd->mLen is incorrect, which we will here assume is impossible. - if (mZipCentralOffset + mZipCentralSize > mFd->mLen) { - return nullptr; - } - - auto resultBuf = MakeUnique(mZipCentralSize); - - MMAP_FAULT_HANDLER_BEGIN_HANDLE(mFd) - memcpy(resultBuf.get(), buf, mZipCentralSize); - MMAP_FAULT_HANDLER_CATCH(nullptr) - - *aSize = mZipCentralSize; - return resultBuf; -} - -nsresult nsZipArchive::BuildFileListFromBuffer(const uint8_t* aBuf, - const uint8_t* aEnd) { - mBuiltFileList = true; - const uint8_t* buf = aBuf; //-- Read the central directory headers uint32_t sig = 0; while ((buf + int32_t(sizeof(uint32_t)) > buf) && - (buf + int32_t(sizeof(uint32_t)) <= aEnd) && + (buf + int32_t(sizeof(uint32_t)) <= endp) && ((sig = xtolong(buf)) == CENTRALSIG)) { // Make sure there is enough data available. - if ((buf > aEnd) || (aEnd - buf < ZIPCENTRAL_SIZE)) { + if ((buf > endp) || (endp - buf < ZIPCENTRAL_SIZE)) { return NS_ERROR_FILE_CORRUPTED; } @@ -838,7 +708,7 @@ nsresult nsZipArchive::BuildFileListFromBuffer(const uint8_t* aBuf, return NS_ERROR_FILE_CORRUPTED; } if (buf >= buf + diff || // No overflow - buf >= aEnd - diff) { + buf >= endp - diff) { return NS_ERROR_FILE_CORRUPTED; } @@ -865,18 +735,18 @@ nsresult nsZipArchive::BuildFileListFromBuffer(const uint8_t* aBuf, } // Make the comment available for consumers. - if ((aEnd >= buf) && (aEnd - buf >= ZIPEND_SIZE)) { + if ((endp >= buf) && (endp - buf >= ZIPEND_SIZE)) { ZipEnd* zipend = (ZipEnd*)buf; buf += ZIPEND_SIZE; uint16_t commentlen = xtoint(zipend->commentfield_len); - if (aEnd - buf >= commentlen) { - mCommentPtr = (const char*)aBuf; + if (endp - buf >= commentlen) { + mCommentPtr = (const char*)buf; mCommentLen = commentlen; } } - mZipCentralSize = buf - aBuf; + MMAP_FAULT_HANDLER_CATCH(NS_ERROR_FAILURE) return NS_OK; } @@ -946,64 +816,15 @@ nsresult nsZipArchive::BuildSynthetics() { } nsZipHandle* nsZipArchive::GetFD() { - nsresult rv = EnsureArchiveOpenedOnDisk(); - if (NS_WARN_IF(NS_FAILED(rv))) { - return nullptr; - } + if (!mFd) return nullptr; return mFd.get(); } -void nsZipArchive::GetURIString(nsACString& result) { - { - AutoReadLock lock(mLazyOpenLock); - if (!mLazyOpenParams) { - mFd->mFile.GetURIString(result); - return; - } - } - AutoReadLock lock(mLazyOpenLock); - if (!mLazyOpenParams) { - // Another thread consumed mLazyOpenParams while we were waiting. - mFd->mFile.GetURIString(result); - return; - } - - // This is a bit tricky - typically, we could just - // NS_GetURLSpecFromActualFile from mLazyOpenParams->mFile or from - // mFd->mFile.GetBaseFile(), depending on which we currently have. However, - // this won't actually be correct if this zip archive is nested inside - // another archive. However, at present, we know that mLazyOpenParams can - // only be here if we were opened from a real underlying file, so we assume - // that we're safe to do this. Any future code that breaks this assumption - // will need to update things here. - NS_GetURLSpecFromActualFile(mLazyOpenParams->mFile, result); -} - -already_AddRefed nsZipArchive::GetBaseFile() { - { - AutoReadLock lock(mLazyOpenLock); - if (!mLazyOpenParams) { - return mFd->mFile.GetBaseFile(); - } - } - AutoReadLock lock(mLazyOpenLock); - if (!mLazyOpenParams) { - // Another thread consumed mLazyOpenParams while we were waiting. - return mFd->mFile.GetBaseFile(); - } - - nsCOMPtr file = mLazyOpenParams->mFile; - return file.forget(); -} - //--------------------------------------------- // nsZipArchive::GetDataOffset //--------------------------------------------- uint32_t nsZipArchive::GetDataOffset(nsZipItem* aItem) { MOZ_ASSERT(aItem); - nsresult rv = EnsureArchiveOpenedOnDisk(); - MOZ_RELEASE_ASSERT(!NS_FAILED(rv), - "Should have been able to open the zip archive"); uint32_t offset; MMAP_FAULT_HANDLER_BEGIN_HANDLE(mFd) @@ -1034,10 +855,6 @@ uint32_t nsZipArchive::GetDataOffset(nsZipItem* aItem) { //--------------------------------------------- const uint8_t* nsZipArchive::GetData(nsZipItem* aItem) { MOZ_ASSERT(aItem); - nsresult rv = EnsureArchiveOpenedOnDisk(); - if (NS_WARN_IF(NS_FAILED(rv))) { - return nullptr; - } uint32_t offset = GetDataOffset(aItem); MMAP_FAULT_HANDLER_BEGIN_HANDLE(mFd) @@ -1072,12 +889,8 @@ int64_t nsZipArchive::SizeOfMapping() { return mFd ? mFd->SizeOfMapping() : 0; } nsZipArchive::nsZipArchive() : mRefCnt(0), mCommentPtr(nullptr), - mZipCentralOffset(0), - mZipCentralSize(0), mCommentLen(0), mBuiltSynthetics(false), - mBuiltFileList(false), - mLazyOpenLock("nsZipArchive::mLazyOpenLock"), mUseZipLog(false) { // initialize the table to nullptr memset(mFiles, 0, sizeof(mFiles)); @@ -1385,14 +1198,12 @@ uint8_t* nsZipCursor::ReadOrCopy(uint32_t* aBytesRead, bool aCopy) { nsZipItemPtr_base::nsZipItemPtr_base(nsZipArchive* aZip, const char* aEntryName, bool doCRC) : mReturnBuf(nullptr), mReadlen(0) { - nsZipItem* item = aZip->GetItem(aEntryName); - if (!item) { - return; - } - // make sure the ziparchive hangs around mZipHandle = aZip->GetFD(); + nsZipItem* item = aZip->GetItem(aEntryName); + if (!item) return; + uint32_t size = 0; bool compressed = (item->Compression() == DEFLATED); #ifdef MOZ_JAR_BROTLI diff --git a/modules/libjar/nsZipArchive.h b/modules/libjar/nsZipArchive.h index 6ce7ed612d46..898e6a8c9491 100644 --- a/modules/libjar/nsZipArchive.h +++ b/modules/libjar/nsZipArchive.h @@ -17,11 +17,9 @@ #include "nsIFile.h" #include "nsISupportsImpl.h" // For mozilla::ThreadSafeAutoRefCnt #include "mozilla/ArenaAllocator.h" -#include "mozilla/Atomics.h" #include "mozilla/FileUtils.h" #include "mozilla/FileLocation.h" #include "mozilla/UniquePtr.h" -#include "mozilla/RWLock.h" class nsZipFind; struct PRFileDesc; @@ -86,22 +84,6 @@ class nsZipArchive final { /** destructing the object closes the archive */ ~nsZipArchive(); - /** - * LazyOpenArchiveParams is a class which is used to store cached - * contents of omnijars. - * - */ - struct LazyOpenArchiveParams { - nsCOMPtr mFile; - mozilla::Span mCachedCentral; - - LazyOpenArchiveParams(nsIFile* aFile, - mozilla::Span aCachedCentral) - : mFile(nullptr), mCachedCentral(aCachedCentral) { - aFile->Clone(getter_AddRefs(mFile)); - } - }; - public: static const char* sFileCorruptedReason; @@ -115,16 +97,11 @@ class nsZipArchive final { * object. If we were allowed to use exceptions this would have been * part of the constructor * - * @param aZipHandle The nsZipHandle used to access the zip - * @param aFd Optional PRFileDesc for Windows readahead - optimization - * @param aCachedCentral Optional cached buffer containing the zip central - for this zip. + * @param aZipHandle The nsZipHandle used to access the zip + * @param aFd Optional PRFileDesc for Windows readahead optimization * @return status code */ - nsresult OpenArchive(nsZipHandle* aZipHandle, PRFileDesc* aFd = nullptr, - mozilla::Span aCachedCentral = - mozilla::Span()); + nsresult OpenArchive(nsZipHandle* aZipHandle, PRFileDesc* aFd = nullptr); /** * OpenArchive @@ -132,46 +109,9 @@ class nsZipArchive final { * Convenience function that generates nsZipHandle * * @param aFile The file used to access the zip - * @param aCachedCentral Optional cached buffer containing the zip central - for this zip. * @return status code */ - nsresult OpenArchive(nsIFile* aFile, - mozilla::Span aCachedCentral = - mozilla::Span()); - - /** - * Ensures underlying archive is opened, if it was opened with - * LazyOpenArchive. - * - * Convenience function that generates nsZipHandle - * - * @param aFile The file used to access the zip - * @return status code - */ - nsresult EnsureArchiveOpenedOnDisk(); - - /** - * OpenArchive - * - * Lazily opens the zip archive on the first request to get data from it. - * NOTE: The buffer provided for aCachedCentral must outlive this - * nsZipArchive. This is presently true for the StartupCache, as it ensures - * that even past cache invalidation, all accessed buffers persist for the - * lifetime of the application, but we will need to ensure that this remains - * true. - * - * @param aFile The file used to access the zip - * @param aCachedCentral Cached buffer containing the zip central - for this zip. - * @return status code - */ - nsresult LazyOpenArchive(nsIFile* aFile, - mozilla::Span aCachedCentral) { - mozilla::AutoWriteLock lock(mLazyOpenLock); - mLazyOpenParams.emplace(aFile, aCachedCentral); - return NS_OK; - } + nsresult OpenArchive(nsIFile* aFile); /** * Test the integrity of items in this archive by running @@ -227,21 +167,6 @@ class nsZipArchive final { */ nsZipHandle* GetFD(); - /* - * Gets the URI string to the mapped file. One could get this URI string - * in a roundabout way using GetFD, but GetFD requires opening the file for - * read access, which can be expensive. - */ - void GetURIString(nsACString& result); - - /* - * Gets the underlying nsIFile pointer. Like GetURIString, this is to be - * preferred over GetFD where possible, because it does not require opening - * the file for read access, which can be expensive, and is to be avoided - * when possible during application startup. - */ - already_AddRefed GetBaseFile(); - /** * Gets the data offset. * @param aItem Pointer to nsZipItem @@ -256,17 +181,6 @@ class nsZipArchive final { */ const uint8_t* GetData(nsZipItem* aItem); - /** - * Copies the contents of the zip central directory, and returns it to the - * caller to take ownership. This is useful for caching the contents of the - * central directory, which can be compressed and stored elsewhere, and - * passed back into OpenArchive when this archive is opened in the future. - * - * @param aSize size_t pointer to be filled with the size of the - returned buffer. - */ - mozilla::UniquePtr CopyCentralDirectoryBuffer(size_t* aSize); - bool GetComment(nsACString& aComment); /** @@ -290,20 +204,14 @@ class nsZipArchive final { mozilla::ArenaAllocator<1024, sizeof(void*)> mArena; const char* mCommentPtr; - size_t mZipCentralOffset; - size_t mZipCentralSize; uint16_t mCommentLen; // Whether we synthesized the directory entries bool mBuiltSynthetics; - bool mBuiltFileList; // file handle RefPtr mFd; - mozilla::Maybe mLazyOpenParams; - mozilla::RWLock mLazyOpenLock; - // file URI, for logging nsCString mURI; @@ -315,9 +223,7 @@ class nsZipArchive final { //--- private methods --- nsZipItem* CreateZipItem(); nsresult BuildFileList(PRFileDesc* aFd = nullptr); - nsresult BuildFileListFromBuffer(const uint8_t* aBuf, const uint8_t* aEnd); nsresult BuildSynthetics(); - nsresult EnsureFileListBuilt(); nsZipArchive& operator=(const nsZipArchive& rhs) = delete; nsZipArchive(const nsZipArchive& rhs) = delete; diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp index 73be349d93cf..4f4782e50810 100644 --- a/modules/libpref/Preferences.cpp +++ b/modules/libpref/Preferences.cpp @@ -82,6 +82,7 @@ #include "nsXPCOMCID.h" #include "nsXPCOM.h" #include "nsXULAppAPI.h" +#include "nsZipArchive.h" #include "plbase64.h" #include "PLDHashTable.h" #include "plstr.h" @@ -4311,7 +4312,7 @@ static nsresult pref_LoadPrefsInDir(nsIFile* aDir, return rv; } -static nsresult pref_ReadPrefFromJar(CacheAwareZipReader* aJarReader, +static nsresult pref_ReadPrefFromJar(nsZipArchive* aJarReader, const char* aName) { TimeStamp startTime = TimeStamp::Now(); @@ -4328,8 +4329,8 @@ static nsresult pref_ReadPrefFromJar(CacheAwareZipReader* aJarReader, return NS_OK; } -static nsresult pref_ReadDefaultPrefs( - const RefPtr& jarReader, const char* path) { +static nsresult pref_ReadDefaultPrefs(const RefPtr jarReader, + const char* path) { UniquePtr find; nsTArray prefEntries; const char* entryName; @@ -4508,7 +4509,7 @@ nsresult Preferences::InitInitialObjects(bool aIsStartup) { const char* entryName; uint16_t entryNameLen; - RefPtr jarReader = Omnijar::GetReader(Omnijar::GRE); + RefPtr jarReader = Omnijar::GetReader(Omnijar::GRE); if (jarReader) { #ifdef MOZ_WIDGET_ANDROID // Try to load an architecture-specific greprefs.js first. This will be @@ -4590,7 +4591,7 @@ nsresult Preferences::InitInitialObjects(bool aIsStartup) { // Load jar:$app/omni.jar!/defaults/preferences/*.js // or jar:$gre/omni.jar!/defaults/preferences/*.js. - RefPtr appJarReader = Omnijar::GetReader(Omnijar::APP); + RefPtr appJarReader = Omnijar::GetReader(Omnijar::APP); // GetReader(Omnijar::APP) returns null when `$app == $gre`, in // which case we look for app-specific default preferences in $gre. diff --git a/startupcache/PStartupCache.ipdl b/startupcache/PStartupCache.ipdl deleted file mode 100644 index a1cdf7855ca8..000000000000 --- a/startupcache/PStartupCache.ipdl +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */ -/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -include protocol PContent; - -using class mozilla::TimeStamp from "mozilla/TimeStamp.h"; -using mozilla::void_t from "ipc/IPCMessageUtils.h"; - -namespace mozilla { -namespace scache { - -struct EntryData { - nsCString key; - // This will be an empty array if data is present in the previous - // session's cache. - uint8_t[] data; -}; - -protocol PStartupCache -{ - manager PContent; - -parent: - async __delete__(EntryData[] entries); -}; - -} // namespace scache -} // namespace mozilla diff --git a/startupcache/StartupCache.cpp b/startupcache/StartupCache.cpp index ab83757a78e9..a9580f3360db 100644 --- a/startupcache/StartupCache.cpp +++ b/startupcache/StartupCache.cpp @@ -9,18 +9,12 @@ #include "mozilla/IOInterposer.h" #include "mozilla/AutoMemMap.h" #include "mozilla/IOBuffers.h" -#include "mozilla/ipc/FileDescriptor.h" -#include "mozilla/ipc/GeckoChildProcessHost.h" #include "mozilla/MemoryReporting.h" #include "mozilla/MemUtils.h" #include "mozilla/MmapFaultHandler.h" #include "mozilla/ResultExtensions.h" #include "mozilla/scache/StartupCache.h" -#include "mozilla/scache/StartupCacheChild.h" #include "mozilla/ScopeExit.h" -#include "mozilla/dom/ContentChild.h" -#include "mozilla/dom/ContentParent.h" -#include "mozilla/dom/ipc/MemMapSnapshot.h" #include "nsClassHashtable.h" #include "nsComponentManagerUtils.h" @@ -57,55 +51,27 @@ # define SC_WORDSIZE "8" #endif -#define DOC_ELEM_INSERTED_TOPIC "document-element-inserted" -#define CONTENT_DOCUMENT_LOADED_TOPIC "content-document-loaded" - using namespace mozilla::Compression; namespace mozilla { namespace scache { -// This is included here, rather than as a member of the StartupCache -// singleton, because including it there would mean we need to pull -// in the chromium IPC headers everywhere we reference StartupCache.h -static ipc::FileDescriptor sSharedDataFD; - MOZ_DEFINE_MALLOC_SIZE_OF(StartupCacheMallocSizeOf) NS_IMETHODIMP StartupCache::CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize) { - MutexAutoLock lock(mLock); - if (XRE_IsParentProcess()) { - MOZ_COLLECT_REPORT( - "explicit/startup-cache/mapping", KIND_NONHEAP, UNITS_BYTES, - mCacheData.nonHeapSizeOfExcludingThis(), - "Memory used to hold the mapping of the startup cache from file. " - "This memory is likely to be swapped out shortly after start-up."); - } else { - // In the child process, mCacheData actually points to the parent's - // mSharedData. We just want to report this once as explicit under - // the parent process's report. - MOZ_COLLECT_REPORT( - "startup-cache-shared-mapping", KIND_NONHEAP, UNITS_BYTES, - mCacheData.nonHeapSizeOfExcludingThis(), - "Memory used to hold the decompressed contents of part of the " - "startup cache, to be used by child processes. This memory is " - "likely to be swapped out shortly after start-up."); - } + MOZ_COLLECT_REPORT( + "explicit/startup-cache/mapping", KIND_NONHEAP, UNITS_BYTES, + mCacheData.nonHeapSizeOfExcludingThis(), + "Memory used to hold the mapping of the startup cache from file. " + "This memory is likely to be swapped out shortly after start-up."); MOZ_COLLECT_REPORT("explicit/startup-cache/data", KIND_HEAP, UNITS_BYTES, HeapSizeOfIncludingThis(StartupCacheMallocSizeOf), "Memory used by the startup cache for things other than " "the file mapping."); - MOZ_COLLECT_REPORT( - "explicit/startup-cache/shared-mapping", KIND_NONHEAP, UNITS_BYTES, - mSharedData.nonHeapSizeOfExcludingThis(), - "Memory used to hold the decompressed contents of part of the " - "startup cache, to be used by child processes. This memory is " - "likely to be swapped out shortly after start-up."); - return NS_OK; } @@ -143,59 +109,39 @@ static nsresult MapLZ4ErrorToNsresult(size_t aError) { return NS_ERROR_FAILURE; } +StartupCache* StartupCache::GetSingletonNoInit() { + return StartupCache::gStartupCache; +} + StartupCache* StartupCache::GetSingleton() { + if (!gStartupCache) { + if (!XRE_IsParentProcess()) { + return nullptr; + } +#ifdef MOZ_DISABLE_STARTUPCACHE + return nullptr; +#else + StartupCache::InitSingleton(); +#endif + } + return StartupCache::gStartupCache; } void StartupCache::DeleteSingleton() { StartupCache::gStartupCache = nullptr; } -nsresult StartupCache::PartialInitSingleton(nsIFile* aProfileLocalDir) { -#ifdef MOZ_DISABLE_STARTUPCACHE - return NS_OK; -#else - if (!XRE_IsParentProcess()) { - return NS_OK; - } - +nsresult StartupCache::InitSingleton() { nsresult rv; StartupCache::gStartupCache = new StartupCache(); - rv = StartupCache::gStartupCache->PartialInit(aProfileLocalDir); + rv = StartupCache::gStartupCache->Init(); if (NS_FAILED(rv)) { StartupCache::gStartupCache = nullptr; } return rv; -#endif -} - -nsresult StartupCache::InitChildSingleton(char* aScacheHandleStr, - char* aScacheSizeStr) { -#ifdef MOZ_DISABLE_STARTUPCACHE - return NS_OK; -#else - MOZ_ASSERT(!XRE_IsParentProcess()); - - nsresult rv; - StartupCache::gStartupCache = new StartupCache(); - - rv = StartupCache::gStartupCache->ParseStartupCacheCmdLineArgs( - aScacheHandleStr, aScacheSizeStr); - if (NS_FAILED(rv)) { - StartupCache::gStartupCache = nullptr; - } - return rv; -#endif -} - -nsresult StartupCache::FullyInitSingleton() { - if (!StartupCache::gStartupCache) { - return NS_OK; - } - return StartupCache::gStartupCache->FullyInit(); } StaticRefPtr StartupCache::gStartupCache; -ProcessType sProcessType; bool StartupCache::gShutdownInitiated; bool StartupCache::gIgnoreDiskCache; bool StartupCache::gFoundDiskCacheOnInit; @@ -203,72 +149,21 @@ bool StartupCache::gFoundDiskCacheOnInit; NS_IMPL_ISUPPORTS(StartupCache, nsIMemoryReporter) StartupCache::StartupCache() - : mLock("StartupCache::mLock"), + : mTableLock("StartupCache::mTableLock"), mDirty(false), mWrittenOnce(false), mCurTableReferenced(false), - mLoaded(false), - mFullyInitialized(false), mRequestedCount(0), - mPrefetchSize(0), - mSharedDataSize(0), mCacheEntriesBaseOffset(0), mPrefetchThread(nullptr) {} StartupCache::~StartupCache() { UnregisterWeakMemoryReporter(this); } -nsresult StartupCache::InitChild(StartupCacheChild* cacheChild) { - mChildActor = cacheChild; - sProcessType = - GetChildProcessType(dom::ContentChild::GetSingleton()->GetRemoteType()); - - mObserverService = do_GetService("@mozilla.org/observer-service;1"); - - if (!mObserverService) { - NS_WARNING("Could not get observerService."); - return NS_ERROR_UNEXPECTED; - } - - mListener = new StartupCacheListener(); - nsresult rv = mObserverService->AddObserver( - mListener, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - NS_ENSURE_SUCCESS(rv, rv); - rv = mObserverService->AddObserver(mListener, "startupcache-invalidate", - false); - - NS_ENSURE_SUCCESS(rv, rv); - - if (mChildActor) { - if (sProcessType == ProcessType::PrivilegedAbout) { - // Since we control all of the documents loaded in the privileged - // content process, we can increase the window of active time for the - // StartupCache to include the scripts that are loaded until the - // first document finishes loading. - mContentStartupFinishedTopic.AssignLiteral(CONTENT_DOCUMENT_LOADED_TOPIC); - } else { - // In the child process, we need to freeze the startup cache before any - // untrusted code has been executed. The insertion of the first DOM - // document element may sometimes be earlier than is ideal, but at - // least it should always be safe. - mContentStartupFinishedTopic.AssignLiteral(DOC_ELEM_INSERTED_TOPIC); - } - - mObserverService->AddObserver(mListener, mContentStartupFinishedTopic.get(), - false); - } - - mFullyInitialized = true; - RegisterWeakMemoryReporter(this); - return NS_OK; -} - -nsresult StartupCache::PartialInit(nsIFile* aProfileLocalDir) { - MutexAutoLock lock(mLock); +nsresult StartupCache::Init() { // workaround for bug 653936 nsCOMPtr jarInitializer( do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "jar")); - sProcessType = ProcessType::Parent; nsresult rv; if (mozilla::RunningGTest()) { @@ -282,9 +177,9 @@ nsresult StartupCache::PartialInit(nsIFile* aProfileLocalDir) { if (env && *env) { rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(env), false, getter_AddRefs(mFile)); - } else if (aProfileLocalDir) { + } else { nsCOMPtr file; - rv = aProfileLocalDir->Clone(getter_AddRefs(file)); + rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(file)); if (NS_FAILED(rv)) { // return silently, this will fail in mochitests's xpcshell process. return rv; @@ -302,15 +197,25 @@ nsresult StartupCache::PartialInit(nsIFile* aProfileLocalDir) { NS_ENSURE_SUCCESS(rv, rv); mFile = file; - } else { - return NS_ERROR_INVALID_ARG; } NS_ENSURE_TRUE(mFile, NS_ERROR_UNEXPECTED); - mDecompressionContext = MakeUnique(true); + mObserverService = do_GetService("@mozilla.org/observer-service;1"); + + if (!mObserverService) { + NS_WARNING("Could not get observerService."); + return NS_ERROR_UNEXPECTED; + } + + mListener = new StartupCacheListener(); + rv = mObserverService->AddObserver(mListener, NS_XPCOM_SHUTDOWN_OBSERVER_ID, + false); + NS_ENSURE_SUCCESS(rv, rv); + rv = mObserverService->AddObserver(mListener, "startupcache-invalidate", + false); + NS_ENSURE_SUCCESS(rv, rv); - Unused << mCacheData.init(mFile); auto result = LoadArchive(); rv = result.isErr() ? result.unwrapErr() : NS_OK; @@ -320,136 +225,15 @@ nsresult StartupCache::PartialInit(nsIFile* aProfileLocalDir) { // If it's corrupted, just remove it and start over. if (gIgnoreDiskCache || (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND)) { NS_WARNING("Failed to load startupcache file correctly, removing!"); - InvalidateCacheImpl(); - } - - return NS_OK; -} - -nsresult StartupCache::FullyInit() { - mObserverService = do_GetService("@mozilla.org/observer-service;1"); - - if (!mObserverService) { - NS_WARNING("Could not get observerService."); - return NS_ERROR_UNEXPECTED; - } - - mListener = new StartupCacheListener(); - nsresult rv = mObserverService->AddObserver( - mListener, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - rv = mObserverService->AddObserver(mListener, "startupcache-invalidate", - false); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; + InvalidateCache(); } RegisterWeakMemoryReporter(this); - mFullyInitialized = true; - return NS_OK; -} - -void StartupCache::InitContentChild(dom::ContentParent& parent) { - auto* cache = GetSingleton(); - if (!cache) { - return; - } - - auto processType = GetChildProcessType(parent.GetRemoteType()); - bool wantScriptData = !cache->mInitializedProcesses.contains(processType); - cache->mInitializedProcesses += processType; - Unused << parent.SendPStartupCacheConstructor(wantScriptData); -} - -void StartupCache::AddStartupCacheCmdLineArgs( - mozilla::ipc::GeckoChildProcessHost& procHost, - std::vector& aExtraOpts) { -#ifndef ANDROID - // Don't send original cache data to new processes if the cache has been - // invalidated. - if (!mSharedData.initialized() || gIgnoreDiskCache) { - return; - } - - // Formats a pointer or pointer-sized-integer as a string suitable for - // passing in an arguments list. - auto formatPtrArg = [](auto arg) { - return nsPrintfCString("%zu", uintptr_t(arg)); - }; - if (!mSharedDataHandle) { - auto fd = mSharedData.cloneHandle(); - MOZ_ASSERT(fd.IsValid()); - - mSharedDataHandle = fd.TakePlatformHandle(); - } - -# if defined(XP_WIN) - procHost.AddHandleToShare(mSharedDataHandle.get()); - aExtraOpts.push_back("-scacheHandle"); - aExtraOpts.push_back(formatPtrArg(mSharedDataHandle.get()).get()); -# else - procHost.AddFdToRemap(mSharedDataHandle.get(), kStartupCacheFd); -# endif - - aExtraOpts.push_back("-scacheSize"); - aExtraOpts.push_back(formatPtrArg(mSharedDataSize).get()); -#endif -} - -nsresult StartupCache::ParseStartupCacheCmdLineArgs(char* aScacheHandleStr, - char* aScacheSizeStr) { - // Parses an arg containing a pointer-sized-integer. - auto parseUIntPtrArg = [](char*& aArg) { - // ContentParent uses %zu to print a word-sized unsigned integer. So - // even though strtoull() returns a long long int, it will fit in a - // uintptr_t. - return uintptr_t(strtoull(aArg, &aArg, 10)); - }; - - MutexAutoLock lock(mLock); - if (aScacheHandleStr) { -#ifdef XP_WIN - auto parseHandleArg = [&](char*& aArg) { - return HANDLE(parseUIntPtrArg(aArg)); - }; - - sSharedDataFD = FileDescriptor(parseHandleArg(aScacheHandleStr)); -#endif - -#ifdef XP_UNIX - sSharedDataFD = FileDescriptor(UniqueFileHandle(kStartupCacheFd)); -#endif - MOZ_TRY(mCacheData.initWithHandle(sSharedDataFD, - parseUIntPtrArg(aScacheSizeStr))); - mCacheData.setPersistent(); - } - - nsresult rv; - auto result = LoadArchive(); - rv = result.isErr() ? result.unwrapErr() : NS_OK; - - // Sometimes we don't have a cache yet, that's ok. - // If it's corrupted, just remove it and start over. - if (gIgnoreDiskCache || (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND)) { - NS_WARNING("Failed to load startupcache file correctly, removing!"); - InvalidateCacheImpl(); - } + mDecompressionContext = MakeUnique(true); return NS_OK; } -ProcessType StartupCache::GetChildProcessType(const nsAString& remoteType) { - if (remoteType.EqualsLiteral(EXTENSION_REMOTE_TYPE)) { - return ProcessType::Extension; - } - if (remoteType.EqualsLiteral(PRIVILEGEDABOUT_REMOTE_TYPE)) { - return ProcessType::PrivilegedAbout; - } - return ProcessType::Web; -} - void StartupCache::StartPrefetchMemoryThread() { // XXX: It would be great for this to not create its own thread, unfortunately // there doesn't seem to be an existing thread that makes sense for this, so @@ -459,29 +243,27 @@ void StartupCache::StartPrefetchMemoryThread() { PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 256 * 1024); } -Result StartupCache::LoadEntriesOffDisk() { - mLock.AssertCurrentThreadOwns(); +/** + * LoadArchive can only be called from the main thread. + */ +Result StartupCache::LoadArchive() { + MOZ_ASSERT(NS_IsMainThread(), "Can only load startup cache on main thread"); + if (gIgnoreDiskCache) return Err(NS_ERROR_FAILURE); + + MOZ_TRY(mCacheData.init(mFile)); auto size = mCacheData.size(); + if (CanPrefetchMemory()) { + StartPrefetchMemoryThread(); + } uint32_t headerSize; - uint32_t prefetchSize; - size_t headerOffset = - sizeof(MAGIC) + sizeof(headerSize) + sizeof(prefetchSize); - if (size < headerOffset) { + if (size < sizeof(MAGIC) + sizeof(headerSize)) { return Err(NS_ERROR_UNEXPECTED); } auto data = mCacheData.get(); - auto start = data; auto end = data + size; - auto cleanup = MakeScopeExit([&]() { - WaitOnPrefetchThread(); - mTable.clear(); - mCacheData.reset(); - mSharedDataSize = 0; - }); - MMAP_FAULT_HANDLER_BEGIN_BUFFER(data.get(), size) if (memcmp(MAGIC, data.get(), sizeof(MAGIC))) { @@ -492,78 +274,45 @@ Result StartupCache::LoadEntriesOffDisk() { headerSize = LittleEndian::readUint32(data.get()); data += sizeof(headerSize); - prefetchSize = LittleEndian::readUint32(data.get()); - data += sizeof(prefetchSize); - - if (size < prefetchSize) { + if (headerSize > end - data) { MOZ_ASSERT(false, "StartupCache file is corrupt."); return Err(NS_ERROR_UNEXPECTED); } - if (size < headerOffset + headerSize) { - MOZ_ASSERT(false, "StartupCache file is corrupt."); - return Err(NS_ERROR_UNEXPECTED); - } - - if (CanPrefetchMemory()) { - mPrefetchSize = prefetchSize; - StartPrefetchMemoryThread(); - } - Range header(data, data + headerSize); data += headerSize; - uint32_t numSharedEntries = 0; - - mCacheEntriesBaseOffset = headerOffset + headerSize; + mCacheEntriesBaseOffset = sizeof(MAGIC) + sizeof(headerSize) + headerSize; { if (!mTable.reserve(STARTUP_CACHE_RESERVE_CAPACITY)) { return Err(NS_ERROR_UNEXPECTED); } + auto cleanup = MakeScopeExit([&]() { + WaitOnPrefetchThread(); + mTable.clear(); + mCacheData.reset(); + }); loader::InputBuffer buf(header); uint32_t currentOffset = 0; - mSharedDataSize = sizeof(MAGIC) + sizeof(numSharedEntries); while (!buf.finished()) { uint32_t offset = 0; uint32_t compressedSize = 0; uint32_t uncompressedSize = 0; - uint8_t sharedToChild = 0; nsCString key; buf.codeUint32(offset); buf.codeUint32(compressedSize); buf.codeUint32(uncompressedSize); - buf.codeUint8(sharedToChild); buf.codeString(key); if (offset + compressedSize > end - data) { - if (XRE_IsParentProcess()) { - MOZ_ASSERT(false, "StartupCache file is corrupt."); - return Err(NS_ERROR_UNEXPECTED); - } - - // If we're not the parent process, then we received a buffer with - // only data that was already prefetched. If that's the case, then - // just break because we've hit the end of that range. - break; - } - - EnumSet entryFlags; - if (sharedToChild) { - // We encode the key as a u16 indicating the length, followed by the - // contents of the string. We encode the uncompressed data similarly, - // but with a u32 indicating the length rather than a u16. - size_t sharedEntrySize = sizeof(uint16_t) + key.Length() + - sizeof(uint32_t) + uncompressedSize; - numSharedEntries++; - mSharedDataSize += sharedEntrySize; - entryFlags += StartupCacheEntryFlags::Shared; + MOZ_ASSERT(false, "StartupCache file is corrupt."); + return Err(NS_ERROR_UNEXPECTED); } // Make sure offsets match what we'd expect based on script ordering and // size, as a basic sanity check. if (offset != currentOffset) { - MOZ_ASSERT(false, "StartupCache file is corrupt."); return Err(NS_ERROR_UNEXPECTED); } currentOffset += compressedSize; @@ -573,204 +322,24 @@ Result StartupCache::LoadEntriesOffDisk() { // exists. If it does, we know the file must be corrupt. decltype(mTable)::AddPtr p = mTable.lookupForAdd(key); if (p) { - MOZ_ASSERT(false, "StartupCache file is corrupt."); return Err(NS_ERROR_UNEXPECTED); } - if (!mTable.add(p, key, - StartupCacheEntry(offset, compressedSize, - uncompressedSize, entryFlags))) { - MOZ_ASSERT(false, "StartupCache file is corrupt."); + if (!mTable.add( + p, key, + StartupCacheEntry(offset, compressedSize, uncompressedSize))) { return Err(NS_ERROR_UNEXPECTED); } } if (buf.error()) { - MOZ_ASSERT(false, "StartupCache file is corrupt."); return Err(NS_ERROR_UNEXPECTED); } - // We only get to init mSharedData once - we can't edit it after we created - // it, otherwise we'd be pulling memory out from underneath our child - // processes. - if (!mSharedData.initialized()) { - ipc::MemMapSnapshot mem; - if (mem.Init(mSharedDataSize).isErr()) { - MOZ_ASSERT(false, "Failed to init shared StartupCache data."); - return Err(NS_ERROR_UNEXPECTED); - } - - auto ptr = mem.Get(); - Range ptrRange(ptr, ptr + mSharedDataSize); - loader::PreallocatedOutputBuffer sharedBuf(ptrRange); - - if (sizeof(MAGIC) > sharedBuf.remainingCapacity()) { - MOZ_ASSERT(false); - return Err(NS_ERROR_UNEXPECTED); - } - uint8_t* sharedMagic = sharedBuf.write(sizeof(MAGIC)); - memcpy(sharedMagic, MAGIC, sizeof(MAGIC)); - sharedBuf.codeUint32(numSharedEntries); - - for (auto iter = mTable.iter(); !iter.done(); iter.next()) { - const auto& key = iter.get().key(); - auto& value = iter.get().value(); - - if (!value.mFlags.contains(StartupCacheEntryFlags::Shared)) { - continue; - } - - sharedBuf.codeString(key); - sharedBuf.codeUint32(value.mUncompressedSize); - - if (value.mUncompressedSize > sharedBuf.remainingCapacity()) { - MOZ_ASSERT(false); - return Err(NS_ERROR_UNEXPECTED); - } - value.mSharedDataOffset = sharedBuf.cursor(); - value.mData = MaybeOwnedCharPtr( - (char*)(sharedBuf.write(value.mUncompressedSize))); - - if (sharedBuf.error()) { - MOZ_ASSERT(false, "Failed serializing to shared memory."); - return Err(NS_ERROR_UNEXPECTED); - } - - MOZ_TRY(DecompressEntry(value)); - value.mData = nullptr; - } - - if (mem.Finalize(mSharedData).isErr()) { - MOZ_ASSERT(false, "Failed to freeze shared StartupCache data."); - return Err(NS_ERROR_UNEXPECTED); - } - - mSharedData.setPersistent(); - } + cleanup.release(); } MMAP_FAULT_HANDLER_CATCH(Err(NS_ERROR_UNEXPECTED)) - cleanup.release(); - - return Ok(); -} - -Result StartupCache::LoadEntriesFromSharedMemory() { - mLock.AssertCurrentThreadOwns(); - auto size = mCacheData.size(); - auto start = mCacheData.get(); - auto end = start + size; - - Range range(start, end); - loader::InputBuffer buf(range); - - if (sizeof(MAGIC) > buf.remainingCapacity()) { - MOZ_ASSERT(false, "Bad shared StartupCache buffer."); - return Err(NS_ERROR_UNEXPECTED); - } - - const uint8_t* magic = buf.read(sizeof(MAGIC)); - if (memcmp(magic, MAGIC, sizeof(MAGIC)) != 0) { - MOZ_ASSERT(false, "Bad shared StartupCache buffer."); - return Err(NS_ERROR_UNEXPECTED); - } - - uint32_t numEntries = 0; - if (!buf.codeUint32(numEntries) || numEntries > STARTUP_CACHE_MAX_CAPACITY) { - MOZ_ASSERT(false, "Bad number of entries in shared StartupCache buffer."); - return Err(NS_ERROR_UNEXPECTED); - } - - if (!mTable.reserve(STARTUP_CACHE_RESERVE_CAPACITY)) { - return Err(NS_ERROR_UNEXPECTED); - } - - uint32_t entriesSeen = 0; - while (!buf.finished()) { - entriesSeen++; - if (entriesSeen > numEntries) { - MOZ_ASSERT(false, "More entries than expected in StartupCache buffer."); - return Err(NS_ERROR_UNEXPECTED); - } - - nsCString key; - uint32_t uncompressedSize = 0; - buf.codeString(key); - buf.codeUint32(uncompressedSize); - - if (uncompressedSize > buf.remainingCapacity()) { - MOZ_ASSERT(false, - "StartupCache entry larger than remaining buffer size."); - return Err(NS_ERROR_UNEXPECTED); - } - const char* data = - reinterpret_cast(buf.read(uncompressedSize)); - - StartupCacheEntry entry(0, 0, uncompressedSize, - StartupCacheEntryFlags::Shared); - // The const cast is unfortunate here. We have runtime guarantees via memory - // protections that mData will not be modified, but we do not have compile - // time guarantees. - entry.mData = MaybeOwnedCharPtr(const_cast(data)); - - if (!mTable.putNew(key, std::move(entry))) { - return Err(NS_ERROR_UNEXPECTED); - } - } - - return Ok(); -} - -/** - * LoadArchive can only be called from the main thread. - */ -Result StartupCache::LoadArchive() { - mLock.AssertCurrentThreadOwns(); - - if (gIgnoreDiskCache) { - return Err(NS_ERROR_FAILURE); - } - - mLoaded = true; - - if (!mCacheData.initialized()) { - return Err(NS_ERROR_FILE_NOT_FOUND); - } - - if (XRE_IsParentProcess()) { - MOZ_TRY(LoadEntriesOffDisk()); - } else { - MOZ_TRY(LoadEntriesFromSharedMemory()); - } - - return Ok(); -} - -Result StartupCache::DecompressEntry(StartupCacheEntry& aEntry) { - MOZ_ASSERT(XRE_IsParentProcess()); - mLock.AssertCurrentThreadOwns(); - - size_t totalRead = 0; - size_t totalWritten = 0; - Span compressed = MakeSpan( - mCacheData.get().get() + mCacheEntriesBaseOffset + aEntry.mOffset, - aEntry.mCompressedSize); - Span uncompressed = - MakeSpan(aEntry.mData.get(), aEntry.mUncompressedSize); - bool finished = false; - while (!finished) { - auto result = mDecompressionContext->Decompress( - uncompressed.From(totalWritten), compressed.From(totalRead)); - if (NS_WARN_IF(result.isErr())) { - aEntry.mData = nullptr; - InvalidateCacheImpl(); - return Err(NS_ERROR_UNEXPECTED); - } - auto decompressionResult = result.unwrap(); - totalRead += decompressionResult.mSizeRead; - totalWritten += decompressionResult.mSizeWritten; - finished = decompressionResult.mFinished; - } return Ok(); } @@ -778,53 +347,75 @@ Result StartupCache::DecompressEntry(StartupCacheEntry& aEntry) { bool StartupCache::HasEntry(const char* id) { AUTO_PROFILER_LABEL("StartupCache::HasEntry", OTHER); - MutexAutoLock lock(mLock); + MOZ_ASSERT(NS_IsMainThread(), "Startup cache only available on main thread"); + return mTable.has(nsDependentCString(id)); } nsresult StartupCache::GetBuffer(const char* id, const char** outbuf, uint32_t* length) { + AUTO_PROFILER_LABEL("StartupCache::GetBuffer", OTHER); + + NS_ASSERTION(NS_IsMainThread(), + "Startup cache only available on main thread"); + Telemetry::LABELS_STARTUP_CACHE_REQUESTS label = Telemetry::LABELS_STARTUP_CACHE_REQUESTS::Miss; auto telemetry = MakeScopeExit([&label] { Telemetry::AccumulateCategorical(label); }); - MutexAutoLock lock(mLock); - if (!mLoaded) { - return NS_ERROR_NOT_AVAILABLE; - } - decltype(mTable)::Ptr p = mTable.lookup(nsDependentCString(id)); if (!p) { return NS_ERROR_NOT_AVAILABLE; } - // Track that something holds a reference into mTable, so we know to hold - // onto it in case the cache is invalidated. - mCurTableReferenced = true; auto& value = p->value(); if (value.mData) { label = Telemetry::LABELS_STARTUP_CACHE_REQUESTS::HitMemory; - } else if (value.mSharedDataOffset != kStartupcacheEntryNotInSharedData) { - if (!XRE_IsParentProcess() || !mSharedData.initialized()) { - return NS_ERROR_NOT_AVAILABLE; - } - value.mData = MaybeOwnedCharPtr(mSharedData.get().get() + - value.mSharedDataOffset); - label = Telemetry::LABELS_STARTUP_CACHE_REQUESTS::HitMemory; } else { - // We do not decompress entries in child processes: we receive them - // uncompressed in shared memory. - if (!XRE_IsParentProcess() || !mCacheData.initialized()) { + if (!mCacheData.initialized()) { return NS_ERROR_NOT_AVAILABLE; } +#ifdef DEBUG + // It should be impossible for a write to be pending here. This is because + // we just checked mCacheData.initialized(), and this is reset before + // writing to the cache. It's not re-initialized unless we call + // LoadArchive(), either from Init() (which must have already happened) or + // InvalidateCache(). InvalidateCache() locks the mutex, so a write can't be + // happening. Really, we want to MOZ_ASSERT(!mTableLock.IsLocked()) here, + // but there is no such method. So we hack around by attempting to gain the + // lock. This should always succeed; if it fails, someone's broken the + // assumptions. + if (!mTableLock.TryLock()) { + MOZ_ASSERT(false, "Could not gain mTableLock - should never happen!"); + return NS_ERROR_NOT_AVAILABLE; + } + mTableLock.Unlock(); +#endif - value.mData = MaybeOwnedCharPtr(value.mUncompressedSize); - MMAP_FAULT_HANDLER_BEGIN_BUFFER(value.mData.get(), value.mUncompressedSize) - - auto decompressionResult = DecompressEntry(value); - if (decompressionResult.isErr()) { - return decompressionResult.unwrapErr(); + size_t totalRead = 0; + size_t totalWritten = 0; + Span compressed = MakeSpan( + mCacheData.get().get() + mCacheEntriesBaseOffset + value.mOffset, + value.mCompressedSize); + value.mData = MakeUnique(value.mUncompressedSize); + Span uncompressed = + MakeSpan(value.mData.get(), value.mUncompressedSize); + MMAP_FAULT_HANDLER_BEGIN_BUFFER(uncompressed.Elements(), + uncompressed.Length()) + bool finished = false; + while (!finished) { + auto result = mDecompressionContext->Decompress( + uncompressed.From(totalWritten), compressed.From(totalRead)); + if (NS_WARN_IF(result.isErr())) { + value.mData = nullptr; + InvalidateCache(); + return NS_ERROR_FAILURE; + } + auto decompressionResult = result.unwrap(); + totalRead += decompressionResult.mSizeRead; + totalWritten += decompressionResult.mSizeWritten; + finished = decompressionResult.mFinished; } MMAP_FAULT_HANDLER_CATCH(NS_ERROR_FAILURE) @@ -832,80 +423,51 @@ nsresult StartupCache::GetBuffer(const char* id, const char** outbuf, label = Telemetry::LABELS_STARTUP_CACHE_REQUESTS::HitDisk; } - if (value.mRequestedOrder == kStartupCacheEntryNotRequested) { + if (!value.mRequested) { + value.mRequested = true; value.mRequestedOrder = ++mRequestedCount; MOZ_ASSERT(mRequestedCount <= mTable.count(), "Somehow we requested more StartupCache items than exist."); ResetStartupWriteTimerCheckingReadCount(); } + // Track that something holds a reference into mTable, so we know to hold + // onto it in case the cache is invalidated. + mCurTableReferenced = true; *outbuf = value.mData.get(); *length = value.mUncompressedSize; - return NS_OK; } -// Client gives ownership of inbuf. +// Makes a copy of the buffer, client retains ownership of inbuf. nsresult StartupCache::PutBuffer(const char* id, UniquePtr&& inbuf, - uint32_t len, bool isFromChildProcess) { + uint32_t len) { + NS_ASSERTION(NS_IsMainThread(), + "Startup cache only available on main thread"); if (StartupCache::gShutdownInitiated) { return NS_ERROR_NOT_AVAILABLE; } - // We use this to update the RequestedByChild flag. - MOZ_RELEASE_ASSERT( - inbuf || isFromChildProcess, - "Null input to PutBuffer should only be used by child actor."); - - if (!XRE_IsParentProcess() && !mChildActor && mFullyInitialized) { - return NS_ERROR_NOT_AVAILABLE; - } - - MutexAutoLock lock(mLock); - if (!mLoaded) { - return NS_ERROR_NOT_AVAILABLE; - } - bool exists = mTable.has(nsDependentCString(id)); if (exists) { - if (isFromChildProcess) { - decltype(mTable)::Ptr p = mTable.lookup(nsDependentCString(id)); - auto& value = p->value(); - value.mFlags += StartupCacheEntryFlags::RequestedByChild; - if (value.mRequestedOrder == kStartupCacheEntryNotRequested) { - value.mRequestedOrder = ++mRequestedCount; - MOZ_ASSERT(mRequestedCount <= mTable.count(), - "Somehow we requested more StartupCache items than exist."); - ResetStartupWriteTimerCheckingReadCount(); - } - } else { - NS_WARNING("Existing entry in StartupCache."); - } - + NS_WARNING("Existing entry in StartupCache."); // Double-caching is undesirable but not an error. return NS_OK; } - - if (!inbuf) { - MOZ_ASSERT(false, - "Should only PutBuffer with null buffer for existing entries."); - return NS_ERROR_UNEXPECTED; - } - - EnumSet flags = - StartupCacheEntryFlags::AddedThisSession; - if (isFromChildProcess) { - flags += StartupCacheEntryFlags::RequestedByChild; + // Try to gain the table write lock. If the background task to write the + // cache is running, this will fail. + if (!mTableLock.TryLock()) { + return NS_ERROR_NOT_AVAILABLE; } + auto lockGuard = MakeScopeExit([&] { mTableLock.Unlock(); }); // putNew returns false on alloc failure - in the very unlikely event we hit // that and aren't going to crash elsewhere, there's no reason we need to // crash here. - if (mTable.putNew( - nsCString(id), - StartupCacheEntry(std::move(inbuf), len, ++mRequestedCount, flags))) { - return ResetStartupWriteTimerImpl(); + if (mTable.putNew(nsCString(id), StartupCacheEntry(std::move(inbuf), len, + ++mRequestedCount))) { + return ResetStartupWriteTimer(); } MOZ_DIAGNOSTIC_ASSERT(mTable.count() < STARTUP_CACHE_MAX_CAPACITY, "Too many StartupCache entries."); @@ -936,8 +498,7 @@ size_t StartupCache::HeapSizeOfIncludingThis( * happening on another thread */ Result StartupCache::WriteToDisk() { - MOZ_ASSERT(XRE_IsParentProcess()); - mLock.AssertCurrentThreadOwns(); + mTableLock.AssertCurrentThreadOwns(); if (!mDirty || mWrittenOnce) { return Ok(); @@ -947,155 +508,104 @@ Result StartupCache::WriteToDisk() { return Err(NS_ERROR_UNEXPECTED); } - nsCOMPtr tmpFile; - nsresult rv = mFile->Clone(getter_AddRefs(tmpFile)); - if (NS_FAILED(rv)) { - return Err(NS_ERROR_UNEXPECTED); - } + AutoFDClose fd; + MOZ_TRY(mFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0644, &fd.rwget())); - nsAutoCString leafName; - mFile->GetNativeLeafName(leafName); - tmpFile->SetNativeLeafName(leafName + "-tmp"_ns); - - { - AutoFDClose fd; - MOZ_TRY(tmpFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, - 0644, &fd.rwget())); - - nsTArray> entries; - - for (auto iter = mTable.iter(); !iter.done(); iter.next()) { + nsTArray> entries; + for (auto iter = mTable.iter(); !iter.done(); iter.next()) { + if (iter.get().value().mRequested) { entries.AppendElement( std::make_pair(&iter.get().key(), &iter.get().value())); } - - if (entries.IsEmpty()) { - return Ok(); - } - - entries.Sort(StartupCacheEntry::Comparator()); - loader::OutputBuffer buf; - for (auto& e : entries) { - const auto& key = e.first; - auto* value = e.second; - auto uncompressedSize = value->mUncompressedSize; - uint8_t sharedToChild = - value->mFlags.contains(StartupCacheEntryFlags::RequestedByChild); - // Set the mHeaderOffsetInFile so we can go back and edit the offset. - value->mHeaderOffsetInFile = buf.cursor(); - // Write a 0 offset/compressed size as a placeholder until we get the real - // offset after compressing. - buf.codeUint32(0); - buf.codeUint32(0); - buf.codeUint32(uncompressedSize); - buf.codeUint8(sharedToChild); - buf.codeString(*key); - } - - uint8_t headerSize[4]; - LittleEndian::writeUint32(headerSize, buf.cursor()); - - MOZ_TRY(Write(fd, MAGIC, sizeof(MAGIC))); - MOZ_TRY(Write(fd, headerSize, sizeof(headerSize))); - size_t prefetchSizeOffset = sizeof(MAGIC) + sizeof(headerSize); - size_t headerStart = prefetchSizeOffset + sizeof(uint32_t); - size_t dataStart = headerStart + buf.cursor(); - MOZ_TRY(Seek(fd, dataStart)); - - size_t offset = 0; - size_t prefetchSize = 0; - - const size_t chunkSize = 1024 * 16; - LZ4FrameCompressionContext ctx(6, /* aCompressionLevel */ - chunkSize, /* aReadBufLen */ - true, /* aChecksum */ - true); /* aStableSrc */ - size_t writeBufLen = ctx.GetRequiredWriteBufferLength(); - auto writeBuffer = MaybeOwnedCharPtr(writeBufLen); - auto writeSpan = MakeSpan(writeBuffer.get(), writeBufLen); - - for (auto& e : entries) { - auto* value = e.second; - - // If this is the first entry which was not requested, set the prefetch - // size to the offset before we include this item. We will then prefetch - // all items up to but not including this one during our next startup. - if (value->mRequestedOrder == kStartupCacheEntryNotRequested && - prefetchSize == 0) { - prefetchSize = dataStart + offset; - } - - // Reuse the existing compressed entry if possible - if (mCacheData.initialized() && value->mCompressedSize) { - Span compressed = - MakeSpan(mCacheData.get().get() + mCacheEntriesBaseOffset + - value->mOffset, - value->mCompressedSize); - MOZ_TRY(Write(fd, compressed.Elements(), compressed.Length())); - value->mOffset = offset; - offset += compressed.Length(); - } else { - value->mOffset = offset; - Span result; - MOZ_TRY_VAR(result, ctx.BeginCompressing(writeSpan).mapErr( - MapLZ4ErrorToNsresult)); - MOZ_TRY(Write(fd, result.Elements(), result.Length())); - offset += result.Length(); - - for (size_t i = 0; i < value->mUncompressedSize; i += chunkSize) { - size_t size = std::min(chunkSize, value->mUncompressedSize - i); - char* uncompressed = value->mData.get() + i; - MOZ_TRY_VAR(result, - ctx.ContinueCompressing(MakeSpan(uncompressed, size)) - .mapErr(MapLZ4ErrorToNsresult)); - MOZ_TRY(Write(fd, result.Elements(), result.Length())); - offset += result.Length(); - } - - MOZ_TRY_VAR(result, ctx.EndCompressing().mapErr(MapLZ4ErrorToNsresult)); - MOZ_TRY(Write(fd, result.Elements(), result.Length())); - offset += result.Length(); - value->mCompressedSize = offset - value->mOffset; - } - } - - if (prefetchSize == 0) { - prefetchSize = dataStart + offset; - } - - for (auto& e : entries) { - auto* value = e.second; - uint8_t* headerEntry = buf.Get() + value->mHeaderOffsetInFile; - LittleEndian::writeUint32(headerEntry, value->mOffset); - LittleEndian::writeUint32(headerEntry + sizeof(value->mOffset), - value->mCompressedSize); - } - - uint8_t prefetchSizeBuf[4]; - LittleEndian::writeUint32(prefetchSizeBuf, prefetchSize); - - MOZ_TRY(Seek(fd, prefetchSizeOffset)); - MOZ_TRY(Write(fd, prefetchSizeBuf, sizeof(prefetchSizeBuf))); - MOZ_TRY(Write(fd, buf.Get(), buf.cursor())); } + if (entries.IsEmpty()) { + return Ok(); + } + + entries.Sort(StartupCacheEntry::Comparator()); + loader::OutputBuffer buf; + for (auto& e : entries) { + auto key = e.first; + auto value = e.second; + auto uncompressedSize = value->mUncompressedSize; + // Set the mHeaderOffsetInFile so we can go back and edit the offset. + value->mHeaderOffsetInFile = buf.cursor(); + // Write a 0 offset/compressed size as a placeholder until we get the real + // offset after compressing. + buf.codeUint32(0); + buf.codeUint32(0); + buf.codeUint32(uncompressedSize); + buf.codeString(*key); + } + + uint8_t headerSize[4]; + LittleEndian::writeUint32(headerSize, buf.cursor()); + + MOZ_TRY(Write(fd, MAGIC, sizeof(MAGIC))); + MOZ_TRY(Write(fd, headerSize, sizeof(headerSize))); + size_t headerStart = sizeof(MAGIC) + sizeof(headerSize); + size_t dataStart = headerStart + buf.cursor(); + MOZ_TRY(Seek(fd, dataStart)); + + size_t offset = 0; + + const size_t chunkSize = 1024 * 16; + LZ4FrameCompressionContext ctx(6, /* aCompressionLevel */ + chunkSize, /* aReadBufLen */ + true, /* aChecksum */ + true); /* aStableSrc */ + size_t writeBufLen = ctx.GetRequiredWriteBufferLength(); + auto writeBuffer = MakeUnique(writeBufLen); + auto writeSpan = MakeSpan(writeBuffer.get(), writeBufLen); + + for (auto& e : entries) { + auto value = e.second; + value->mOffset = offset; + Span result; + MOZ_TRY_VAR(result, + ctx.BeginCompressing(writeSpan).mapErr(MapLZ4ErrorToNsresult)); + MOZ_TRY(Write(fd, result.Elements(), result.Length())); + offset += result.Length(); + + for (size_t i = 0; i < value->mUncompressedSize; i += chunkSize) { + size_t size = std::min(chunkSize, value->mUncompressedSize - i); + char* uncompressed = value->mData.get() + i; + MOZ_TRY_VAR(result, ctx.ContinueCompressing(MakeSpan(uncompressed, size)) + .mapErr(MapLZ4ErrorToNsresult)); + MOZ_TRY(Write(fd, result.Elements(), result.Length())); + offset += result.Length(); + } + + MOZ_TRY_VAR(result, ctx.EndCompressing().mapErr(MapLZ4ErrorToNsresult)); + MOZ_TRY(Write(fd, result.Elements(), result.Length())); + offset += result.Length(); + value->mCompressedSize = offset - value->mOffset; + MOZ_TRY(Seek(fd, dataStart + offset)); + } + + for (auto& e : entries) { + auto value = e.second; + uint8_t* headerEntry = buf.Get() + value->mHeaderOffsetInFile; + LittleEndian::writeUint32(headerEntry, value->mOffset); + LittleEndian::writeUint32(headerEntry + sizeof(value->mOffset), + value->mCompressedSize); + } + MOZ_TRY(Seek(fd, headerStart)); + MOZ_TRY(Write(fd, buf.Get(), buf.cursor())); + mDirty = false; mWrittenOnce = true; - mCacheData.reset(); - tmpFile->MoveToNative(nullptr, leafName); return Ok(); } -void StartupCache::InvalidateCache() { - MutexAutoLock lock(mLock); - InvalidateCacheImpl(); -} - -void StartupCache::InvalidateCacheImpl(bool memoryOnly) { - mLock.AssertCurrentThreadOwns(); - +void StartupCache::InvalidateCache(bool memoryOnly) { WaitOnPrefetchThread(); + // Ensure we're not writing using mTable... + MutexAutoLock unlock(mTableLock); + mWrittenOnce = false; if (memoryOnly) { // This should only be called in tests. @@ -1105,11 +615,9 @@ void StartupCache::InvalidateCacheImpl(bool memoryOnly) { return; } } - if (mCurTableReferenced) { - // There should be no way for this assert to fail other than a user - // manually sending startupcache-invalidate messages through the Browser - // Toolbox. + // There should be no way for this assert to fail other than a user manually + // sending startupcache-invalidate messages through the Browser Toolbox. MOZ_DIAGNOSTIC_ASSERT(xpc::IsInAutomation() || mOldTables.Length() < 10, "Startup cache invalidated too many times."); mOldTables.AppendElement(std::move(mTable)); @@ -1117,16 +625,7 @@ void StartupCache::InvalidateCacheImpl(bool memoryOnly) { } else { mTable.clear(); } - - if (!XRE_IsParentProcess()) { - return; - } mRequestedCount = 0; - if (!XRE_IsParentProcess()) { - gIgnoreDiskCache = true; - return; - } - if (!memoryOnly) { mCacheData.reset(); nsresult rv = mFile->Remove(false); @@ -1137,7 +636,6 @@ void StartupCache::InvalidateCacheImpl(bool memoryOnly) { } } gIgnoreDiskCache = false; - Unused << mCacheData.init(mFile); auto result = LoadArchive(); if (NS_WARN_IF(result.isErr())) { gIgnoreDiskCache = true; @@ -1145,12 +643,8 @@ void StartupCache::InvalidateCacheImpl(bool memoryOnly) { } void StartupCache::MaybeInitShutdownWrite() { - if (!XRE_IsParentProcess()) { - return; - } - MutexAutoLock lock(mLock); - if (mWriteTimer) { - mWriteTimer->Cancel(); + if (mTimer) { + mTimer->Cancel(); } gShutdownInitiated = true; @@ -1158,28 +652,23 @@ void StartupCache::MaybeInitShutdownWrite() { } void StartupCache::EnsureShutdownWriteComplete() { - if (!XRE_IsParentProcess()) { + // If we've already written or there's nothing to write, + // we don't need to do anything. This is the common case. + if (mWrittenOnce || (mCacheData.initialized() && !ShouldCompactCache())) { return; } // Otherwise, ensure the write happens. The timer should have been cancelled // already in MaybeInitShutdownWrite. - if (!mLock.TryLock()) { + if (!mTableLock.TryLock()) { // Uh oh, we're writing away from the main thread. Wait to gain the lock, // to ensure the write completes. - mLock.Lock(); + mTableLock.Lock(); } else { // We got the lock. Keep the following in sync with // MaybeWriteOffMainThread: - - // If we've already written or there's nothing to write, - // we don't need to do anything. This is the common case. - if (mWrittenOnce || (mCacheData.initialized() && !ShouldCompactCache())) { - mLock.Unlock(); - return; - } - WaitOnPrefetchThread(); mDirty = true; + mCacheData.reset(); // Most of this should be redundant given MaybeWriteOffMainThread should // have run before now. @@ -1189,14 +678,12 @@ void StartupCache::EnsureShutdownWriteComplete() { // when done, and checks for them when starting, so we don't need to do // anything else. } - mLock.Unlock(); + mTableLock.Unlock(); } void StartupCache::IgnoreDiskCache() { gIgnoreDiskCache = true; - if (gStartupCache) { - gStartupCache->InvalidateCache(); - } + if (gStartupCache) gStartupCache->InvalidateCache(); } void StartupCache::WaitOnPrefetchThread() { @@ -1212,7 +699,7 @@ void StartupCache::ThreadedPrefetch(void* aClosure) { mozilla::IOInterposer::RegisterCurrentThread(); StartupCache* startupCacheObj = static_cast(aClosure); uint8_t* buf = startupCacheObj->mCacheData.get().get(); - size_t size = startupCacheObj->mPrefetchSize; + size_t size = startupCacheObj->mCacheData.size(); MMAP_FAULT_HANDLER_BEGIN_BUFFER(buf, size) PrefetchMemory(buf, size); MMAP_FAULT_HANDLER_CATCH() @@ -1220,7 +707,6 @@ void StartupCache::ThreadedPrefetch(void* aClosure) { } bool StartupCache::ShouldCompactCache() { - mLock.AssertCurrentThreadOwns(); // If we've requested less than 4/5 of the startup cache, then we should // probably compact it down. This can happen quite easily after the first run, // which seems to request quite a few more things than subsequent runs. @@ -1242,25 +728,13 @@ void StartupCache::WriteTimeout(nsITimer* aTimer, void* aClosure) { * if the StartupCache object is valid. */ StartupCache* startupCacheObj = static_cast(aClosure); - MutexAutoLock lock(startupCacheObj->mLock); startupCacheObj->MaybeWriteOffMainThread(); } -void StartupCache::SendEntriesTimeout(nsITimer* aTimer, void* aClosure) { - StartupCache* sc = static_cast(aClosure); - MutexAutoLock lock(sc->mLock); - ((StartupCacheChild*)sc->mChildActor)->SendEntriesAndFinalize(sc->mTable); -} - /* * See StartupCache::WriteTimeout above - this is just the non-static body. */ void StartupCache::MaybeWriteOffMainThread() { - mLock.AssertCurrentThreadOwns(); - if (!XRE_IsParentProcess()) { - return; - } - if (mWrittenOnce) { return; } @@ -1272,11 +746,12 @@ void StartupCache::MaybeWriteOffMainThread() { // Keep this code in sync with EnsureShutdownWriteComplete. WaitOnPrefetchThread(); mDirty = true; + mCacheData.reset(); RefPtr self = this; nsCOMPtr runnable = NS_NewRunnableFunction("StartupCache::Write", [self]() mutable { - MutexAutoLock lock(self->mLock); + MutexAutoLock unlock(self->mTableLock); auto result = self->WriteToDisk(); Unused << NS_WARN_IF(result.isErr()); }); @@ -1302,21 +777,7 @@ nsresult StartupCacheListener::Observe(nsISupports* subject, const char* topic, // EnsureShutdownWriteComplete() to ensure any pending writes happen // in that case. } else if (strcmp(topic, "startupcache-invalidate") == 0) { - MutexAutoLock lock(sc->mLock); - sc->InvalidateCacheImpl(data && nsCRT::strcmp(data, u"memoryOnly") == 0); - } else if (sc->mContentStartupFinishedTopic.Equals(topic) && - sc->mChildActor) { - if (sProcessType == ProcessType::PrivilegedAbout) { - if (!sc->mSendEntriesTimer) { - sc->mSendEntriesTimer = NS_NewTimer(); - sc->mSendEntriesTimer->InitWithNamedFuncCallback( - StartupCache::SendEntriesTimeout, sc, 10000, - nsITimer::TYPE_ONE_SHOT, "StartupCache::SendEntriesTimeout"); - } - } else { - MutexAutoLock lock(sc->mLock); - ((StartupCacheChild*)sc->mChildActor)->SendEntriesAndFinalize(sc->mTable); - } + sc->InvalidateCache(data && nsCRT::strcmp(data, u"memoryOnly") == 0); } return NS_OK; } @@ -1335,49 +796,39 @@ nsresult StartupCache::GetDebugObjectOutputStream( } nsresult StartupCache::ResetStartupWriteTimerCheckingReadCount() { - mLock.AssertCurrentThreadOwns(); nsresult rv = NS_OK; - if (!mWriteTimer) { - mWriteTimer = NS_NewTimer(); - } else { - rv = mWriteTimer->Cancel(); - } + if (!mTimer) + mTimer = NS_NewTimer(); + else + rv = mTimer->Cancel(); NS_ENSURE_SUCCESS(rv, rv); // Wait for the specified timeout, then write out the cache. - mWriteTimer->InitWithNamedFuncCallback( + mTimer->InitWithNamedFuncCallback( StartupCache::WriteTimeout, this, STARTUP_CACHE_WRITE_TIMEOUT * 1000, nsITimer::TYPE_ONE_SHOT, "StartupCache::WriteTimeout"); return NS_OK; } nsresult StartupCache::ResetStartupWriteTimer() { - MutexAutoLock lock(mLock); - return ResetStartupWriteTimerImpl(); -} - -nsresult StartupCache::ResetStartupWriteTimerImpl() { - if (!XRE_IsParentProcess()) { - return NS_OK; - } - - mLock.AssertCurrentThreadOwns(); mDirty = true; nsresult rv = NS_OK; - if (!mWriteTimer) { - mWriteTimer = NS_NewTimer(); - } else { - rv = mWriteTimer->Cancel(); - } + if (!mTimer) + mTimer = NS_NewTimer(); + else + rv = mTimer->Cancel(); NS_ENSURE_SUCCESS(rv, rv); // Wait for the specified timeout, then write out the cache. - mWriteTimer->InitWithNamedFuncCallback( + mTimer->InitWithNamedFuncCallback( StartupCache::WriteTimeout, this, STARTUP_CACHE_WRITE_TIMEOUT * 1000, nsITimer::TYPE_ONE_SHOT, "StartupCache::WriteTimeout"); return NS_OK; } // Used only in tests: -bool StartupCache::StartupWriteComplete() { return !mDirty && mWrittenOnce; } +bool StartupCache::StartupWriteComplete() { + // Need to have written to disk and not added new things since; + return !mDirty && mWrittenOnce; +} // StartupCacheDebugOutputStream implementation #ifdef DEBUG diff --git a/startupcache/StartupCache.h b/startupcache/StartupCache.h index 3bc497bc392e..682894fd10a3 100644 --- a/startupcache/StartupCache.h +++ b/startupcache/StartupCache.h @@ -22,13 +22,10 @@ #include "mozilla/Attributes.h" #include "mozilla/AutoMemMap.h" #include "mozilla/Compression.h" -#include "mozilla/EnumSet.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Mutex.h" -#include "mozilla/Omnijar.h" #include "mozilla/Result.h" #include "mozilla/UniquePtr.h" -#include "mozilla/UniquePtrExtensions.h" /** * The StartupCache is a persistent cache of simple key-value pairs, @@ -81,153 +78,47 @@ */ namespace mozilla { -namespace dom { -class ContentParent; -} -namespace ipc { -class GeckoChildProcessHost; -} // namespace ipc namespace scache { -class StartupCacheChild; - -#ifdef XP_UNIX - -// Please see bug 1440207 about improving the problem of random fixed FDs, -// which the addition of the below constant exacerbates. -static const int kStartupCacheFd = 11; -#endif - -// We use INT_MAX here just to simplify the sorting - we want to push -// unrequested entries to the back, and have requested entries in the order -// they came in. -static const int kStartupCacheEntryNotRequested = INT_MAX; -static const int kStartupcacheEntryNotInSharedData = -1; - -// StartupCache entries can be backed by a buffer which they allocate as -// soon as they are requested, into which they decompress the contents out -// of the memory mapped file, *or* they can be backed by a contiguous buffer -// which we allocate up front and decompress into, in order to share it with -// child processes. This class is a helper class to hold a buffer which the -// entry itself may or may not own. -// -// Side note: it may be appropriate for StartupCache entries to never own -// their underlying buffers. We explicitly work to ensure that anything the -// StartupCache returns to a caller survives for the lifetime of the -// application, so it may be preferable to have a set of large contiguous -// buffers which we allocate on demand, and fill up with cache entry contents, -// but at that point we're basically implementing our own hacky pseudo-malloc, -// for relatively uncertain performance gains. For the time being, we just -// keep the existing model unchanged. -class MaybeOwnedCharPtr { - public: - char* mPtr; - bool mOwned; - - ~MaybeOwnedCharPtr() { - if (mOwned) { - delete[] mPtr; - } - } - - MaybeOwnedCharPtr(const MaybeOwnedCharPtr& other); - MaybeOwnedCharPtr& operator=(const MaybeOwnedCharPtr& other); - - MaybeOwnedCharPtr(MaybeOwnedCharPtr&& other) - : mPtr(std::exchange(other.mPtr, nullptr)), - mOwned(std::exchange(other.mOwned, false)) {} - - MaybeOwnedCharPtr& operator=(MaybeOwnedCharPtr&& other) { - std::swap(mPtr, other.mPtr); - std::swap(mOwned, other.mOwned); - return *this; - } - - MaybeOwnedCharPtr& operator=(decltype(nullptr)) { - mPtr = nullptr; - mOwned = false; - return *this; - } - - explicit operator bool() const { return !!mPtr; } - - char* get() { return mPtr; } - - explicit MaybeOwnedCharPtr(char* aBytes) : mPtr(aBytes), mOwned(false) {} - - explicit MaybeOwnedCharPtr(UniquePtr&& aBytes) - : mPtr(aBytes.release()), mOwned(true) {} - - explicit MaybeOwnedCharPtr(size_t size) - : mPtr(new char[size]), mOwned(true) {} -}; - -enum class StartupCacheEntryFlags { - Shared, - RequestedByChild, - AddedThisSession, -}; - struct StartupCacheEntry { - MaybeOwnedCharPtr mData; + UniquePtr mData; uint32_t mOffset; uint32_t mCompressedSize; uint32_t mUncompressedSize; - int32_t mSharedDataOffset; int32_t mHeaderOffsetInFile; int32_t mRequestedOrder; - EnumSet mFlags; + bool mRequested; MOZ_IMPLICIT StartupCacheEntry(uint32_t aOffset, uint32_t aCompressedSize, - uint32_t aUncompressedSize, - EnumSet aFlags) + uint32_t aUncompressedSize) : mData(nullptr), mOffset(aOffset), mCompressedSize(aCompressedSize), mUncompressedSize(aUncompressedSize), - mSharedDataOffset(kStartupcacheEntryNotInSharedData), mHeaderOffsetInFile(0), - mRequestedOrder(kStartupCacheEntryNotRequested), - mFlags(aFlags) {} + mRequestedOrder(0), + mRequested(false) {} StartupCacheEntry(UniquePtr aData, size_t aLength, - int32_t aRequestedOrder, - EnumSet aFlags) + int32_t aRequestedOrder) : mData(std::move(aData)), mOffset(0), mCompressedSize(0), mUncompressedSize(aLength), - mSharedDataOffset(kStartupcacheEntryNotInSharedData), mHeaderOffsetInFile(0), - mRequestedOrder(aRequestedOrder), - mFlags(aFlags) {} + mRequestedOrder(0), + mRequested(true) {} struct Comparator { using Value = std::pair; bool Equals(const Value& a, const Value& b) const { - // This is a bit ugly. Here and below, just note that we want entries - // with the RequestedByChild flag to be sorted before any other entries, - // because we're going to want to decompress them and send them down to - // child processes pretty early during startup. - return a.second->mFlags.contains( - StartupCacheEntryFlags::RequestedByChild) == - b.second->mFlags.contains( - StartupCacheEntryFlags::RequestedByChild) && - a.second->mRequestedOrder == b.second->mRequestedOrder; + return a.second->mRequestedOrder == b.second->mRequestedOrder; } bool LessThan(const Value& a, const Value& b) const { - bool requestedByChildA = - a.second->mFlags.contains(StartupCacheEntryFlags::RequestedByChild); - bool requestedByChildB = - b.second->mFlags.contains(StartupCacheEntryFlags::RequestedByChild); - if (requestedByChildA == requestedByChildB) { - return a.second->mRequestedOrder < b.second->mRequestedOrder; - } else { - return requestedByChildA; - } + return a.second->mRequestedOrder < b.second->mRequestedOrder; } }; }; @@ -240,26 +131,10 @@ class StartupCacheListener final : public nsIObserver { NS_DECL_NSIOBSERVER }; -// This mirrors a bit of logic in the script preloader. Basically, there's -// certainly some overhead in child processes sending us lists of requested -// startup cache items, so we want to limit that. Accordingly, we only -// request to be notified of requested cache items for the first occurrence -// of each process type, enumerated below. -enum class ProcessType : uint8_t { - Uninitialized, - Parent, - Web, - Extension, - PrivilegedAbout, -}; - class StartupCache : public nsIMemoryReporter { friend class StartupCacheListener; - friend class StartupCacheChild; public: - using Table = HashMap; - NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIMEMORYREPORTER @@ -272,10 +147,11 @@ class StartupCache : public nsIMemoryReporter { nsresult GetBuffer(const char* id, const char** outbuf, uint32_t* length); // Stores a buffer. Caller yields ownership. - nsresult PutBuffer(const char* id, UniquePtr&& inbuf, uint32_t length, - bool isFromChildProcess = false); + nsresult PutBuffer(const char* id, UniquePtr&& inbuf, + uint32_t length); - void InvalidateCache(); + // Removes the cache file. + void InvalidateCache(bool memoryOnly = false); // For use during shutdown - this will write the startupcache's data // to disk if the timer hasn't already gone off. @@ -293,35 +169,16 @@ class StartupCache : public nsIMemoryReporter { nsresult GetDebugObjectOutputStream(nsIObjectOutputStream* aStream, nsIObjectOutputStream** outStream); - static ProcessType GetChildProcessType(const nsAString& remoteType); + static StartupCache* GetSingletonNoInit(); static StartupCache* GetSingleton(); - - // This will get the StartupCache up and running to get cached entries, but - // it won't init some of the deferred things which require later services - // to be up and running. - static nsresult PartialInitSingleton(nsIFile* aProfileLocalDir); - - // If the startup cache singleton exists (initialized via - // PartialInitSingleton), this will ensure that all of the ancillary - // requirements of the startup cache are met. - static nsresult FullyInitSingleton(); - - static nsresult InitChildSingleton(char* aScacheHandleStr, - char* aScacheSizeStr); - static void DeleteSingleton(); - static void InitContentChild(dom::ContentParent& parent); - - void AddStartupCacheCmdLineArgs(ipc::GeckoChildProcessHost& procHost, - std::vector& aExtraOpts); - nsresult ParseStartupCacheCmdLineArgs(char* aScacheHandleStr, - char* aScacheSizeStr); // This measures all the heap memory used by the StartupCache, i.e. it // excludes the mapping. size_t HeapSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; bool ShouldCompactCache(); + nsresult ResetStartupWriteTimerCheckingReadCount(); nsresult ResetStartupWriteTimer(); bool StartupWriteComplete(); @@ -332,15 +189,7 @@ class StartupCache : public nsIMemoryReporter { friend class StartupCacheInfo; Result LoadArchive(); - nsresult PartialInit(nsIFile* aProfileLocalDir); - nsresult FullyInit(); - nsresult InitChild(StartupCacheChild* cacheChild); - - // Removes the cache file. - void InvalidateCacheImpl(bool memoryOnly = false); - - nsresult ResetStartupWriteTimerCheckingReadCount(); - nsresult ResetStartupWriteTimerImpl(); + nsresult Init(); // Returns a file pointer for the cache file with the given name in the // current profile. @@ -352,69 +201,37 @@ class StartupCache : public nsIMemoryReporter { // Writes the cache to disk Result WriteToDisk(); - Result DecompressEntry(StartupCacheEntry& aEntry); - - Result LoadEntriesOffDisk(); - - Result LoadEntriesFromSharedMemory(); - void WaitOnPrefetchThread(); void StartPrefetchMemoryThread(); + static nsresult InitSingleton(); static void WriteTimeout(nsITimer* aTimer, void* aClosure); - static void SendEntriesTimeout(nsITimer* aTimer, void* aClosure); void MaybeWriteOffMainThread(); static void ThreadedPrefetch(void* aClosure); - EnumSet mInitializedProcesses{}; - nsCString mContentStartupFinishedTopic; - - Table mTable; + HashMap mTable; // owns references to the contents of tables which have been invalidated. // In theory grows forever if the cache is continually filled and then // invalidated, but this should not happen in practice. nsTArray mOldTables; nsCOMPtr mFile; loader::AutoMemMap mCacheData; - loader::AutoMemMap mSharedData; - UniqueFileHandle mSharedDataHandle; - - // This lock must protect a few members of the StartupCache. Essentially, - // we want to protect everything accessed by GetBuffer and PutBuffer. This - // includes: - // - mTable - // - mCacheData - // - mDecompressionContext - // - mCurTableReferenced - // - mOldTables - // - mWrittenOnce - // - gIgnoreDiskCache - // - mFile - // - mWriteTimer - // - mStartupWriteInitiated - mutable Mutex mLock; + Mutex mTableLock; nsCOMPtr mObserverService; RefPtr mListener; - nsCOMPtr mWriteTimer; - nsCOMPtr mSendEntriesTimer; + nsCOMPtr mTimer; Atomic mDirty; Atomic mWrittenOnce; bool mCurTableReferenced; - bool mLoaded; - bool mFullyInitialized; uint32_t mRequestedCount; - uint32_t mPrefetchSize; - uint32_t mSharedDataSize; size_t mCacheEntriesBaseOffset; static StaticRefPtr gStartupCache; static bool gShutdownInitiated; static bool gIgnoreDiskCache; static bool gFoundDiskCacheOnInit; - - Atomic mChildActor; PRThread* mPrefetchThread; UniquePtr mDecompressionContext; #ifdef DEBUG diff --git a/startupcache/StartupCacheChild.cpp b/startupcache/StartupCacheChild.cpp deleted file mode 100644 index 3fabc8dddd4e..000000000000 --- a/startupcache/StartupCacheChild.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/scache/StartupCacheChild.h" - -#include "mozilla/scache/StartupCache.h" -#include "mozilla/dom/ContentParent.h" - -namespace mozilla { -namespace scache { - -void StartupCacheChild::Init(bool wantCacheData) { - mWantCacheData = wantCacheData; - - auto* cache = StartupCache::GetSingleton(); - if (cache) { - Unused << cache->InitChild(wantCacheData ? this : nullptr); - } - - if (!wantCacheData) { - // If the parent process isn't expecting any cache data from us, we're - // done. - Send__delete__(this, AutoTArray()); - } -} - -void StartupCacheChild::SendEntriesAndFinalize(StartupCache::Table& entries) { - MOZ_RELEASE_ASSERT(mWantCacheData); - nsTArray dataArray; - for (auto iter = entries.iter(); !iter.done(); iter.next()) { - const auto& key = iter.get().key(); - auto& value = iter.get().value(); - - if (!value.mData || - value.mRequestedOrder == kStartupCacheEntryNotRequested) { - continue; - } - - auto data = dataArray.AppendElement(); - - data->key() = key; - if (value.mFlags.contains(StartupCacheEntryFlags::AddedThisSession)) { - data->data().AppendElements( - reinterpret_cast(value.mData.get()), - value.mUncompressedSize); - } - } - - mWantCacheData = false; - Send__delete__(this, dataArray); -} - -void StartupCacheChild::ActorDestroy(ActorDestroyReason aWhy) { - auto* cache = StartupCache::GetSingleton(); - if (cache) { - cache->mChildActor = nullptr; - } -} - -} // namespace scache -} // namespace mozilla \ No newline at end of file diff --git a/startupcache/StartupCacheChild.h b/startupcache/StartupCacheChild.h deleted file mode 100644 index 49747b8dc499..000000000000 --- a/startupcache/StartupCacheChild.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef StartupCacheChild_h -#define StartupCacheChild_h - -#include "mozilla/scache/StartupCache.h" -#include "mozilla/scache/PStartupCacheChild.h" -#include "mozilla/scache/PStartupCacheParent.h" - -namespace mozilla { -namespace ipc { -class FileDescriptor; -} - -namespace scache { - -using mozilla::ipc::FileDescriptor; - -class StartupCacheChild final : public PStartupCacheChild { - friend class mozilla::scache::StartupCache; - friend class mozilla::scache::StartupCacheListener; - - public: - StartupCacheChild() = default; - - void Init(bool wantCacheData); - - protected: - virtual void ActorDestroy(ActorDestroyReason aWhy) override; - - void SendEntriesAndFinalize(StartupCache::Table& entries); - - private: - bool mWantCacheData = false; -}; - -} // namespace scache -} // namespace mozilla - -#endif // StartupCacheChild_h diff --git a/startupcache/StartupCacheParent.cpp b/startupcache/StartupCacheParent.cpp deleted file mode 100644 index fa7634ce5cf9..000000000000 --- a/startupcache/StartupCacheParent.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/scache/StartupCacheParent.h" - -#include "mozilla/scache/StartupCache.h" -#include "mozilla/dom/ContentParent.h" - -namespace mozilla { -namespace scache { - -IPCResult StartupCacheParent::Recv__delete__(nsTArray&& entries) { - if (!mWantCacheData && entries.Length()) { - return IPC_FAIL(this, "UnexpectedScriptData"); - } - - mWantCacheData = false; - - if (entries.Length()) { - auto* cache = StartupCache::GetSingleton(); - for (auto& entry : entries) { - auto buffer = MakeUnique(entry.data().Length()); - memcpy(buffer.get(), entry.data().Elements(), entry.data().Length()); - cache->PutBuffer(entry.key().get(), std::move(buffer), - entry.data().Length(), /* isFromChildProcess:*/ true); - } - } - - return IPC_OK(); -} - -void StartupCacheParent::ActorDestroy(ActorDestroyReason aWhy) {} - -} // namespace scache -} // namespace mozilla \ No newline at end of file diff --git a/startupcache/StartupCacheParent.h b/startupcache/StartupCacheParent.h deleted file mode 100644 index d7813454e7ae..000000000000 --- a/startupcache/StartupCacheParent.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef StartupCacheParent_h -#define StartupCacheParent_h - -#include "mozilla/scache/StartupCache.h" -#include "mozilla/scache/PStartupCacheParent.h" - -namespace mozilla { - -namespace scache { - -using mozilla::ipc::IPCResult; - -class StartupCacheParent final : public PStartupCacheParent { - friend class PStartupCacheParent; - - public: - explicit StartupCacheParent(bool wantCacheData) - : mWantCacheData(wantCacheData) {} - - protected: - IPCResult Recv__delete__(nsTArray&& entries); - - virtual void ActorDestroy(ActorDestroyReason aWhy) override; - - private: - bool mWantCacheData; -}; - -} // namespace scache -} // namespace mozilla - -#endif // StartupCacheParent_h diff --git a/startupcache/moz.build b/startupcache/moz.build index 09a810a72f54..7cf14b18cc40 100644 --- a/startupcache/moz.build +++ b/startupcache/moz.build @@ -12,16 +12,12 @@ BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini'] EXPORTS.mozilla.scache += [ 'StartupCache.h', - 'StartupCacheChild.h', - 'StartupCacheParent.h', 'StartupCacheUtils.h', ] UNIFIED_SOURCES += [ 'StartupCache.cpp', - 'StartupCacheChild.cpp', 'StartupCacheInfo.cpp', - 'StartupCacheParent.cpp', 'StartupCacheUtils.cpp', ] @@ -35,10 +31,4 @@ XPIDL_SOURCES += [ 'nsIStartupCacheInfo.idl', ] -IPDL_SOURCES += [ - 'PStartupCache.ipdl', -] - -include('/ipc/chromium/chromium-config.mozbuild') - FINAL_LIBRARY = 'xul' diff --git a/startupcache/test/TestStartupCache.cpp b/startupcache/test/TestStartupCache.cpp index 0a95d92e6bba..28e758c6a5e3 100644 --- a/startupcache/test/TestStartupCache.cpp +++ b/startupcache/test/TestStartupCache.cpp @@ -66,11 +66,6 @@ TestStartupCache::TestStartupCache() { // We intentionally leak `env` here because it is required by PR_SetEnv MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(env); #endif - - if (!StartupCache::GetSingleton()) { - StartupCache::PartialInitSingleton(nullptr); - StartupCache::FullyInitSingleton(); - } StartupCache::GetSingleton()->InvalidateCache(); } TestStartupCache::~TestStartupCache() { diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 5b0675db9337..2219b3e22abd 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -4234,10 +4234,7 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) { mAppData->directory, gSafeMode || !startupCacheValid); } - if (!startupCacheValid) { - StartupCache::IgnoreDiskCache(); - } - StartupCache::PartialInitSingleton(mProfLD); + if (!startupCacheValid) StartupCache::IgnoreDiskCache(); if (flagFile) { flagFile->Remove(true); diff --git a/xpcom/base/AppShutdown.cpp b/xpcom/base/AppShutdown.cpp index 24deea5fd8ed..a3a6ebe1dafa 100644 --- a/xpcom/base/AppShutdown.cpp +++ b/xpcom/base/AppShutdown.cpp @@ -142,7 +142,7 @@ void AppShutdown::Init(AppShutdownMode aMode) { // Very early shutdowns can happen before the startup cache is even // initialized; don't bother initializing it during shutdown. - if (auto* cache = scache::StartupCache::GetSingleton()) { + if (auto* cache = scache::StartupCache::GetSingletonNoInit()) { cache->MaybeInitShutdownWrite(); } } @@ -152,7 +152,7 @@ void AppShutdown::MaybeFastShutdown(ShutdownPhase aPhase) { // the late write checking code. Anything that writes to disk and which // we don't want to skip should be listed out explicitly in this section. if (aPhase == sFastShutdownPhase || aPhase == sLateWriteChecksPhase) { - if (auto* cache = scache::StartupCache::GetSingleton()) { + if (auto* cache = scache::StartupCache::GetSingletonNoInit()) { cache->EnsureShutdownWriteComplete(); } diff --git a/xpcom/build/FileLocation.cpp b/xpcom/build/FileLocation.cpp index a55070cce0d2..ae0d5d90e1f1 100644 --- a/xpcom/build/FileLocation.cpp +++ b/xpcom/build/FileLocation.cpp @@ -7,7 +7,6 @@ #include "FileLocation.h" #include "nsZipArchive.h" #include "nsURLHelper.h" -#include "mozilla/Omnijar.h" namespace mozilla { @@ -17,12 +16,12 @@ FileLocation::~FileLocation() = default; FileLocation::FileLocation(nsIFile* aFile) { Init(aFile); } -FileLocation::FileLocation(CacheAwareZipReader* aZip, const char* aPath) { - Init(aZip, aPath); +FileLocation::FileLocation(nsIFile* aFile, const char* aPath) { + Init(aFile, aPath); } FileLocation::FileLocation(nsZipArchive* aZip, const char* aPath) { - Init(new CacheAwareZipReader(aZip, nullptr), aPath); + Init(aZip, aPath); } FileLocation::FileLocation(const FileLocation& aOther) @@ -89,14 +88,8 @@ void FileLocation::Init(nsIFile* aFile, const char* aPath) { mPath = aPath; } -void FileLocation::Init(CacheAwareZipReader* aZip, const char* aPath) { - mBaseZip = aZip; - mBaseFile = nullptr; - mPath = aPath; -} - void FileLocation::Init(nsZipArchive* aZip, const char* aPath) { - mBaseZip = new CacheAwareZipReader(aZip, nullptr); + mBaseZip = aZip; mBaseFile = nullptr; mPath = aPath; } @@ -105,7 +98,8 @@ void FileLocation::GetURIString(nsACString& aResult) const { if (mBaseFile) { net_GetURLSpecFromActualFile(mBaseFile, aResult); } else if (mBaseZip) { - mBaseZip->GetURIString(aResult); + RefPtr handler = mBaseZip->GetFD(); + handler->mFile.GetURIString(aResult); } if (IsZip()) { aResult.InsertLiteral("jar:", 0); @@ -116,7 +110,11 @@ void FileLocation::GetURIString(nsACString& aResult) const { already_AddRefed FileLocation::GetBaseFile() { if (IsZip() && mBaseZip) { - return mBaseZip->GetBaseFile(); + RefPtr handler = mBaseZip->GetFD(); + if (handler) { + return handler->mFile.GetBaseFile(); + } + return nullptr; } nsCOMPtr file = mBaseFile; @@ -128,17 +126,23 @@ bool FileLocation::Equals(const FileLocation& aFile) const { return false; } - nsCOMPtr a = mBaseFile; - nsCOMPtr b = aFile.mBaseFile; - if (!mBaseFile && mBaseZip) { - a = mBaseZip->GetBaseFile(); - } - if (!aFile.mBaseFile && aFile.mBaseZip) { - b = mBaseZip->GetBaseFile(); + if (mBaseFile && aFile.mBaseFile) { + bool eq; + return NS_SUCCEEDED(mBaseFile->Equals(aFile.mBaseFile, &eq)) && eq; } - bool eq; - return NS_SUCCEEDED(a->Equals(b, &eq)) && eq; + const FileLocation* a = this; + const FileLocation* b = &aFile; + if (a->mBaseZip) { + RefPtr handler = a->mBaseZip->GetFD(); + a = &handler->mFile; + } + if (b->mBaseZip) { + RefPtr handler = b->mBaseZip->GetFD(); + b = &handler->mFile; + } + + return a->Equals(*b); } nsresult FileLocation::GetData(Data& aData) { @@ -147,7 +151,7 @@ nsresult FileLocation::GetData(Data& aData) { } aData.mZip = mBaseZip; if (!aData.mZip) { - aData.mZip = new CacheAwareZipReader(); + aData.mZip = new nsZipArchive(); aData.mZip->OpenArchive(mBaseFile); } aData.mItem = aData.mZip->GetItem(mPath.get()); @@ -191,8 +195,8 @@ nsresult FileLocation::Data::Copy(char* aBuf, uint32_t aLen) { return NS_OK; } if (mItem) { - CacheAwareZipCursor cursor(mItem, mZip, reinterpret_cast(aBuf), - aLen, true); + nsZipCursor cursor(mItem, mZip, reinterpret_cast(aBuf), aLen, + true); uint32_t readLen; cursor.Copy(&readLen); if (readLen != aLen) { diff --git a/xpcom/build/FileLocation.h b/xpcom/build/FileLocation.h index fd5d7503de55..0988a9595ffb 100644 --- a/xpcom/build/FileLocation.h +++ b/xpcom/build/FileLocation.h @@ -17,8 +17,6 @@ class nsZipItem; namespace mozilla { -class CacheAwareZipReader; - class FileLocation { public: /** @@ -29,7 +27,7 @@ class FileLocation { * - in archives within archives * As such, it stores a path within an archive, as well as the archive * path itself, or the complete file path alone when on a filesystem. - * When the archive is in an archive, an CacheAwareZipReader is stored instead + * When the archive is in an archive, an nsZipArchive is stored instead * of a file path. */ FileLocation(); @@ -47,14 +45,9 @@ class FileLocation { /** * Constructors for path within an archive. The archive can be given either - * as nsIFile or CacheAwareZipReader. + * as nsIFile or nsZipArchive. */ - FileLocation(nsIFile* aFile, const char* aPath); - - /** - * Constructors for path within a zip archive. - */ - FileLocation(CacheAwareZipReader* aZip, const char* aPath); + FileLocation(nsIFile* aZip, const char* aPath); FileLocation(nsZipArchive* aZip, const char* aPath); @@ -68,12 +61,10 @@ class FileLocation { */ void Init(nsIFile* aFile); - void Init(nsIFile* aFile, const char* aPath); + void Init(nsIFile* aZip, const char* aPath); void Init(nsZipArchive* aZip, const char* aPath); - void Init(CacheAwareZipReader* aZip, const char* aPath); - /** * Returns an URI string corresponding to the file location */ @@ -87,7 +78,7 @@ class FileLocation { */ already_AddRefed GetBaseFile(); - CacheAwareZipReader* GetBaseZip() { return mBaseZip; } + nsZipArchive* GetBaseZip() { return mBaseZip; } /** * Returns whether the "base file" (see GetBaseFile) is an archive @@ -128,7 +119,7 @@ class FileLocation { protected: friend class FileLocation; nsZipItem* mItem; - RefPtr mZip; + RefPtr mZip; mozilla::AutoFDClose mFd; }; @@ -140,7 +131,7 @@ class FileLocation { private: nsCOMPtr mBaseFile; - RefPtr mBaseZip; + RefPtr mBaseZip; nsCString mPath; }; /* class FileLocation */ diff --git a/xpcom/build/Omnijar.cpp b/xpcom/build/Omnijar.cpp index 2e24300e3dba..36a8a511cbeb 100644 --- a/xpcom/build/Omnijar.cpp +++ b/xpcom/build/Omnijar.cpp @@ -1,5 +1,4 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -12,28 +11,16 @@ #include "nsIFile.h" #include "nsZipArchive.h" #include "nsNetUtil.h" -#include "mozilla/scache/StartupCache.h" -#include "mozilla/MmapFaultHandler.h" namespace mozilla { StaticRefPtr Omnijar::sPath[2]; -StaticRefPtr Omnijar::sReader[2]; -StaticRefPtr Omnijar::sOuterReader[2]; +StaticRefPtr Omnijar::sReader[2]; +StaticRefPtr Omnijar::sOuterReader[2]; bool Omnijar::sInitialized = false; bool Omnijar::sIsUnified = false; -static MOZ_THREAD_LOCAL(int) tlsSuspendStartupCacheWrites; - -bool SuspendingStartupCacheWritesForCurrentThread() { - if (!tlsSuspendStartupCacheWrites.init()) { - return true; - } - return tlsSuspendStartupCacheWrites.get() > 0; -} - static const char* sProp[2] = {NS_GRE_DIR, NS_XPCOM_CURRENT_PROCESS_DIR}; -static const char* sCachePrefixes[2] = {"GreOmnijar:", "AppOmnijar:"}; #define SPROP(Type) ((Type == mozilla::Omnijar::GRE) ? sProp[GRE] : sProp[APP]) @@ -91,41 +78,8 @@ void Omnijar::InitOne(nsIFile* aPath, Type aType) { } RefPtr zipReader = new nsZipArchive(); - auto* cache = scache::StartupCache::GetSingleton(); - const uint8_t* centralBuf = nullptr; - uint32_t centralBufLength = 0; - nsCString startupCacheKey = - nsPrintfCString("::%s:OmnijarCentral", sCachePrefixes[aType]); - if (cache) { - nsresult rv = cache->GetBuffer(startupCacheKey.get(), - reinterpret_cast(¢ralBuf), - ¢ralBufLength); - if (NS_FAILED(rv)) { - centralBuf = nullptr; - centralBufLength = 0; - } - } - - if (!centralBuf) { - if (NS_FAILED(zipReader->OpenArchive(file))) { - return; - } - if (cache) { - size_t bufSize; - // Annoyingly, nsZipArchive and the startupcache use different types to - // represent bytes (uint8_t vs char), so we have to do a little dance to - // convert the UniquePtr over. - UniquePtr centralBuf(reinterpret_cast( - zipReader->CopyCentralDirectoryBuffer(&bufSize).release())); - if (centralBuf) { - cache->PutBuffer(startupCacheKey.get(), std::move(centralBuf), bufSize); - } - } - } else { - if (NS_FAILED(zipReader->LazyOpenArchive( - file, MakeSpan(centralBuf, centralBufLength)))) { - return; - } + if (NS_FAILED(zipReader->OpenArchive(file))) { + return; } RefPtr outerReader; @@ -140,9 +94,8 @@ void Omnijar::InitOne(nsIFile* aPath, Type aType) { } CleanUpOne(aType); - sReader[aType] = new CacheAwareZipReader(zipReader, sCachePrefixes[aType]); - sOuterReader[aType] = - outerReader ? new CacheAwareZipReader(outerReader, nullptr) : nullptr; + sReader[aType] = zipReader; + sOuterReader[aType] = outerReader; sPath[aType] = file; } @@ -158,7 +111,7 @@ void Omnijar::CleanUp() { sInitialized = false; } -already_AddRefed Omnijar::GetReader(nsIFile* aPath) { +already_AddRefed Omnijar::GetReader(nsIFile* aPath) { MOZ_ASSERT(IsInitialized(), "Omnijar not initialized"); bool equals; @@ -179,7 +132,7 @@ already_AddRefed Omnijar::GetReader(nsIFile* aPath) { return nullptr; } -already_AddRefed Omnijar::GetInnerReader( +already_AddRefed Omnijar::GetInnerReader( nsIFile* aPath, const nsACString& aEntry) { MOZ_ASSERT(IsInitialized(), "Omnijar not initialized"); @@ -244,226 +197,4 @@ nsresult Omnijar::GetURIString(Type aType, nsACString& aResult) { return NS_OK; } -CacheAwareZipReader::CacheAwareZipReader(nsZipArchive* aZip, - const char* aCacheKeyPrefix) - : mZip(aZip), mCacheKeyPrefix(aCacheKeyPrefix) {} - -nsresult CacheAwareZipReader::FindInit(const char* aPattern, - nsZipFind** aFind) { - return mZip->FindInit(aPattern, aFind); -} - -const uint8_t* CacheAwareZipReader::GetData( - nsZipItem* aItem, CacheAwareZipReader::Caching aCaching) { - nsAutoCString cacheKey; - uint32_t size; - const uint8_t* cached = - GetCachedBuffer(aItem->Name(), aItem->nameLength, &size, cacheKey); - if (cached) { - MOZ_ASSERT(size == aItem->RealSize()); - return cached; - } - - const uint8_t* zipItemData = mZip->GetData(aItem); - - // If the data is compressed, it is somewhat silly to store it in the startup - // cache, as the startup cache will try to double compress it. - if (aCaching == Default && aItem->Compression() == STORED && - !cacheKey.IsEmpty()) { - MOZ_ASSERT(aItem->RealSize() == aItem->Size()); - PutBufferIntoCache(cacheKey, zipItemData, aItem->Size()); - } - - return zipItemData; -} - -const uint8_t* CacheAwareZipReader::GetData( - const char* aEntryName, uint32_t* aResultSize, - CacheAwareZipReader::Caching aCaching) { - nsAutoCString cacheKey; - const uint8_t* cached = - GetCachedBuffer(aEntryName, strlen(aEntryName), aResultSize, cacheKey); - if (cached) { - return cached; - } - - nsZipItem* zipItem = mZip->GetItem(aEntryName); - if (!zipItem) { - *aResultSize = 0; - return nullptr; - } - const uint8_t* zipItemData = mZip->GetData(zipItem); - *aResultSize = zipItem->Size(); - - // If the data is compressed, it is somewhat silly to store it in the startup - // cache, as the startup cache will try to double compress it. - if (aCaching == Default && zipItem->Compression() == STORED && - !cacheKey.IsEmpty()) { - MOZ_ASSERT(zipItem->RealSize() == *aResultSize); - PutBufferIntoCache(cacheKey, zipItemData, *aResultSize); - } - - return zipItemData; -} - -nsZipItem* CacheAwareZipReader::GetItem(const char* aEntryName) { - return mZip->GetItem(aEntryName); -} - -nsresult CacheAwareZipReader::CloseArchive() { return mZip->CloseArchive(); } - -CacheAwareZipCursor::CacheAwareZipCursor(nsZipItem* aItem, - CacheAwareZipReader* aReader, - uint8_t* aBuf, uint32_t aBufSize, - bool aDoCRC) - : mItem(aItem), - mReader(aReader), - mBuf(aBuf), - mBufSize(aBufSize), - mDoCRC(aDoCRC) {} - -uint8_t* CacheAwareZipCursor::ReadOrCopy(uint32_t* aBytesRead, bool aCopy) { - nsCString cacheKey; - const uint8_t* cached = mReader->GetCachedBuffer( - mItem->Name(), mItem->nameLength, aBytesRead, cacheKey); - if (cached && *aBytesRead <= mBufSize) { - if (aCopy) { - memcpy(mBuf, cached, *aBytesRead); - return mBuf; - } - - // The const cast is unfortunate, but it matches existing consumers' - // uses. We ought to file a bug to make Read return a const uint8_t* - return const_cast(cached); - } - - nsZipCursor cursor(mItem, mReader->mZip, mBuf, mBufSize, mDoCRC); - uint8_t* buf = nullptr; - if (aCopy) { - cursor.Copy(aBytesRead); - buf = mBuf; - } else { - buf = cursor.Read(aBytesRead); - } - - if (!cacheKey.IsEmpty() && *aBytesRead == mItem->RealSize()) { - CacheAwareZipReader::PutBufferIntoCache(cacheKey, buf, *aBytesRead); - } - - return buf; -} - -nsresult CacheAwareZipReader::GetPersistentHandle( - nsZipItem* aItem, CacheAwareZipHandle* aHandle, - CacheAwareZipReader::Caching aCaching) { - nsCString cacheKey; - if (!mCacheKeyPrefix.IsEmpty() && aItem->Compression() == STORED) { - auto* cache = scache::StartupCache::GetSingleton(); - if (cache) { - cacheKey.Append(mCacheKeyPrefix); - cacheKey.Append(aItem->Name(), aItem->nameLength); - - if (cache->HasEntry(cacheKey.get())) { - aHandle->mDataIsCached = true; - aHandle->mFd = nullptr; - return NS_OK; - } - if (aCaching == DeferCaching) { - aHandle->mDeferredCachingKey = std::move(cacheKey); - } - } - } - - nsresult rv = mZip->EnsureArchiveOpenedOnDisk(); - if (NS_FAILED(rv)) { - return rv; - } - - aHandle->mDataIsCached = false; - aHandle->mFd = mZip->GetFD(); - - if (!aHandle->mDeferredCachingKey.IsEmpty() && - aItem->Compression() == STORED) { - MOZ_ASSERT(aItem->RealSize() == aItem->Size()); - aHandle->mDataToCache = MakeSpan(mZip->GetData(aItem), aItem->Size()); - } - - return NS_OK; -} - -const uint8_t* CacheAwareZipReader::GetCachedBuffer(const char* aEntryName, - uint32_t aEntryNameLength, - uint32_t* aResultSize, - nsCString& aCacheKey) { - *aResultSize = 0; - if (mCacheKeyPrefix.IsEmpty()) { - return nullptr; - } - auto* cache = scache::StartupCache::GetSingleton(); - if (!cache) { - return nullptr; - } - - aCacheKey.Append(mCacheKeyPrefix); - aCacheKey.Append(aEntryName, aEntryNameLength); - - const char* cached; - nsresult rv = cache->GetBuffer(aCacheKey.get(), &cached, aResultSize); - if (NS_FAILED(rv)) { - return nullptr; - } - - return reinterpret_cast(cached); -} - -void CacheAwareZipReader::PutBufferIntoCache(const nsCString& aCacheKey, - const uint8_t* aBuffer, - uint32_t aSize) { - if (SuspendingStartupCacheWritesForCurrentThread() || aSize == 0) { - return; - } - - auto* cache = scache::StartupCache::GetSingleton(); - auto dataCopy = MakeUnique(aSize); - - MMAP_FAULT_HANDLER_BEGIN_BUFFER(aBuffer, aSize) - memcpy(dataCopy.get(), aBuffer, aSize); - MMAP_FAULT_HANDLER_CATCH() - Unused << cache->PutBuffer(aCacheKey.get(), std::move(dataCopy), aSize); -} - -void CacheAwareZipReader::PushSuspendStartupCacheWrites() { - if (!tlsSuspendStartupCacheWrites.init()) { - return; - } - tlsSuspendStartupCacheWrites.set(tlsSuspendStartupCacheWrites.get() + 1); -} - -void CacheAwareZipReader::PopSuspendStartupCacheWrites() { - if (!tlsSuspendStartupCacheWrites.init()) { - return; - } - int current = tlsSuspendStartupCacheWrites.get(); - MOZ_ASSERT(current > 0); - tlsSuspendStartupCacheWrites.set(current - 1); -} - -void CacheAwareZipHandle::ReleaseHandle() { - if (!mDataToCache.IsEmpty()) { - MOZ_ASSERT(mFd); - MOZ_ASSERT(!mDeferredCachingKey.IsEmpty()); - MOZ_ASSERT(!mDataIsCached); - - auto* cache = scache::StartupCache::GetSingleton(); - MOZ_ASSERT(cache); - if (cache) { - CacheAwareZipReader::PutBufferIntoCache( - mDeferredCachingKey, mDataToCache.Elements(), mDataToCache.Length()); - mDataToCache = Span(); - } - } - - mFd = nullptr; -} - } /* namespace mozilla */ diff --git a/xpcom/build/Omnijar.h b/xpcom/build/Omnijar.h index 444f6753d086..793a26570fd4 100644 --- a/xpcom/build/Omnijar.h +++ b/xpcom/build/Omnijar.h @@ -13,14 +13,10 @@ #include "nsIFile.h" #include "nsZipArchive.h" -#include "mozilla/Span.h" #include "mozilla/StaticPtr.h" -#include "mozilla/UniquePtr.h" namespace mozilla { -class CacheAwareZipReader; - class Omnijar { private: /** @@ -32,15 +28,15 @@ class Omnijar { static StaticRefPtr sPath[2]; /** - * Cached CacheAwareZipReaders for the corresponding sPath + * Cached nsZipArchives for the corresponding sPath */ - static StaticRefPtr sReader[2]; + static StaticRefPtr sReader[2]; /** - * Cached CacheAwareZipReaders for the outer jar, when using nested jars. + * Cached nsZipArchives for the outer jar, when using nested jars. * Otherwise nullptr. */ - static StaticRefPtr sOuterReader[2]; + static StaticRefPtr sOuterReader[2]; /** * Has Omnijar::Init() been called? @@ -65,14 +61,13 @@ class Omnijar { } /** - * Returns an CacheAwareZipReader pointer for the outer jar file when using - * nested jars. Returns nullptr in the same cases GetPath() would, or if not - * using nested jars. + * Returns a nsZipArchive pointer for the outer jar file when using nested + * jars. Returns nullptr in the same cases GetPath() would, or if not using + * nested jars. */ - static inline already_AddRefed GetOuterReader( - Type aType) { + static inline already_AddRefed GetOuterReader(Type aType) { MOZ_ASSERT(IsInitialized(), "Omnijar not initialized"); - RefPtr reader = sOuterReader[aType].get(); + RefPtr reader = sOuterReader[aType].get(); return reader.forget(); } @@ -118,20 +113,20 @@ class Omnijar { } /** - * Returns an CacheAwareZipReader pointer for the omni.jar file for GRE or + * Returns a nsZipArchive pointer for the omni.jar file for GRE or * APP. Returns nullptr in the same cases GetPath() would. */ - static inline already_AddRefed GetReader(Type aType) { + static inline already_AddRefed GetReader(Type aType) { MOZ_ASSERT(IsInitialized(), "Omnijar not initialized"); - RefPtr reader = sReader[aType].get(); + RefPtr reader = sReader[aType].get(); return reader.forget(); } /** - * Returns an CacheAwareZipReader pointer for the given path IAOI the given + * Returns a nsZipArchive pointer for the given path IAOI the given * path is the omni.jar for either GRE or APP. */ - static already_AddRefed GetReader(nsIFile* aPath); + static already_AddRefed GetReader(nsIFile* aPath); /** * In the case of a nested omnijar, this returns the inner reader for the @@ -141,7 +136,7 @@ class Omnijar { * GetReader("path/to.apk") returns the outer reader and GetInnerReader( * "path/to.apk", "assets/omni.ja") returns the inner reader. */ - static already_AddRefed GetInnerReader( + static already_AddRefed GetInnerReader( nsIFile* aPath, const nsACString& aEntry); /** @@ -161,132 +156,6 @@ class Omnijar { static void CleanUpOne(Type aType); }; /* class Omnijar */ -class CacheAwareZipCursor { - public: - CacheAwareZipCursor(nsZipItem* aItem, CacheAwareZipReader* aReader, - uint8_t* aBuf = nullptr, uint32_t aBufSize = 0, - bool aDoCRC = false); - - uint8_t* Read(uint32_t* aBytesRead) { return ReadOrCopy(aBytesRead, false); } - uint8_t* Copy(uint32_t* aBytesRead) { return ReadOrCopy(aBytesRead, true); } - - private: - /* Actual implementation for both Read and Copy above */ - uint8_t* ReadOrCopy(uint32_t* aBytesRead, bool aCopy); - - nsZipItem* mItem; - CacheAwareZipReader* mReader; - - uint8_t* mBuf; - uint32_t mBufSize; - - bool mDoCRC; -}; - -// This class wraps an nsZipHandle, which may be null, if the data is -// cached -class CacheAwareZipHandle { - friend class CacheAwareZipReader; - - public: - CacheAwareZipHandle() : mFd(nullptr), mDataIsCached(false) {} - ~CacheAwareZipHandle() { ReleaseHandle(); } - - nsZipHandle* UnderlyingFD() { return mFd; } - void ReleaseHandle(); - - explicit operator bool() const { return mDataIsCached || mFd; } - - private: - RefPtr mFd; - nsCString mDeferredCachingKey; - Span mDataToCache; - bool mDataIsCached; -}; - -class CacheAwareZipReader { - friend class CacheAwareZipCursor; - friend class CacheAwareZipHandle; - - public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CacheAwareZipReader) - - enum Caching { - Default, - DeferCaching, - }; - - // Constructor for CacheAwareZipReader. aCacheKeyPrefix will be a prefix - // which the wrapper will prepend to any requested entries prior to - // requesting the entry from the StartupCache. However, if aCacheKeyPrefix - // is null, we will simply pass through to the underlying zip archive - // without caching. - explicit CacheAwareZipReader(nsZipArchive* aZip, const char* aCacheKeyPrefix); - - // The default constructor should be used for an nsZipArchive which doesn't - // want to cache any entries. Consumers will need to call `OpenArchive` - // explicitly after constructing. - CacheAwareZipReader() : mZip(new nsZipArchive()) {} - - nsresult OpenArchive(nsIFile* aFile) { return mZip->OpenArchive(aFile); } - nsresult OpenArchive(nsZipHandle* aHandle) { - return mZip->OpenArchive(aHandle); - } - - const uint8_t* GetData(const char* aEntryName, uint32_t* aResultSize, - Caching aCaching = Default); - const uint8_t* GetData(nsZipItem* aItem, Caching aCaching = Default); - - nsresult GetPersistentHandle(nsZipItem* aItem, CacheAwareZipHandle* aHandle, - Caching aCaching); - - already_AddRefed GetBaseFile() { return mZip->GetBaseFile(); } - - void GetURIString(nsACString& result) { mZip->GetURIString(result); } - - nsZipArchive* GetZipArchive() { return mZip; } - - nsresult FindInit(const char* aPattern, nsZipFind** aFind); - bool IsForZip(nsZipArchive* aArchive) { return aArchive == mZip; } - nsZipItem* GetItem(const char* aEntryName); - - nsresult CloseArchive(); - - nsresult Test(const char* aEntryName) { return mZip->Test(aEntryName); } - - nsresult ExtractFile(nsZipItem* zipEntry, nsIFile* outFile, - PRFileDesc* outFD) { - return mZip->ExtractFile(zipEntry, outFile, outFD); - } - - static void PushSuspendStartupCacheWrites(); - static void PopSuspendStartupCacheWrites(); - - protected: - ~CacheAwareZipReader() = default; - - private: - const uint8_t* GetCachedBuffer(const char* aEntryName, - uint32_t aEntryNameLength, - uint32_t* aResultSize, nsCString& aCacheKey); - static void PutBufferIntoCache(const nsCString& aCacheKey, - const uint8_t* aBuffer, uint32_t aSize); - - RefPtr mZip; - nsCString mCacheKeyPrefix; -}; - -class MOZ_RAII AutoSuspendStartupCacheWrites { - public: - AutoSuspendStartupCacheWrites() { - CacheAwareZipReader::PushSuspendStartupCacheWrites(); - } - - ~AutoSuspendStartupCacheWrites() { - CacheAwareZipReader::PopSuspendStartupCacheWrites(); - } -}; - } /* namespace mozilla */ #endif /* mozilla_Omnijar_h */ diff --git a/xpcom/build/XPCOMInit.cpp b/xpcom/build/XPCOMInit.cpp index 2070eab133f0..f64190c9b534 100644 --- a/xpcom/build/XPCOMInit.cpp +++ b/xpcom/build/XPCOMInit.cpp @@ -462,7 +462,7 @@ NS_InitXPCOM(nsIServiceManager** aResult, nsIFile* aBinDirectory, // Init mozilla::SharedThreadPool (which needs the service manager). mozilla::SharedThreadPool::InitStatics(); - mozilla::scache::StartupCache::FullyInitSingleton(); + mozilla::scache::StartupCache::GetSingleton(); mozilla::AvailableMemoryTracker::Init(); // Notify observers of xpcom autoregistration start diff --git a/xpcom/components/nsComponentManager.cpp b/xpcom/components/nsComponentManager.cpp index 874448598d68..aa4a4e8436fe 100644 --- a/xpcom/components/nsComponentManager.cpp +++ b/xpcom/components/nsComponentManager.cpp @@ -491,7 +491,7 @@ nsresult nsComponentManagerImpl::Init() { InitializeModuleLocations(); ComponentLocation* cl = sModuleLocations->AppendElement(); cl->type = NS_APP_LOCATION; - RefPtr greOmnijar = + RefPtr greOmnijar = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE); if (greOmnijar) { cl->location.Init(greOmnijar, "chrome.manifest"); @@ -500,7 +500,7 @@ nsresult nsComponentManagerImpl::Init() { cl->location.Init(lf); } - RefPtr appOmnijar = + RefPtr appOmnijar = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP); if (appOmnijar) { cl = sModuleLocations->AppendElement();