File: | var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp |
Warning: | line 189, column 5 Value stored to 'rv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | |
7 | #include "prio.h" |
8 | #include "PLDHashTable.h" |
9 | #include "mozilla/IOInterposer.h" |
10 | #include "mozilla/AutoMemMap.h" |
11 | #include "mozilla/IOBuffers.h" |
12 | #include "mozilla/MemoryReporting.h" |
13 | #include "mozilla/MemUtils.h" |
14 | #include "mozilla/MmapFaultHandler.h" |
15 | #include "mozilla/ResultExtensions.h" |
16 | #include "mozilla/scache/StartupCache.h" |
17 | #include "mozilla/ScopeExit.h" |
18 | #include "mozilla/Try.h" |
19 | |
20 | #include "nsClassHashtable.h" |
21 | #include "nsComponentManagerUtils.h" |
22 | #include "nsCRT.h" |
23 | #include "nsDirectoryServiceUtils.h" |
24 | #include "nsIClassInfo.h" |
25 | #include "nsIFile.h" |
26 | #include "nsIObserver.h" |
27 | #include "nsIOutputStream.h" |
28 | #include "nsISupports.h" |
29 | #include "nsITimer.h" |
30 | #include "mozilla/Omnijar.h" |
31 | #include "prenv.h" |
32 | #include "mozilla/Telemetry.h" |
33 | #include "nsThreadUtils.h" |
34 | #include "nsXULAppAPI.h" |
35 | #include "nsIProtocolHandler.h" |
36 | #include "GeckoProfiler.h" |
37 | #include "nsAppRunner.h" |
38 | #include "xpcpublic.h" |
39 | #ifdef MOZ_BACKGROUNDTASKS1 |
40 | # include "mozilla/BackgroundTasks.h" |
41 | #endif |
42 | |
43 | #if defined(XP_WIN) |
44 | # include <windows.h> |
45 | #endif |
46 | |
47 | #ifdef IS_BIG_ENDIAN |
48 | # define SC_ENDIAN"little" "big" |
49 | #else |
50 | # define SC_ENDIAN"little" "little" |
51 | #endif |
52 | |
53 | #if PR_BYTES_PER_WORD8 == 4 |
54 | # define SC_WORDSIZE"8" "4" |
55 | #else |
56 | # define SC_WORDSIZE"8" "8" |
57 | #endif |
58 | |
59 | using namespace mozilla::Compression; |
60 | |
61 | namespace mozilla { |
62 | namespace scache { |
63 | |
64 | MOZ_DEFINE_MALLOC_SIZE_OF(StartupCacheMallocSizeOf)static size_t StartupCacheMallocSizeOf(const void* aPtr) { mozilla ::dmd::Report(aPtr); return moz_malloc_size_of(aPtr); } |
65 | |
66 | NS_IMETHODIMPnsresult |
67 | StartupCache::CollectReports(nsIHandleReportCallback* aHandleReport, |
68 | nsISupports* aData, bool aAnonymize) { |
69 | MutexAutoLock lock(mTableLock); |
70 | MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/mapping" ), KIND_NONHEAP, UNITS_BYTES, mCacheData.nonHeapSizeOfExcludingThis (), nsLiteralCString("Memory used to hold the mapping of the startup cache from file. " "This memory is likely to be swapped out shortly after start-up." ), aData) |
71 | "explicit/startup-cache/mapping", KIND_NONHEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/mapping" ), KIND_NONHEAP, UNITS_BYTES, mCacheData.nonHeapSizeOfExcludingThis (), nsLiteralCString("Memory used to hold the mapping of the startup cache from file. " "This memory is likely to be swapped out shortly after start-up." ), aData) |
72 | mCacheData.nonHeapSizeOfExcludingThis(),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/mapping" ), KIND_NONHEAP, UNITS_BYTES, mCacheData.nonHeapSizeOfExcludingThis (), nsLiteralCString("Memory used to hold the mapping of the startup cache from file. " "This memory is likely to be swapped out shortly after start-up." ), aData) |
73 | "Memory used to hold the mapping of the startup cache from file. "(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/mapping" ), KIND_NONHEAP, UNITS_BYTES, mCacheData.nonHeapSizeOfExcludingThis (), nsLiteralCString("Memory used to hold the mapping of the startup cache from file. " "This memory is likely to be swapped out shortly after start-up." ), aData) |
74 | "This memory is likely to be swapped out shortly after start-up.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/mapping" ), KIND_NONHEAP, UNITS_BYTES, mCacheData.nonHeapSizeOfExcludingThis (), nsLiteralCString("Memory used to hold the mapping of the startup cache from file. " "This memory is likely to be swapped out shortly after start-up." ), aData); |
75 | |
76 | MOZ_COLLECT_REPORT("explicit/startup-cache/data", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/data" ), KIND_HEAP, UNITS_BYTES, HeapSizeOfIncludingThis(StartupCacheMallocSizeOf ), nsLiteralCString("Memory used by the startup cache for things other than " "the file mapping."), aData) |
77 | HeapSizeOfIncludingThis(StartupCacheMallocSizeOf),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/data" ), KIND_HEAP, UNITS_BYTES, HeapSizeOfIncludingThis(StartupCacheMallocSizeOf ), nsLiteralCString("Memory used by the startup cache for things other than " "the file mapping."), aData) |
78 | "Memory used by the startup cache for things other than "(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/data" ), KIND_HEAP, UNITS_BYTES, HeapSizeOfIncludingThis(StartupCacheMallocSizeOf ), nsLiteralCString("Memory used by the startup cache for things other than " "the file mapping."), aData) |
79 | "the file mapping.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/data" ), KIND_HEAP, UNITS_BYTES, HeapSizeOfIncludingThis(StartupCacheMallocSizeOf ), nsLiteralCString("Memory used by the startup cache for things other than " "the file mapping."), aData); |
80 | |
81 | return NS_OK; |
82 | } |
83 | |
84 | static const uint8_t MAGIC[] = "startupcache0002"; |
85 | // This is a heuristic value for how much to reserve for mTable to avoid |
86 | // rehashing. This is not a hard limit in release builds, but it is in |
87 | // debug builds as it should be stable. If we exceed this number we should |
88 | // just increase it. |
89 | static const size_t STARTUP_CACHE_RESERVE_CAPACITY = 450; |
90 | // This is a hard limit which we will assert on, to ensure that we don't |
91 | // have some bug causing runaway cache growth. |
92 | static const size_t STARTUP_CACHE_MAX_CAPACITY = 5000; |
93 | |
94 | // Not const because we change it for gtests. |
95 | static uint8_t STARTUP_CACHE_WRITE_TIMEOUT = 60; |
96 | |
97 | #define STARTUP_CACHE_NAME"startupCache." "8" "." "little" "startupCache." SC_WORDSIZE"8" "." SC_ENDIAN"little" |
98 | |
99 | static inline Result<Ok, nsresult> Write(PRFileDesc* fd, const void* data, |
100 | int32_t len) { |
101 | if (PR_Write(fd, data, len) != len) { |
102 | return Err(NS_ERROR_FAILURE); |
103 | } |
104 | return Ok(); |
105 | } |
106 | |
107 | static inline Result<Ok, nsresult> Seek(PRFileDesc* fd, int32_t offset) { |
108 | if (PR_Seek(fd, offset, PR_SEEK_SET) == -1) { |
109 | return Err(NS_ERROR_FAILURE); |
110 | } |
111 | return Ok(); |
112 | } |
113 | |
114 | static nsresult MapLZ4ErrorToNsresult(size_t aError) { |
115 | return NS_ERROR_FAILURE; |
116 | } |
117 | |
118 | StartupCache* StartupCache::GetSingletonNoInit() { |
119 | return StartupCache::gStartupCache; |
120 | } |
121 | |
122 | StartupCache* StartupCache::GetSingleton() { |
123 | #ifdef MOZ_BACKGROUNDTASKS1 |
124 | if (BackgroundTasks::IsBackgroundTaskMode()) { |
125 | return nullptr; |
126 | } |
127 | #endif |
128 | |
129 | if (!gStartupCache) { |
130 | if (!XRE_IsParentProcess()) { |
131 | return nullptr; |
132 | } |
133 | #ifdef MOZ_DISABLE_STARTUPCACHE |
134 | return nullptr; |
135 | #else |
136 | StartupCache::InitSingleton(); |
137 | #endif |
138 | } |
139 | |
140 | return StartupCache::gStartupCache; |
141 | } |
142 | |
143 | void StartupCache::DeleteSingleton() { StartupCache::gStartupCache = nullptr; } |
144 | |
145 | nsresult StartupCache::InitSingleton() { |
146 | nsresult rv; |
147 | StartupCache::gStartupCache = new StartupCache(); |
148 | |
149 | rv = StartupCache::gStartupCache->Init(); |
150 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
151 | StartupCache::gStartupCache = nullptr; |
152 | } |
153 | return rv; |
154 | } |
155 | |
156 | StaticRefPtr<StartupCache> StartupCache::gStartupCache; |
157 | bool StartupCache::gShutdownInitiated; |
158 | bool StartupCache::gIgnoreDiskCache; |
159 | bool StartupCache::gFoundDiskCacheOnInit; |
160 | |
161 | NS_IMPL_ISUPPORTS(StartupCache, nsIMemoryReporter)MozExternalRefCountType StartupCache::AddRef(void) { static_assert (!std::is_destructible_v<StartupCache>, "Reference-counted class " "StartupCache" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 161; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("StartupCache" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("StartupCache" != nullptr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"StartupCache\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCache\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 161; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("StartupCache" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("StartupCache" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType StartupCache::Release(void) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(int32_t(mRefCnt) > 0) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 161 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("StartupCache" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("StartupCache" != nullptr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"StartupCache\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCache\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 161; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("StartupCache" " not thread-safe"); const char * const nametmp = "StartupCache"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult StartupCache::QueryInterface(const nsIID& aIID, void** aInstancePtr ) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "QueryInterface requires a non-NULL destination!", "aInstancePtr" , "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 161); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<StartupCache, nsIMemoryReporter>, int32_t ( reinterpret_cast<char*>(static_cast<nsIMemoryReporter *>((StartupCache*)0x1000)) - reinterpret_cast<char*> ((StartupCache*)0x1000))}, {&mozilla::detail::kImplementedIID <StartupCache, nsISupports>, int32_t(reinterpret_cast< char*>(static_cast<nsISupports*>( static_cast<nsIMemoryReporter *>((StartupCache*)0x1000))) - reinterpret_cast<char*> ((StartupCache*)0x1000))}, { nullptr, 0 } } ; static_assert(( sizeof(table) / sizeof(table[0])) > 1, "need at least 1 interface" ); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID , aInstancePtr, table); return rv; } |
162 | |
163 | StartupCache::StartupCache() |
164 | : mTableLock("StartupCache::mTableLock"), |
165 | mDirty(false), |
166 | mWrittenOnce(false), |
167 | mCurTableReferenced(false), |
168 | mRequestedCount(0), |
169 | mCacheEntriesBaseOffset(0) {} |
170 | |
171 | StartupCache::~StartupCache() { UnregisterWeakMemoryReporter(this); } |
172 | |
173 | nsresult StartupCache::Init() { |
174 | // workaround for bug 653936 |
175 | nsCOMPtr<nsIProtocolHandler> jarInitializer( |
176 | do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"@mozilla.org/network/protocol;1?name=" "jar")); |
177 | |
178 | nsresult rv; |
179 | |
180 | if (mozilla::RunningGTest()) { |
181 | STARTUP_CACHE_WRITE_TIMEOUT = 3; |
182 | } |
183 | |
184 | // This allows to override the startup cache filename |
185 | // which is useful from xpcshell, when there is no ProfLDS directory to keep |
186 | // cache in. |
187 | char* env = PR_GetEnv("MOZ_STARTUP_CACHE"); |
188 | if (env && *env) { |
189 | rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(env), false, |
Value stored to 'rv' is never read | |
190 | getter_AddRefs(mFile)); |
191 | } else { |
192 | nsCOMPtr<nsIFile> file; |
193 | rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(file)); |
194 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
195 | // return silently, this will fail in mochitests's xpcshell process. |
196 | return rv; |
197 | } |
198 | |
199 | rv = file->AppendNative("startupCache"_ns); |
200 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 200); return rv; } } while (false); |
201 | |
202 | // Try to create the directory if it's not there yet |
203 | rv = file->Create(nsIFile::DIRECTORY_TYPE, 0777); |
204 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && rv != NS_ERROR_FILE_ALREADY_EXISTS) return rv; |
205 | |
206 | rv = file->AppendNative(nsLiteralCString(STARTUP_CACHE_NAME"startupCache." "8" "." "little")); |
207 | |
208 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 208); return rv; } } while (false); |
209 | |
210 | mFile = file; |
211 | } |
212 | |
213 | NS_ENSURE_TRUE(mFile, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(mFile)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mFile" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 213); return NS_ERROR_UNEXPECTED; } } while (false); |
214 | |
215 | mObserverService = do_GetService("@mozilla.org/observer-service;1"); |
216 | |
217 | if (!mObserverService) { |
218 | NS_WARNING("Could not get observerService.")NS_DebugBreak(NS_DEBUG_WARNING, "Could not get observerService." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 218); |
219 | return NS_ERROR_UNEXPECTED; |
220 | } |
221 | |
222 | mListener = new StartupCacheListener(); |
223 | rv = mObserverService->AddObserver(mListener, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", |
224 | false); |
225 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 225); return rv; } } while (false); |
226 | rv = mObserverService->AddObserver(mListener, "startupcache-invalidate", |
227 | false); |
228 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 228); return rv; } } while (false); |
229 | rv = mObserverService->AddObserver(mListener, "intl:app-locales-changed", |
230 | false); |
231 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 231); return rv; } } while (false); |
232 | |
233 | { |
234 | MutexAutoLock lock(mTableLock); |
235 | auto result = LoadArchive(); |
236 | rv = result.isErr() ? result.unwrapErr() : NS_OK; |
237 | } |
238 | |
239 | gFoundDiskCacheOnInit = rv != NS_ERROR_FILE_NOT_FOUND; |
240 | |
241 | // Sometimes we don't have a cache yet, that's ok. |
242 | // If it's corrupted, just remove it and start over. |
243 | if (gIgnoreDiskCache || (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && rv != NS_ERROR_FILE_NOT_FOUND)) { |
244 | NS_WARNING("Failed to load startupcache file correctly, removing!")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to load startupcache file correctly, removing!" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 244); |
245 | InvalidateCache(); |
246 | } |
247 | |
248 | RegisterWeakMemoryReporter(this); |
249 | mDecompressionContext = MakeUnique<LZ4FrameDecompressionContext>(true); |
250 | |
251 | return NS_OK; |
252 | } |
253 | |
254 | void StartupCache::StartPrefetchMemory() { |
255 | { |
256 | MonitorAutoLock lock(mPrefetchComplete); |
257 | mPrefetchInProgress = true; |
258 | } |
259 | NS_DispatchBackgroundTask(NewRunnableMethod<uint8_t*, size_t>( |
260 | "StartupCache::ThreadedPrefetch", this, &StartupCache::ThreadedPrefetch, |
261 | mCacheData.get<uint8_t>().get(), mCacheData.size())); |
262 | } |
263 | |
264 | /** |
265 | * LoadArchive can only be called from the main thread. |
266 | */ |
267 | Result<Ok, nsresult> StartupCache::LoadArchive() { |
268 | MOZ_ASSERT(NS_IsMainThread(), "Can only load startup cache on main thread")do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" " (" "Can only load startup cache on main thread" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 268); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ") (" "Can only load startup cache on main thread" ")"); do { *((volatile int*)__null) = 268; __attribute__((nomerge)) ::abort (); } while (false); } } while (false); |
269 | if (gIgnoreDiskCache) return Err(NS_ERROR_FAILURE); |
270 | |
271 | MOZ_TRY(mCacheData.init(mFile))do { auto mozTryTempResult_ = ::mozilla::ToResult(mCacheData. init(mFile)); if ((__builtin_expect(!!(mozTryTempResult_.isErr ()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0); |
272 | auto size = mCacheData.size(); |
273 | if (CanPrefetchMemory()) { |
274 | StartPrefetchMemory(); |
275 | } |
276 | |
277 | uint32_t headerSize; |
278 | if (size < sizeof(MAGIC) + sizeof(headerSize)) { |
279 | return Err(NS_ERROR_UNEXPECTED); |
280 | } |
281 | |
282 | auto data = mCacheData.get<uint8_t>(); |
283 | auto end = data + size; |
284 | |
285 | MMAP_FAULT_HANDLER_BEGIN_BUFFER(data.get(), size){ MmapAccessScope mmapScope((void*)(data.get()), (size)); if ( __sigsetjmp (mmapScope.mJmpBuf, 0) == 0) { |
286 | |
287 | if (memcmp(MAGIC, data.get(), sizeof(MAGIC))) { |
288 | return Err(NS_ERROR_UNEXPECTED); |
289 | } |
290 | data += sizeof(MAGIC); |
291 | |
292 | headerSize = LittleEndian::readUint32(data.get()); |
293 | data += sizeof(headerSize); |
294 | |
295 | if (headerSize > end - data) { |
296 | MOZ_ASSERT(false, "StartupCache file is corrupt.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "StartupCache file is corrupt." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "StartupCache file is corrupt." ")"); do { *((volatile int*) __null) = 296; __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
297 | return Err(NS_ERROR_UNEXPECTED); |
298 | } |
299 | |
300 | Range<uint8_t> header(data, data + headerSize); |
301 | data += headerSize; |
302 | |
303 | mCacheEntriesBaseOffset = sizeof(MAGIC) + sizeof(headerSize) + headerSize; |
304 | { |
305 | if (!mTable.reserve(STARTUP_CACHE_RESERVE_CAPACITY)) { |
306 | return Err(NS_ERROR_UNEXPECTED); |
307 | } |
308 | auto cleanup = MakeScopeExit([&]() { |
309 | mTableLock.AssertCurrentThreadOwns(); |
310 | WaitOnPrefetch(); |
311 | mTable.clear(); |
312 | mCacheData.reset(); |
313 | }); |
314 | loader::InputBuffer buf(header); |
315 | |
316 | uint32_t currentOffset = 0; |
317 | while (!buf.finished()) { |
318 | uint32_t offset = 0; |
319 | uint32_t compressedSize = 0; |
320 | uint32_t uncompressedSize = 0; |
321 | nsCString key; |
322 | buf.codeUint32(offset); |
323 | buf.codeUint32(compressedSize); |
324 | buf.codeUint32(uncompressedSize); |
325 | buf.codeString(key); |
326 | |
327 | if (offset + compressedSize > end - data) { |
328 | MOZ_ASSERT(false, "StartupCache file is corrupt.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "StartupCache file is corrupt." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 328); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "StartupCache file is corrupt." ")"); do { *((volatile int*) __null) = 328; __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
329 | return Err(NS_ERROR_UNEXPECTED); |
330 | } |
331 | |
332 | // Make sure offsets match what we'd expect based on script ordering and |
333 | // size, as a basic sanity check. |
334 | if (offset != currentOffset) { |
335 | return Err(NS_ERROR_UNEXPECTED); |
336 | } |
337 | currentOffset += compressedSize; |
338 | |
339 | // We could use mTable.putNew if we knew the file we're loading weren't |
340 | // corrupt. However, we don't know that, so check if the key already |
341 | // exists. If it does, we know the file must be corrupt. |
342 | decltype(mTable)::AddPtr p = mTable.lookupForAdd(key); |
343 | if (p) { |
344 | return Err(NS_ERROR_UNEXPECTED); |
345 | } |
346 | |
347 | if (!mTable.add( |
348 | p, key, |
349 | StartupCacheEntry(offset, compressedSize, uncompressedSize))) { |
350 | return Err(NS_ERROR_UNEXPECTED); |
351 | } |
352 | } |
353 | |
354 | if (buf.error()) { |
355 | return Err(NS_ERROR_UNEXPECTED); |
356 | } |
357 | |
358 | cleanup.release(); |
359 | } |
360 | |
361 | MMAP_FAULT_HANDLER_CATCH(Err(NS_ERROR_UNEXPECTED))} else { NS_DebugBreak(NS_DEBUG_WARNING, "SIGBUS received when accessing mmapped file" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 361); return Err(NS_ERROR_UNEXPECTED); } } |
362 | |
363 | return Ok(); |
364 | } |
365 | |
366 | bool StartupCache::HasEntry(const char* id) { |
367 | AUTO_PROFILER_LABEL("StartupCache::HasEntry", OTHER)mozilla::AutoProfilerLabel raiiObject367( "StartupCache::HasEntry" , nullptr, JS::ProfilingCategoryPair::OTHER); |
368 | |
369 | MOZ_ASSERT(NS_IsMainThread(), "Startup cache only available on main thread")do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" " (" "Startup cache only available on main thread" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 369); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ") (" "Startup cache only available on main thread" ")"); do { *((volatile int*)__null) = 369; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
370 | |
371 | MutexAutoLock lock(mTableLock); |
372 | return mTable.has(nsDependentCString(id)); |
373 | } |
374 | |
375 | nsresult StartupCache::GetBuffer(const char* id, const char** outbuf, |
376 | uint32_t* length) |
377 | MOZ_NO_THREAD_SAFETY_ANALYSIS__attribute__((no_thread_safety_analysis)) { |
378 | AUTO_PROFILER_LABEL("StartupCache::GetBuffer", OTHER)mozilla::AutoProfilerLabel raiiObject378( "StartupCache::GetBuffer" , nullptr, JS::ProfilingCategoryPair::OTHER); |
379 | |
380 | NS_ASSERTION(NS_IsMainThread(),do { if (!(NS_IsMainThread())) { NS_DebugBreak(NS_DEBUG_ASSERTION , "Startup cache only available on main thread", "NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 381); MOZ_PretendNoReturn(); } } while (0) |
381 | "Startup cache only available on main thread")do { if (!(NS_IsMainThread())) { NS_DebugBreak(NS_DEBUG_ASSERTION , "Startup cache only available on main thread", "NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 381); MOZ_PretendNoReturn(); } } while (0); |
382 | |
383 | Telemetry::LABELS_STARTUP_CACHE_REQUESTS label = |
384 | Telemetry::LABELS_STARTUP_CACHE_REQUESTS::Miss; |
385 | auto telemetry = |
386 | MakeScopeExit([&label] { Telemetry::AccumulateCategorical(label); }); |
387 | |
388 | MutexAutoLock lock(mTableLock); |
389 | decltype(mTable)::Ptr p = mTable.lookup(nsDependentCString(id)); |
390 | if (!p) { |
391 | return NS_ERROR_NOT_AVAILABLE; |
392 | } |
393 | |
394 | auto& value = p->value(); |
395 | if (value.mData) { |
396 | label = Telemetry::LABELS_STARTUP_CACHE_REQUESTS::HitMemory; |
397 | } else { |
398 | if (!mCacheData.initialized()) { |
399 | return NS_ERROR_NOT_AVAILABLE; |
400 | } |
401 | // It is impossible for a write to be pending here. This is because |
402 | // we just checked mCacheData.initialized(), and this is reset before |
403 | // writing to the cache. It's not re-initialized unless we call |
404 | // LoadArchive(), either from Init() (which must have already happened) or |
405 | // InvalidateCache(). InvalidateCache() locks the mutex, so a write can't be |
406 | // happening. |
407 | // Also, WriteToDisk() requires mTableLock, so while it's writing we can't |
408 | // be here. |
409 | |
410 | size_t totalRead = 0; |
411 | size_t totalWritten = 0; |
412 | Span<const char> compressed = Span( |
413 | mCacheData.get<char>().get() + mCacheEntriesBaseOffset + value.mOffset, |
414 | value.mCompressedSize); |
415 | value.mData = UniqueFreePtr<char[]>(reinterpret_cast<char*>( |
416 | malloc(sizeof(char) * value.mUncompressedSize))); |
417 | Span<char> uncompressed = Span(value.mData.get(), value.mUncompressedSize); |
418 | MMAP_FAULT_HANDLER_BEGIN_BUFFER(uncompressed.Elements(),{ MmapAccessScope mmapScope((void*)(uncompressed.Elements()), (uncompressed.Length())); if (__sigsetjmp (mmapScope.mJmpBuf , 0) == 0) { |
419 | uncompressed.Length()){ MmapAccessScope mmapScope((void*)(uncompressed.Elements()), (uncompressed.Length())); if (__sigsetjmp (mmapScope.mJmpBuf , 0) == 0) { |
420 | bool finished = false; |
421 | while (!finished) { |
422 | auto result = mDecompressionContext->Decompress( |
423 | uncompressed.From(totalWritten), compressed.From(totalRead)); |
424 | if (NS_WARN_IF(result.isErr())NS_warn_if_impl(result.isErr(), "result.isErr()", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 424)) { |
425 | value.mData = nullptr; |
426 | MutexAutoUnlock unlock(mTableLock); |
427 | InvalidateCache(); |
428 | return NS_ERROR_FAILURE; |
429 | } |
430 | auto decompressionResult = result.unwrap(); |
431 | totalRead += decompressionResult.mSizeRead; |
432 | totalWritten += decompressionResult.mSizeWritten; |
433 | finished = decompressionResult.mFinished; |
434 | } |
435 | |
436 | MMAP_FAULT_HANDLER_CATCH(NS_ERROR_FAILURE)} else { NS_DebugBreak(NS_DEBUG_WARNING, "SIGBUS received when accessing mmapped file" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 436); return NS_ERROR_FAILURE; } } |
437 | |
438 | label = Telemetry::LABELS_STARTUP_CACHE_REQUESTS::HitDisk; |
439 | } |
440 | |
441 | if (!value.mRequested) { |
442 | value.mRequested = true; |
443 | value.mRequestedOrder = ++mRequestedCount; |
444 | MOZ_ASSERT(mRequestedCount <= mTable.count(),do { static_assert( mozilla::detail::AssertionConditionType< decltype(mRequestedCount <= mTable.count())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mRequestedCount <= mTable .count()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("mRequestedCount <= mTable.count()" " (" "Somehow we requested more StartupCache items than exist." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRequestedCount <= mTable.count()" ") (" "Somehow we requested more StartupCache items than exist." ")"); do { *((volatile int*)__null) = 445; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
445 | "Somehow we requested more StartupCache items than exist.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(mRequestedCount <= mTable.count())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mRequestedCount <= mTable .count()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("mRequestedCount <= mTable.count()" " (" "Somehow we requested more StartupCache items than exist." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRequestedCount <= mTable.count()" ") (" "Somehow we requested more StartupCache items than exist." ")"); do { *((volatile int*)__null) = 445; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
446 | ResetStartupWriteTimerCheckingReadCount(); |
447 | } |
448 | |
449 | // Track that something holds a reference into mTable, so we know to hold |
450 | // onto it in case the cache is invalidated. |
451 | mCurTableReferenced = true; |
452 | *outbuf = value.mData.get(); |
453 | *length = value.mUncompressedSize; |
454 | return NS_OK; |
455 | } |
456 | |
457 | // Makes a copy of the buffer, client retains ownership of inbuf. |
458 | nsresult StartupCache::PutBuffer(const char* id, UniqueFreePtr<char[]>&& inbuf, |
459 | uint32_t len) MOZ_NO_THREAD_SAFETY_ANALYSIS__attribute__((no_thread_safety_analysis)) { |
460 | NS_ASSERTION(NS_IsMainThread(),do { if (!(NS_IsMainThread())) { NS_DebugBreak(NS_DEBUG_ASSERTION , "Startup cache only available on main thread", "NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 461); MOZ_PretendNoReturn(); } } while (0) |
461 | "Startup cache only available on main thread")do { if (!(NS_IsMainThread())) { NS_DebugBreak(NS_DEBUG_ASSERTION , "Startup cache only available on main thread", "NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 461); MOZ_PretendNoReturn(); } } while (0); |
462 | if (StartupCache::gShutdownInitiated) { |
463 | return NS_ERROR_NOT_AVAILABLE; |
464 | } |
465 | |
466 | // Try to gain the table write lock. If the background task to write the |
467 | // cache is running, this will fail. |
468 | MutexAutoTryLock lock(mTableLock); |
469 | if (!lock) { |
470 | return NS_ERROR_NOT_AVAILABLE; |
471 | } |
472 | mTableLock.AssertCurrentThreadOwns(); |
473 | bool exists = mTable.has(nsDependentCString(id)); |
474 | if (exists) { |
475 | NS_WARNING("Existing entry in StartupCache.")NS_DebugBreak(NS_DEBUG_WARNING, "Existing entry in StartupCache." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 475); |
476 | // Double-caching is undesirable but not an error. |
477 | return NS_OK; |
478 | } |
479 | |
480 | // putNew returns false on alloc failure - in the very unlikely event we hit |
481 | // that and aren't going to crash elsewhere, there's no reason we need to |
482 | // crash here. |
483 | if (mTable.putNew(nsCString(id), StartupCacheEntry(std::move(inbuf), len, |
484 | ++mRequestedCount))) { |
485 | return ResetStartupWriteTimer(); |
486 | } |
487 | MOZ_DIAGNOSTIC_ASSERT(mTable.count() < STARTUP_CACHE_MAX_CAPACITY,do { static_assert( mozilla::detail::AssertionConditionType< decltype(mTable.count() < STARTUP_CACHE_MAX_CAPACITY)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(mTable.count() < STARTUP_CACHE_MAX_CAPACITY))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("mTable.count() < STARTUP_CACHE_MAX_CAPACITY" " (" "Too many StartupCache entries." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 488); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mTable.count() < STARTUP_CACHE_MAX_CAPACITY" ") (" "Too many StartupCache entries." ")"); do { *((volatile int*)__null) = 488; __attribute__((nomerge)) ::abort(); } while (false); } } while (false) |
488 | "Too many StartupCache entries.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(mTable.count() < STARTUP_CACHE_MAX_CAPACITY)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(mTable.count() < STARTUP_CACHE_MAX_CAPACITY))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("mTable.count() < STARTUP_CACHE_MAX_CAPACITY" " (" "Too many StartupCache entries." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 488); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mTable.count() < STARTUP_CACHE_MAX_CAPACITY" ") (" "Too many StartupCache entries." ")"); do { *((volatile int*)__null) = 488; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
489 | return NS_OK; |
490 | } |
491 | |
492 | size_t StartupCache::HeapSizeOfIncludingThis( |
493 | mozilla::MallocSizeOf aMallocSizeOf) const { |
494 | // This function could measure more members, but they haven't been found by |
495 | // DMD to be significant. They can be added later if necessary. |
496 | |
497 | size_t n = aMallocSizeOf(this); |
498 | |
499 | n += mTable.shallowSizeOfExcludingThis(aMallocSizeOf); |
500 | for (auto iter = mTable.iter(); !iter.done(); iter.next()) { |
501 | if (iter.get().value().mData) { |
502 | n += aMallocSizeOf(iter.get().value().mData.get()); |
503 | } |
504 | n += iter.get().key().SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
505 | } |
506 | |
507 | return n; |
508 | } |
509 | |
510 | /** |
511 | * WriteToDisk writes the cache out to disk. Callers of WriteToDisk need to call |
512 | * WaitOnWriteComplete to make sure there isn't a write |
513 | * happening on another thread. |
514 | * We own the mTableLock here. |
515 | */ |
516 | Result<Ok, nsresult> StartupCache::WriteToDisk() { |
517 | if (!mDirty || mWrittenOnce) { |
518 | return Ok(); |
519 | } |
520 | |
521 | if (!mFile) { |
522 | return Err(NS_ERROR_UNEXPECTED); |
523 | } |
524 | |
525 | AutoFDClose raiiFd; |
526 | MOZ_TRY(mFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,do { auto mozTryTempResult_ = ::mozilla::ToResult(mFile->OpenNSPRFileDesc (0x02 | 0x08 | 0x20, 0644, getter_Transfers(raiiFd))); if ((__builtin_expect (!!(mozTryTempResult_.isErr()), 0))) { return mozTryTempResult_ .propagateErr(); } } while (0) |
527 | 0644, getter_Transfers(raiiFd)))do { auto mozTryTempResult_ = ::mozilla::ToResult(mFile->OpenNSPRFileDesc (0x02 | 0x08 | 0x20, 0644, getter_Transfers(raiiFd))); if ((__builtin_expect (!!(mozTryTempResult_.isErr()), 0))) { return mozTryTempResult_ .propagateErr(); } } while (0); |
528 | const auto fd = raiiFd.get(); |
529 | |
530 | nsTArray<StartupCacheEntry::KeyValuePair> entries(mTable.count()); |
531 | for (auto iter = mTable.iter(); !iter.done(); iter.next()) { |
532 | if (iter.get().value().mRequested) { |
533 | StartupCacheEntry::KeyValuePair kv(&iter.get().key(), |
534 | &iter.get().value()); |
535 | entries.AppendElement(kv); |
536 | } |
537 | } |
538 | |
539 | if (entries.IsEmpty()) { |
540 | return Ok(); |
541 | } |
542 | |
543 | entries.Sort(StartupCacheEntry::Comparator()); |
544 | loader::OutputBuffer buf; |
545 | for (auto& e : entries) { |
546 | auto* key = e.first; |
547 | auto* value = e.second; |
548 | auto uncompressedSize = value->mUncompressedSize; |
549 | // Set the mHeaderOffsetInFile so we can go back and edit the offset. |
550 | value->mHeaderOffsetInFile = buf.cursor(); |
551 | // Write a 0 offset/compressed size as a placeholder until we get the real |
552 | // offset after compressing. |
553 | buf.codeUint32(0); |
554 | buf.codeUint32(0); |
555 | buf.codeUint32(uncompressedSize); |
556 | buf.codeString(*key); |
557 | } |
558 | |
559 | uint8_t headerSize[4]; |
560 | LittleEndian::writeUint32(headerSize, buf.cursor()); |
561 | |
562 | MOZ_TRY(Write(fd, MAGIC, sizeof(MAGIC)))do { auto mozTryTempResult_ = ::mozilla::ToResult(Write(fd, MAGIC , sizeof(MAGIC))); if ((__builtin_expect(!!(mozTryTempResult_ .isErr()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0); |
563 | MOZ_TRY(Write(fd, headerSize, sizeof(headerSize)))do { auto mozTryTempResult_ = ::mozilla::ToResult(Write(fd, headerSize , sizeof(headerSize))); if ((__builtin_expect(!!(mozTryTempResult_ .isErr()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0); |
564 | size_t headerStart = sizeof(MAGIC) + sizeof(headerSize); |
565 | size_t dataStart = headerStart + buf.cursor(); |
566 | MOZ_TRY(Seek(fd, dataStart))do { auto mozTryTempResult_ = ::mozilla::ToResult(Seek(fd, dataStart )); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0); |
567 | |
568 | size_t offset = 0; |
569 | |
570 | const size_t chunkSize = 1024 * 16; |
571 | LZ4FrameCompressionContext ctx(6, /* aCompressionLevel */ |
572 | chunkSize, /* aReadBufLen */ |
573 | true, /* aChecksum */ |
574 | true); /* aStableSrc */ |
575 | size_t writeBufLen = ctx.GetRequiredWriteBufferLength(); |
576 | auto writeBuffer = MakeUnique<char[]>(writeBufLen); |
577 | auto writeSpan = Span(writeBuffer.get(), writeBufLen); |
578 | |
579 | for (auto& e : entries) { |
580 | auto value = e.second; |
581 | value->mOffset = offset; |
582 | Span<const char> result; |
583 | MOZ_TRY_VAR(result,do { auto mozTryVarTempResult_ = (ctx.BeginCompressing(writeSpan ).mapErr(MapLZ4ErrorToNsresult)); if ((__builtin_expect(!!(mozTryVarTempResult_ .isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (result) = mozTryVarTempResult_.unwrap(); } while (0) |
584 | ctx.BeginCompressing(writeSpan).mapErr(MapLZ4ErrorToNsresult))do { auto mozTryVarTempResult_ = (ctx.BeginCompressing(writeSpan ).mapErr(MapLZ4ErrorToNsresult)); if ((__builtin_expect(!!(mozTryVarTempResult_ .isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (result) = mozTryVarTempResult_.unwrap(); } while (0); |
585 | MOZ_TRY(Write(fd, result.Elements(), result.Length()))do { auto mozTryTempResult_ = ::mozilla::ToResult(Write(fd, result .Elements(), result.Length())); if ((__builtin_expect(!!(mozTryTempResult_ .isErr()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0); |
586 | offset += result.Length(); |
587 | |
588 | for (size_t i = 0; i < value->mUncompressedSize; i += chunkSize) { |
589 | size_t size = std::min(chunkSize, value->mUncompressedSize - i); |
590 | char* uncompressed = value->mData.get() + i; |
591 | MOZ_TRY_VAR(result, ctx.ContinueCompressing(Span(uncompressed, size))do { auto mozTryVarTempResult_ = (ctx.ContinueCompressing(Span (uncompressed, size)) .mapErr(MapLZ4ErrorToNsresult)); if ((__builtin_expect (!!(mozTryVarTempResult_.isErr()), 0))) { return mozTryVarTempResult_ .propagateErr(); } (result) = mozTryVarTempResult_.unwrap(); } while (0) |
592 | .mapErr(MapLZ4ErrorToNsresult))do { auto mozTryVarTempResult_ = (ctx.ContinueCompressing(Span (uncompressed, size)) .mapErr(MapLZ4ErrorToNsresult)); if ((__builtin_expect (!!(mozTryVarTempResult_.isErr()), 0))) { return mozTryVarTempResult_ .propagateErr(); } (result) = mozTryVarTempResult_.unwrap(); } while (0); |
593 | MOZ_TRY(Write(fd, result.Elements(), result.Length()))do { auto mozTryTempResult_ = ::mozilla::ToResult(Write(fd, result .Elements(), result.Length())); if ((__builtin_expect(!!(mozTryTempResult_ .isErr()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0); |
594 | offset += result.Length(); |
595 | } |
596 | |
597 | MOZ_TRY_VAR(result, ctx.EndCompressing().mapErr(MapLZ4ErrorToNsresult))do { auto mozTryVarTempResult_ = (ctx.EndCompressing().mapErr (MapLZ4ErrorToNsresult)); if ((__builtin_expect(!!(mozTryVarTempResult_ .isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (result) = mozTryVarTempResult_.unwrap(); } while (0); |
598 | MOZ_TRY(Write(fd, result.Elements(), result.Length()))do { auto mozTryTempResult_ = ::mozilla::ToResult(Write(fd, result .Elements(), result.Length())); if ((__builtin_expect(!!(mozTryTempResult_ .isErr()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0); |
599 | offset += result.Length(); |
600 | value->mCompressedSize = offset - value->mOffset; |
601 | MOZ_TRY(Seek(fd, dataStart + offset))do { auto mozTryTempResult_ = ::mozilla::ToResult(Seek(fd, dataStart + offset)); if ((__builtin_expect(!!(mozTryTempResult_.isErr ()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0); |
602 | } |
603 | |
604 | for (auto& e : entries) { |
605 | auto value = e.second; |
606 | uint8_t* headerEntry = buf.Get() + value->mHeaderOffsetInFile; |
607 | LittleEndian::writeUint32(headerEntry, value->mOffset); |
608 | LittleEndian::writeUint32(headerEntry + sizeof(value->mOffset), |
609 | value->mCompressedSize); |
610 | } |
611 | MOZ_TRY(Seek(fd, headerStart))do { auto mozTryTempResult_ = ::mozilla::ToResult(Seek(fd, headerStart )); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0); |
612 | MOZ_TRY(Write(fd, buf.Get(), buf.cursor()))do { auto mozTryTempResult_ = ::mozilla::ToResult(Write(fd, buf .Get(), buf.cursor())); if ((__builtin_expect(!!(mozTryTempResult_ .isErr()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0); |
613 | |
614 | mDirty = false; |
615 | mWrittenOnce = true; |
616 | |
617 | return Ok(); |
618 | } |
619 | |
620 | void StartupCache::InvalidateCache(bool memoryOnly) { |
621 | WaitOnPrefetch(); |
622 | // Ensure we're not writing using mTable... |
623 | MutexAutoLock lock(mTableLock); |
624 | |
625 | mWrittenOnce = false; |
626 | if (memoryOnly) { |
627 | // This should only be called in tests. |
628 | auto writeResult = WriteToDisk(); |
629 | if (NS_WARN_IF(writeResult.isErr())NS_warn_if_impl(writeResult.isErr(), "writeResult.isErr()", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 629)) { |
630 | gIgnoreDiskCache = true; |
631 | return; |
632 | } |
633 | } |
634 | if (mCurTableReferenced) { |
635 | // There should be no way for this assert to fail other than a user manually |
636 | // sending startupcache-invalidate messages through the Browser Toolbox. If |
637 | // something knowingly invalidates the cache, the event can be counted with |
638 | // mAllowedInvalidationsCount. |
639 | MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10)>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" " (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" ") (" "Startup cache invalidated too many times." ")"); do { *((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort (); } while (false); } } while (false) |
640 | xpc::IsInAutomation() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10)>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" " (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" ") (" "Startup cache invalidated too many times." ")"); do { *((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort (); } while (false); } } while (false) |
641 | // The allowed invalidations can grow faster than the old tables, sodo { static_assert( mozilla::detail::AssertionConditionType< decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10)>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" " (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" ") (" "Startup cache invalidated too many times." ")"); do { *((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort (); } while (false); } } while (false) |
642 | // guard against incorrect unsigned subtraction.do { static_assert( mozilla::detail::AssertionConditionType< decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10)>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" " (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" ") (" "Startup cache invalidated too many times." ")"); do { *((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort (); } while (false); } } while (false) |
643 | mAllowedInvalidationsCount > mOldTables.Length() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10)>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" " (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" ") (" "Startup cache invalidated too many times." ")"); do { *((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort (); } while (false); } } while (false) |
644 | // Now perform the real check.do { static_assert( mozilla::detail::AssertionConditionType< decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10)>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" " (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" ") (" "Startup cache invalidated too many times." ")"); do { *((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort (); } while (false); } } while (false) |
645 | mOldTables.Length() - mAllowedInvalidationsCount < 10,do { static_assert( mozilla::detail::AssertionConditionType< decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10)>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" " (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" ") (" "Startup cache invalidated too many times." ")"); do { *((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort (); } while (false); } } while (false) |
646 | "Startup cache invalidated too many times.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10)>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" " (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10" ") (" "Startup cache invalidated too many times." ")"); do { *((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort (); } while (false); } } while (false); |
647 | mOldTables.AppendElement(std::move(mTable)); |
648 | mCurTableReferenced = false; |
649 | } else { |
650 | mTable.clear(); |
651 | } |
652 | mRequestedCount = 0; |
653 | if (!memoryOnly) { |
654 | mCacheData.reset(); |
655 | nsresult rv = mFile->Remove(false); |
656 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && rv != NS_ERROR_FILE_NOT_FOUND) { |
657 | gIgnoreDiskCache = true; |
658 | return; |
659 | } |
660 | } |
661 | gIgnoreDiskCache = false; |
662 | auto result = LoadArchive(); |
663 | if (NS_WARN_IF(result.isErr())NS_warn_if_impl(result.isErr(), "result.isErr()", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 663)) { |
664 | gIgnoreDiskCache = true; |
665 | } |
666 | } |
667 | |
668 | void StartupCache::CountAllowedInvalidation() { mAllowedInvalidationsCount++; } |
669 | |
670 | void StartupCache::MaybeInitShutdownWrite() { |
671 | if (mTimer) { |
672 | mTimer->Cancel(); |
673 | } |
674 | gShutdownInitiated = true; |
675 | |
676 | MaybeWriteOffMainThread(); |
677 | } |
678 | |
679 | void StartupCache::EnsureShutdownWriteComplete() { |
680 | MutexAutoLock lock(mTableLock); |
681 | // If we've already written or there's nothing to write, |
682 | // we don't need to do anything. This is the common case. |
683 | if (mWrittenOnce || (mCacheData.initialized() && !ShouldCompactCache())) { |
684 | return; |
685 | } |
686 | // Otherwise, ensure the write happens. The timer should have been cancelled |
687 | // already in MaybeInitShutdownWrite. |
688 | |
689 | // We got the lock. Keep the following in sync with |
690 | // MaybeWriteOffMainThread: |
691 | WaitOnPrefetch(); |
692 | mDirty = true; |
693 | mCacheData.reset(); |
694 | // Most of this should be redundant given MaybeWriteOffMainThread should |
695 | // have run before now. |
696 | |
697 | auto writeResult = WriteToDisk(); |
698 | Unused << NS_WARN_IF(writeResult.isErr())NS_warn_if_impl(writeResult.isErr(), "writeResult.isErr()", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 698); |
699 | // We've had the lock, and `WriteToDisk()` sets mWrittenOnce and mDirty |
700 | // when done, and checks for them when starting, so we don't need to do |
701 | // anything else. |
702 | } |
703 | |
704 | void StartupCache::IgnoreDiskCache() { |
705 | gIgnoreDiskCache = true; |
706 | if (gStartupCache) gStartupCache->InvalidateCache(); |
707 | } |
708 | |
709 | bool StartupCache::GetIgnoreDiskCache() { return gIgnoreDiskCache; } |
710 | |
711 | void StartupCache::WaitOnPrefetch() { |
712 | // This can't be called from within ThreadedPrefetch() |
713 | MonitorAutoLock lock(mPrefetchComplete); |
714 | while (mPrefetchInProgress) { |
715 | mPrefetchComplete.Wait(); |
716 | } |
717 | } |
718 | |
719 | void StartupCache::ThreadedPrefetch(uint8_t* aStart, size_t aSize) { |
720 | // Always notify of completion, even if MMAP_FAULT_HANDLER_CATCH() |
721 | // early-returns. |
722 | auto notifyPrefetchComplete = MakeScopeExit([&] { |
723 | MonitorAutoLock lock(mPrefetchComplete); |
724 | mPrefetchInProgress = false; |
725 | mPrefetchComplete.NotifyAll(); |
726 | }); |
727 | |
728 | // PrefetchMemory does madvise/equivalent, but doesn't access the memory |
729 | // pointed to by aStart |
730 | MMAP_FAULT_HANDLER_BEGIN_BUFFER(aStart, aSize){ MmapAccessScope mmapScope((void*)(aStart), (aSize)); if (__sigsetjmp (mmapScope.mJmpBuf, 0) == 0) { |
731 | PrefetchMemory(aStart, aSize); |
732 | MMAP_FAULT_HANDLER_CATCH()} else { NS_DebugBreak(NS_DEBUG_WARNING, "SIGBUS received when accessing mmapped file" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 732); return ; } } |
733 | } |
734 | |
735 | // mTableLock must be held |
736 | bool StartupCache::ShouldCompactCache() { |
737 | // If we've requested less than 4/5 of the startup cache, then we should |
738 | // probably compact it down. This can happen quite easily after the first run, |
739 | // which seems to request quite a few more things than subsequent runs. |
740 | CheckedInt<uint32_t> threshold = CheckedInt<uint32_t>(mTable.count()) * 4 / 5; |
741 | MOZ_RELEASE_ASSERT(threshold.isValid(), "Runaway StartupCache size")do { static_assert( mozilla::detail::AssertionConditionType< decltype(threshold.isValid())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(threshold.isValid()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("threshold.isValid()" " (" "Runaway StartupCache size" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 741); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "threshold.isValid()" ") (" "Runaway StartupCache size" ")"); do { *((volatile int *)__null) = 741; __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
742 | return mRequestedCount < threshold.value(); |
743 | } |
744 | |
745 | /* |
746 | * The write-thread is spawned on a timeout(which is reset with every write). |
747 | * This can avoid a slow shutdown. |
748 | */ |
749 | void StartupCache::WriteTimeout(nsITimer* aTimer, void* aClosure) { |
750 | /* |
751 | * It is safe to use the pointer passed in aClosure to reference the |
752 | * StartupCache object because the timer's lifetime is tightly coupled to |
753 | * the lifetime of the StartupCache object; this timer is canceled in the |
754 | * StartupCache destructor, guaranteeing that this function runs if and only |
755 | * if the StartupCache object is valid. |
756 | */ |
757 | StartupCache* startupCacheObj = static_cast<StartupCache*>(aClosure); |
758 | startupCacheObj->MaybeWriteOffMainThread(); |
759 | } |
760 | |
761 | /* |
762 | * See StartupCache::WriteTimeout above - this is just the non-static body. |
763 | */ |
764 | void StartupCache::MaybeWriteOffMainThread() { |
765 | { |
766 | MutexAutoLock lock(mTableLock); |
767 | if (mWrittenOnce || (mCacheData.initialized() && !ShouldCompactCache())) { |
768 | return; |
769 | } |
770 | } |
771 | // Keep this code in sync with EnsureShutdownWriteComplete. |
772 | WaitOnPrefetch(); |
773 | { |
774 | MutexAutoLock lock(mTableLock); |
775 | mDirty = true; |
776 | mCacheData.reset(); |
777 | } |
778 | |
779 | RefPtr<StartupCache> self = this; |
780 | nsCOMPtr<nsIRunnable> runnable = |
781 | NS_NewRunnableFunction("StartupCache::Write", [self]() mutable { |
782 | MutexAutoLock lock(self->mTableLock); |
783 | auto result = self->WriteToDisk(); |
784 | Unused << NS_WARN_IF(result.isErr())NS_warn_if_impl(result.isErr(), "result.isErr()", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 784); |
785 | }); |
786 | NS_DispatchBackgroundTask(runnable.forget(), NS_DISPATCH_EVENT_MAY_BLOCKnsIEventTarget::DISPATCH_EVENT_MAY_BLOCK); |
787 | } |
788 | |
789 | // We don't want to refcount StartupCache, so we'll just |
790 | // hold a ref to this and pass it to observerService instead. |
791 | NS_IMPL_ISUPPORTS(StartupCacheListener, nsIObserver)MozExternalRefCountType StartupCacheListener::AddRef(void) { static_assert (!std::is_destructible_v<StartupCacheListener>, "Reference-counted class " "StartupCacheListener" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 791); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 791; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("StartupCacheListener" != nullptr)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !("StartupCacheListener" != nullptr))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("\"StartupCacheListener\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 791); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCacheListener\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 791; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("StartupCacheListener" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("StartupCacheListener" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType StartupCacheListener::Release(void) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 791); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 791 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("StartupCacheListener" != nullptr)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !("StartupCacheListener" != nullptr))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("\"StartupCacheListener\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 791); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCacheListener\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 791; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("StartupCacheListener" " not thread-safe"); const char* const nametmp = "StartupCacheListener"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if ( count == 0) { mRefCnt = 1; delete (this); return 0; } return count ; } nsresult StartupCacheListener::QueryInterface(const nsIID & aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 791); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<StartupCacheListener, nsIObserver>, int32_t ( reinterpret_cast<char*>(static_cast<nsIObserver*> ((StartupCacheListener*)0x1000)) - reinterpret_cast<char*> ((StartupCacheListener*)0x1000))}, {&mozilla::detail::kImplementedIID <StartupCacheListener, nsISupports>, int32_t(reinterpret_cast <char*>(static_cast<nsISupports*>( static_cast< nsIObserver*>((StartupCacheListener*)0x1000))) - reinterpret_cast <char*>((StartupCacheListener*)0x1000))}, { nullptr, 0 } } ; static_assert((sizeof(table) / sizeof(table[0])) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast <void*>(this), aIID, aInstancePtr, table); return rv; } |
792 | |
793 | nsresult StartupCacheListener::Observe(nsISupports* subject, const char* topic, |
794 | const char16_t* data) { |
795 | StartupCache* sc = StartupCache::GetSingleton(); |
796 | if (!sc) return NS_OK; |
797 | |
798 | if (strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown") == 0) { |
799 | // Do not leave the thread running past xpcom shutdown |
800 | sc->WaitOnPrefetch(); |
801 | StartupCache::gShutdownInitiated = true; |
802 | // Note that we don't do anything special for the background write |
803 | // task; we expect the threadpool to finish running any tasks already |
804 | // posted to it prior to shutdown. FastShutdown will call |
805 | // EnsureShutdownWriteComplete() to ensure any pending writes happen |
806 | // in that case. |
807 | } else if (strcmp(topic, "startupcache-invalidate") == 0) { |
808 | sc->InvalidateCache(data && nsCRT::strcmp(data, u"memoryOnly") == 0); |
809 | } else if (strcmp(topic, "intl:app-locales-changed") == 0) { |
810 | // Live language switching invalidates the startup cache due to the history |
811 | // sidebar retaining localized strings in its internal SQL query. This |
812 | // should be a relatively rare event, but a user could do it an arbitrary |
813 | // number of times. |
814 | sc->CountAllowedInvalidation(); |
815 | } |
816 | return NS_OK; |
817 | } |
818 | |
819 | nsresult StartupCache::GetDebugObjectOutputStream( |
820 | nsIObjectOutputStream* aStream, nsIObjectOutputStream** aOutStream) { |
821 | NS_ENSURE_ARG_POINTER(aStream)do { if ((__builtin_expect(!!(!(aStream)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStream" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 821); return NS_ERROR_INVALID_POINTER; } } while (false); |
822 | #ifdef DEBUG1 |
823 | auto* stream = new StartupCacheDebugOutputStream(aStream, &mWriteObjectMap); |
824 | NS_ADDREF(*aOutStream = stream)(*aOutStream = stream)->AddRef(); |
825 | #else |
826 | NS_ADDREF(*aOutStream = aStream)(*aOutStream = aStream)->AddRef(); |
827 | #endif |
828 | |
829 | return NS_OK; |
830 | } |
831 | |
832 | nsresult StartupCache::ResetStartupWriteTimerCheckingReadCount() { |
833 | nsresult rv = NS_OK; |
834 | if (!mTimer) |
835 | mTimer = NS_NewTimer(); |
836 | else |
837 | rv = mTimer->Cancel(); |
838 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 838); return rv; } } while (false); |
839 | // Wait for the specified timeout, then write out the cache. |
840 | mTimer->InitWithNamedFuncCallback( |
841 | StartupCache::WriteTimeout, this, STARTUP_CACHE_WRITE_TIMEOUT * 1000, |
842 | nsITimer::TYPE_ONE_SHOT, "StartupCache::WriteTimeout"); |
843 | return NS_OK; |
844 | } |
845 | |
846 | // For test code only |
847 | nsresult StartupCache::ResetStartupWriteTimerAndLock() { |
848 | MutexAutoLock lock(mTableLock); |
849 | return ResetStartupWriteTimer(); |
850 | } |
851 | |
852 | nsresult StartupCache::ResetStartupWriteTimer() { |
853 | mDirty = true; |
854 | nsresult rv = NS_OK; |
855 | if (!mTimer) |
856 | mTimer = NS_NewTimer(); |
857 | else |
858 | rv = mTimer->Cancel(); |
859 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 859); return rv; } } while (false); |
860 | // Wait for the specified timeout, then write out the cache. |
861 | mTimer->InitWithNamedFuncCallback( |
862 | StartupCache::WriteTimeout, this, STARTUP_CACHE_WRITE_TIMEOUT * 1000, |
863 | nsITimer::TYPE_ONE_SHOT, "StartupCache::WriteTimeout"); |
864 | return NS_OK; |
865 | } |
866 | |
867 | // Used only in tests: |
868 | bool StartupCache::StartupWriteComplete() { |
869 | // Need to have written to disk and not added new things since; |
870 | MutexAutoLock lock(mTableLock); |
871 | return !mDirty && mWrittenOnce; |
872 | } |
873 | |
874 | // StartupCacheDebugOutputStream implementation |
875 | #ifdef DEBUG1 |
876 | NS_IMPL_ISUPPORTS(StartupCacheDebugOutputStream, nsIObjectOutputStream,MozExternalRefCountType StartupCacheDebugOutputStream::AddRef (void) { static_assert(!std::is_destructible_v<StartupCacheDebugOutputStream >, "Reference-counted class " "StartupCacheDebugOutputStream" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 877; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("StartupCacheDebugOutputStream" != nullptr)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!("StartupCacheDebugOutputStream" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"StartupCacheDebugOutputStream\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCacheDebugOutputStream\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 877; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("StartupCacheDebugOutputStream" " not thread-safe" ); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ( "StartupCacheDebugOutputStream"), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType StartupCacheDebugOutputStream ::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 877 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("StartupCacheDebugOutputStream" != nullptr)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!("StartupCacheDebugOutputStream" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"StartupCacheDebugOutputStream\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCacheDebugOutputStream\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 877; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("StartupCacheDebugOutputStream" " not thread-safe" ); const char* const nametmp = "StartupCacheDebugOutputStream" ; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), ( nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult StartupCacheDebugOutputStream:: QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 877); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(3 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<StartupCacheDebugOutputStream, nsIObjectOutputStream >, int32_t( reinterpret_cast<char*>(static_cast<nsIObjectOutputStream *>((StartupCacheDebugOutputStream*)0x1000)) - reinterpret_cast <char*>((StartupCacheDebugOutputStream*)0x1000))}, {& mozilla::detail::kImplementedIID<StartupCacheDebugOutputStream , nsIBinaryOutputStream>, int32_t( reinterpret_cast<char *>(static_cast<nsIBinaryOutputStream*>((StartupCacheDebugOutputStream *)0x1000)) - reinterpret_cast<char*>((StartupCacheDebugOutputStream *)0x1000))}, {&mozilla::detail::kImplementedIID<StartupCacheDebugOutputStream , nsIOutputStream>, int32_t( reinterpret_cast<char*> (static_cast<nsIOutputStream*>((StartupCacheDebugOutputStream *)0x1000)) - reinterpret_cast<char*>((StartupCacheDebugOutputStream *)0x1000))}, {&mozilla::detail::kImplementedIID<StartupCacheDebugOutputStream , nsISupports>, int32_t(reinterpret_cast<char*>(static_cast <nsISupports*>( static_cast<nsIObjectOutputStream*> ((StartupCacheDebugOutputStream*)0x1000))) - reinterpret_cast <char*>((StartupCacheDebugOutputStream*)0x1000))}, { nullptr , 0 } } ; static_assert((sizeof(table) / sizeof(table[0])) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast <void*>(this), aIID, aInstancePtr, table); return rv; } |
877 | nsIBinaryOutputStream, nsIOutputStream)MozExternalRefCountType StartupCacheDebugOutputStream::AddRef (void) { static_assert(!std::is_destructible_v<StartupCacheDebugOutputStream >, "Reference-counted class " "StartupCacheDebugOutputStream" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 877; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("StartupCacheDebugOutputStream" != nullptr)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!("StartupCacheDebugOutputStream" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"StartupCacheDebugOutputStream\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCacheDebugOutputStream\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 877; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("StartupCacheDebugOutputStream" " not thread-safe" ); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ( "StartupCacheDebugOutputStream"), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType StartupCacheDebugOutputStream ::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 877 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("StartupCacheDebugOutputStream" != nullptr)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!("StartupCacheDebugOutputStream" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"StartupCacheDebugOutputStream\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCacheDebugOutputStream\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 877; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("StartupCacheDebugOutputStream" " not thread-safe" ); const char* const nametmp = "StartupCacheDebugOutputStream" ; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), ( nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult StartupCacheDebugOutputStream:: QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 877); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(3 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<StartupCacheDebugOutputStream, nsIObjectOutputStream >, int32_t( reinterpret_cast<char*>(static_cast<nsIObjectOutputStream *>((StartupCacheDebugOutputStream*)0x1000)) - reinterpret_cast <char*>((StartupCacheDebugOutputStream*)0x1000))}, {& mozilla::detail::kImplementedIID<StartupCacheDebugOutputStream , nsIBinaryOutputStream>, int32_t( reinterpret_cast<char *>(static_cast<nsIBinaryOutputStream*>((StartupCacheDebugOutputStream *)0x1000)) - reinterpret_cast<char*>((StartupCacheDebugOutputStream *)0x1000))}, {&mozilla::detail::kImplementedIID<StartupCacheDebugOutputStream , nsIOutputStream>, int32_t( reinterpret_cast<char*> (static_cast<nsIOutputStream*>((StartupCacheDebugOutputStream *)0x1000)) - reinterpret_cast<char*>((StartupCacheDebugOutputStream *)0x1000))}, {&mozilla::detail::kImplementedIID<StartupCacheDebugOutputStream , nsISupports>, int32_t(reinterpret_cast<char*>(static_cast <nsISupports*>( static_cast<nsIObjectOutputStream*> ((StartupCacheDebugOutputStream*)0x1000))) - reinterpret_cast <char*>((StartupCacheDebugOutputStream*)0x1000))}, { nullptr , 0 } } ; static_assert((sizeof(table) / sizeof(table[0])) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast <void*>(this), aIID, aInstancePtr, table); return rv; } |
878 | |
879 | bool StartupCacheDebugOutputStream::CheckReferences(nsISupports* aObject) { |
880 | nsresult rv; |
881 | |
882 | nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(aObject); |
883 | if (!classInfo) { |
884 | NS_ERROR("aObject must implement nsIClassInfo")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "aObject must implement nsIClassInfo" , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 884); MOZ_PretendNoReturn(); } while (0); |
885 | return false; |
886 | } |
887 | |
888 | uint32_t flags; |
889 | rv = classInfo->GetFlags(&flags); |
890 | NS_ENSURE_SUCCESS(rv, false)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "false", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 890); return false; } } while (false); |
891 | if (flags & nsIClassInfo::SINGLETON) return true; |
892 | |
893 | bool inserted = mObjectMap->EnsureInserted(aObject); |
894 | if (!inserted) { |
895 | NS_ERROR(do { NS_DebugBreak(NS_DEBUG_ASSERTION, "non-singleton aObject is referenced multiple times in this" "serialization, we don't support that.", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 897); MOZ_PretendNoReturn(); } while (0) |
896 | "non-singleton aObject is referenced multiple times in this"do { NS_DebugBreak(NS_DEBUG_ASSERTION, "non-singleton aObject is referenced multiple times in this" "serialization, we don't support that.", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 897); MOZ_PretendNoReturn(); } while (0) |
897 | "serialization, we don't support that.")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "non-singleton aObject is referenced multiple times in this" "serialization, we don't support that.", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 897); MOZ_PretendNoReturn(); } while (0); |
898 | } |
899 | |
900 | return inserted; |
901 | } |
902 | |
903 | // nsIObjectOutputStream implementation |
904 | nsresult StartupCacheDebugOutputStream::WriteObject(nsISupports* aObject, |
905 | bool aIsStrongRef) { |
906 | nsCOMPtr<nsISupports> rootObject(do_QueryInterface(aObject)); |
907 | |
908 | NS_ASSERTION(rootObject.get() == aObject,do { if (!(rootObject.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "bad call to WriteObject -- call WriteCompoundObject!", "rootObject.get() == aObject" , "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 909); MOZ_PretendNoReturn(); } } while (0) |
909 | "bad call to WriteObject -- call WriteCompoundObject!")do { if (!(rootObject.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "bad call to WriteObject -- call WriteCompoundObject!", "rootObject.get() == aObject" , "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 909); MOZ_PretendNoReturn(); } } while (0); |
910 | bool check = CheckReferences(aObject); |
911 | NS_ENSURE_TRUE(check, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(check)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "check" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 911); return NS_ERROR_FAILURE; } } while (false); |
912 | return mBinaryStream->WriteObject(aObject, aIsStrongRef); |
913 | } |
914 | |
915 | nsresult StartupCacheDebugOutputStream::WriteSingleRefObject( |
916 | nsISupports* aObject) { |
917 | nsCOMPtr<nsISupports> rootObject(do_QueryInterface(aObject)); |
918 | |
919 | NS_ASSERTION(rootObject.get() == aObject,do { if (!(rootObject.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "bad call to WriteSingleRefObject -- call WriteCompoundObject!" , "rootObject.get() == aObject", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 920); MOZ_PretendNoReturn(); } } while (0) |
920 | "bad call to WriteSingleRefObject -- call WriteCompoundObject!")do { if (!(rootObject.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "bad call to WriteSingleRefObject -- call WriteCompoundObject!" , "rootObject.get() == aObject", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 920); MOZ_PretendNoReturn(); } } while (0); |
921 | bool check = CheckReferences(aObject); |
922 | NS_ENSURE_TRUE(check, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(check)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "check" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 922); return NS_ERROR_FAILURE; } } while (false); |
923 | return mBinaryStream->WriteSingleRefObject(aObject); |
924 | } |
925 | |
926 | nsresult StartupCacheDebugOutputStream::WriteCompoundObject( |
927 | nsISupports* aObject, const nsIID& aIID, bool aIsStrongRef) { |
928 | nsCOMPtr<nsISupports> rootObject(do_QueryInterface(aObject)); |
929 | |
930 | nsCOMPtr<nsISupports> roundtrip; |
931 | rootObject->QueryInterface(aIID, getter_AddRefs(roundtrip)); |
932 | NS_ASSERTION(roundtrip.get() == aObject,do { if (!(roundtrip.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "bad aggregation or multiple inheritance detected by call to " "WriteCompoundObject!", "roundtrip.get() == aObject", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 934); MOZ_PretendNoReturn(); } } while (0) |
933 | "bad aggregation or multiple inheritance detected by call to "do { if (!(roundtrip.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "bad aggregation or multiple inheritance detected by call to " "WriteCompoundObject!", "roundtrip.get() == aObject", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 934); MOZ_PretendNoReturn(); } } while (0) |
934 | "WriteCompoundObject!")do { if (!(roundtrip.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "bad aggregation or multiple inheritance detected by call to " "WriteCompoundObject!", "roundtrip.get() == aObject", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 934); MOZ_PretendNoReturn(); } } while (0); |
935 | |
936 | bool check = CheckReferences(aObject); |
937 | NS_ENSURE_TRUE(check, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(check)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "check" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp" , 937); return NS_ERROR_FAILURE; } } while (false); |
938 | return mBinaryStream->WriteCompoundObject(aObject, aIID, aIsStrongRef); |
939 | } |
940 | |
941 | nsresult StartupCacheDebugOutputStream::WriteID(nsID const& aID) { |
942 | return mBinaryStream->WriteID(aID); |
943 | } |
944 | |
945 | char* StartupCacheDebugOutputStream::GetBuffer(uint32_t aLength, |
946 | uint32_t aAlignMask) { |
947 | return mBinaryStream->GetBuffer(aLength, aAlignMask); |
948 | } |
949 | |
950 | void StartupCacheDebugOutputStream::PutBuffer(char* aBuffer, uint32_t aLength) { |
951 | mBinaryStream->PutBuffer(aBuffer, aLength); |
952 | } |
953 | #endif // DEBUG |
954 | |
955 | } // namespace scache |
956 | } // namespace mozilla |