File: | var/lib/jenkins/workspace/firefox-scan-build/dom/xul/nsXULPrototypeCache.cpp |
Warning: | line 124, 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 "nsXULPrototypeCache.h" |
8 | |
9 | #include "nsXULPrototypeDocument.h" |
10 | #include "nsIURI.h" |
11 | #include "nsNetUtil.h" |
12 | |
13 | #include "nsIFile.h" |
14 | #include "nsIMemoryReporter.h" |
15 | #include "nsIObjectInputStream.h" |
16 | #include "nsIObjectOutputStream.h" |
17 | #include "nsIObserverService.h" |
18 | #include "nsIStorageStream.h" |
19 | |
20 | #include "nsAppDirectoryServiceDefs.h" |
21 | |
22 | #include "js/experimental/JSStencil.h" |
23 | #include "js/TracingAPI.h" |
24 | |
25 | #include "mozilla/StyleSheetInlines.h" |
26 | #include "mozilla/Preferences.h" |
27 | #include "mozilla/StaticPrefs_nglayout.h" |
28 | #include "mozilla/scache/StartupCache.h" |
29 | #include "mozilla/scache/StartupCacheUtils.h" |
30 | #include "mozilla/Telemetry.h" |
31 | #include "mozilla/RefPtr.h" |
32 | #include "mozilla/UniquePtrExtensions.h" |
33 | #include "mozilla/intl/LocaleService.h" |
34 | |
35 | using namespace mozilla; |
36 | using namespace mozilla::scache; |
37 | using mozilla::intl::LocaleService; |
38 | |
39 | static const char kXULCacheInfoKey[] = "nsXULPrototypeCache.startupCache"; |
40 | #define CACHE_PREFIX(aCompilationTarget)"xulcache/" aCompilationTarget "xulcache/" aCompilationTarget |
41 | |
42 | static void DisableXULCacheChangedCallback(const char* aPref, void* aClosure) { |
43 | if (nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance()) { |
44 | if (!cache->IsEnabled()) { |
45 | // AbortCaching() calls Flush() for us. |
46 | cache->AbortCaching(); |
47 | } |
48 | } |
49 | } |
50 | |
51 | //---------------------------------------------------------------------- |
52 | |
53 | nsXULPrototypeCache* nsXULPrototypeCache::sInstance = nullptr; |
54 | |
55 | nsXULPrototypeCache::nsXULPrototypeCache() = default; |
56 | |
57 | NS_IMPL_ISUPPORTS(nsXULPrototypeCache, nsIObserver)MozExternalRefCountType nsXULPrototypeCache::AddRef(void) { static_assert (!std::is_destructible_v<nsXULPrototypeCache>, "Reference-counted class " "nsXULPrototypeCache" " 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/dom/xul/nsXULPrototypeCache.cpp" , 57); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 57; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsXULPrototypeCache" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsXULPrototypeCache" != nullptr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "\"nsXULPrototypeCache\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/xul/nsXULPrototypeCache.cpp" , 57); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsXULPrototypeCache\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 57; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership ("nsXULPrototypeCache" " not thread-safe"); nsrefcnt count = ++ mRefCnt; NS_LogAddRef((this), (count), ("nsXULPrototypeCache" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsXULPrototypeCache::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/dom/xul/nsXULPrototypeCache.cpp" , 57); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 57 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsXULPrototypeCache" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsXULPrototypeCache" != nullptr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "\"nsXULPrototypeCache\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/xul/nsXULPrototypeCache.cpp" , 57); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsXULPrototypeCache\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 57; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership ("nsXULPrototypeCache" " not thread-safe"); const char* const nametmp = "nsXULPrototypeCache"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsXULPrototypeCache::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/dom/xul/nsXULPrototypeCache.cpp" , 57); 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<nsXULPrototypeCache, nsIObserver>, int32_t ( reinterpret_cast<char*>(static_cast<nsIObserver*> ((nsXULPrototypeCache*)0x1000)) - reinterpret_cast<char*> ((nsXULPrototypeCache*)0x1000))}, {&mozilla::detail::kImplementedIID <nsXULPrototypeCache, nsISupports>, int32_t(reinterpret_cast <char*>(static_cast<nsISupports*>( static_cast< nsIObserver*>((nsXULPrototypeCache*)0x1000))) - reinterpret_cast <char*>((nsXULPrototypeCache*)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; } |
58 | |
59 | /* static */ |
60 | nsXULPrototypeCache* nsXULPrototypeCache::GetInstance() { |
61 | if (!sInstance) { |
62 | NS_ADDREF(sInstance = new nsXULPrototypeCache())(sInstance = new nsXULPrototypeCache())->AddRef(); |
63 | |
64 | Preferences::RegisterCallback( |
65 | DisableXULCacheChangedCallback, |
66 | nsDependentCString( |
67 | StaticPrefs::GetPrefName_nglayout_debug_disable_xul_cache())); |
68 | |
69 | nsCOMPtr<nsIObserverService> obsSvc = |
70 | mozilla::services::GetObserverService(); |
71 | if (obsSvc) { |
72 | nsXULPrototypeCache* p = sInstance; |
73 | obsSvc->AddObserver(p, "chrome-flush-caches", false); |
74 | obsSvc->AddObserver(p, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", false); |
75 | obsSvc->AddObserver(p, "startupcache-invalidate", false); |
76 | } |
77 | } |
78 | return sInstance; |
79 | } |
80 | |
81 | //---------------------------------------------------------------------- |
82 | |
83 | NS_IMETHODIMPnsresult |
84 | nsXULPrototypeCache::Observe(nsISupports* aSubject, const char* aTopic, |
85 | const char16_t* aData) { |
86 | if (!strcmp(aTopic, "chrome-flush-caches") || |
87 | !strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown")) { |
88 | Flush(); |
89 | } else if (!strcmp(aTopic, "startupcache-invalidate")) { |
90 | AbortCaching(); |
91 | } else { |
92 | NS_WARNING("Unexpected observer topic.")NS_DebugBreak(NS_DEBUG_WARNING, "Unexpected observer topic.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/xul/nsXULPrototypeCache.cpp" , 92); |
93 | } |
94 | return NS_OK; |
95 | } |
96 | |
97 | nsXULPrototypeDocument* nsXULPrototypeCache::GetPrototype(nsIURI* aURI) { |
98 | if (!aURI) return nullptr; |
99 | |
100 | nsCOMPtr<nsIURI> uriWithoutRef; |
101 | NS_GetURIWithoutRef(aURI, getter_AddRefs(uriWithoutRef)); |
102 | |
103 | nsXULPrototypeDocument* protoDoc = mPrototypeTable.GetWeak(uriWithoutRef); |
104 | if (protoDoc) { |
105 | return protoDoc; |
106 | } |
107 | |
108 | nsresult rv = BeginCaching(aURI); |
109 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return nullptr; |
110 | |
111 | // No prototype in XUL memory cache. Spin up the cache Service. |
112 | nsCOMPtr<nsIObjectInputStream> ois; |
113 | rv = GetPrototypeInputStream(aURI, getter_AddRefs(ois)); |
114 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
115 | return nullptr; |
116 | } |
117 | |
118 | RefPtr<nsXULPrototypeDocument> newProto; |
119 | rv = NS_NewXULPrototypeDocument(getter_AddRefs(newProto)); |
120 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return nullptr; |
121 | |
122 | rv = newProto->Read(ois); |
123 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
124 | rv = PutPrototype(newProto); |
Value stored to 'rv' is never read | |
125 | } else { |
126 | newProto = nullptr; |
127 | } |
128 | |
129 | mInputStreamTable.Remove(aURI); |
130 | return newProto; |
131 | } |
132 | |
133 | nsresult nsXULPrototypeCache::PutPrototype(nsXULPrototypeDocument* aDocument) { |
134 | if (!aDocument->GetURI()) { |
135 | return NS_ERROR_FAILURE; |
136 | } |
137 | |
138 | nsCOMPtr<nsIURI> uri; |
139 | NS_GetURIWithoutRef(aDocument->GetURI(), getter_AddRefs(uri)); |
140 | |
141 | // Put() releases any old value |
142 | mPrototypeTable.InsertOrUpdate(uri, RefPtr{aDocument}); |
143 | |
144 | return NS_OK; |
145 | } |
146 | |
147 | JS::Stencil* nsXULPrototypeCache::GetStencil(nsIURI* aURI) { |
148 | if (auto* entry = mStencilTable.GetEntry(aURI)) { |
149 | return entry->mStencil; |
150 | } |
151 | return nullptr; |
152 | } |
153 | |
154 | nsresult nsXULPrototypeCache::PutStencil(nsIURI* aURI, JS::Stencil* aStencil) { |
155 | MOZ_ASSERT(aStencil, "Need a non-NULL stencil")do { static_assert( mozilla::detail::AssertionConditionType< decltype(aStencil)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aStencil))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aStencil" " (" "Need a non-NULL stencil" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/xul/nsXULPrototypeCache.cpp" , 155); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStencil" ") (" "Need a non-NULL stencil" ")"); do { *((volatile int*)__null ) = 155; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
156 | |
157 | #ifdef DEBUG_BUG_392650 |
158 | if (mStencilTable.Get(aURI)) { |
159 | nsAutoCString scriptName; |
160 | aURI->GetSpec(scriptName); |
161 | nsAutoCString message("Loaded script "); |
162 | message += scriptName; |
163 | message += " twice (bug 392650)"; |
164 | NS_WARNING(message.get())NS_DebugBreak(NS_DEBUG_WARNING, message.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/xul/nsXULPrototypeCache.cpp" , 164); |
165 | } |
166 | #endif |
167 | |
168 | mStencilTable.PutEntry(aURI)->mStencil = aStencil; |
169 | |
170 | return NS_OK; |
171 | } |
172 | |
173 | void nsXULPrototypeCache::Flush() { |
174 | mPrototypeTable.Clear(); |
175 | mStencilTable.Clear(); |
176 | } |
177 | |
178 | bool nsXULPrototypeCache::IsEnabled() { |
179 | return !StaticPrefs::nglayout_debug_disable_xul_cache(); |
180 | } |
181 | |
182 | void nsXULPrototypeCache::AbortCaching() { |
183 | // Flush the XUL cache for good measure, in case we cached a bogus/downrev |
184 | // script, somehow. |
185 | Flush(); |
186 | |
187 | // Clear the cache set |
188 | mStartupCacheURITable.Clear(); |
189 | } |
190 | |
191 | nsresult nsXULPrototypeCache::WritePrototype( |
192 | nsXULPrototypeDocument* aPrototypeDocument) { |
193 | nsresult rv = NS_OK, rv2 = NS_OK; |
194 | |
195 | if (!StartupCache::GetSingleton()) return NS_OK; |
196 | |
197 | nsCOMPtr<nsIURI> protoURI = aPrototypeDocument->GetURI(); |
198 | |
199 | nsCOMPtr<nsIObjectOutputStream> oos; |
200 | rv = GetPrototypeOutputStream(protoURI, getter_AddRefs(oos)); |
201 | 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/dom/xul/nsXULPrototypeCache.cpp" , 201); return rv; } } while (false); |
202 | |
203 | rv = aPrototypeDocument->Write(oos); |
204 | 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/dom/xul/nsXULPrototypeCache.cpp" , 204); return rv; } } while (false); |
205 | FinishPrototypeOutputStream(protoURI); |
206 | return NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) ? rv : rv2; |
207 | } |
208 | |
209 | static nsresult PathifyURIForType(nsXULPrototypeCache::CacheType cacheType, |
210 | nsIURI* in, nsACString& out) { |
211 | switch (cacheType) { |
212 | case nsXULPrototypeCache::CacheType::Prototype: |
213 | return PathifyURI(CACHE_PREFIX("proto")"xulcache/" "proto", in, out); |
214 | case nsXULPrototypeCache::CacheType::Script: |
215 | return PathifyURI(CACHE_PREFIX("script")"xulcache/" "script", in, out); |
216 | } |
217 | MOZ_ASSERT_UNREACHABLE("unknown cache type?")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "unknown cache type?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/xul/nsXULPrototypeCache.cpp" , 217); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "unknown cache type?" ")"); do { * ((volatile int*)__null) = 217; __attribute__((nomerge)) ::abort (); } while (false); } } while (false); |
218 | return NS_ERROR_UNEXPECTED; |
219 | } |
220 | |
221 | nsresult nsXULPrototypeCache::GetInputStream(CacheType cacheType, nsIURI* uri, |
222 | nsIObjectInputStream** stream) { |
223 | nsAutoCString spec; |
224 | nsresult rv = PathifyURIForType(cacheType, uri, spec); |
225 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return NS_ERROR_NOT_AVAILABLE; |
226 | |
227 | const char* buf; |
228 | uint32_t len; |
229 | nsCOMPtr<nsIObjectInputStream> ois; |
230 | StartupCache* sc = StartupCache::GetSingleton(); |
231 | if (!sc) return NS_ERROR_NOT_AVAILABLE; |
232 | |
233 | rv = sc->GetBuffer(spec.get(), &buf, &len); |
234 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return NS_ERROR_NOT_AVAILABLE; |
235 | |
236 | rv = NewObjectInputStreamFromBuffer(buf, len, getter_AddRefs(ois)); |
237 | 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/dom/xul/nsXULPrototypeCache.cpp" , 237); return rv; } } while (false); |
238 | |
239 | mInputStreamTable.InsertOrUpdate(uri, ois); |
240 | |
241 | ois.forget(stream); |
242 | return NS_OK; |
243 | } |
244 | |
245 | nsresult nsXULPrototypeCache::FinishInputStream(nsIURI* uri) { |
246 | mInputStreamTable.Remove(uri); |
247 | return NS_OK; |
248 | } |
249 | |
250 | nsresult nsXULPrototypeCache::GetOutputStream(nsIURI* uri, |
251 | nsIObjectOutputStream** stream) { |
252 | nsresult rv; |
253 | nsCOMPtr<nsIObjectOutputStream> objectOutput; |
254 | nsCOMPtr<nsIStorageStream> storageStream; |
255 | bool found = mOutputStreamTable.Get(uri, getter_AddRefs(storageStream)); |
256 | if (found) { |
257 | // Setting an output stream here causes crashes on Windows. The previous |
258 | // version of this code always returned NS_ERROR_OUT_OF_MEMORY here, |
259 | // because it used a mistyped contract ID to create its object stream. |
260 | return NS_ERROR_NOT_IMPLEMENTED; |
261 | #if 0 |
262 | nsCOMPtr<nsIOutputStream> outputStream |
263 | = do_QueryInterface(storageStream); |
264 | objectOutput = NS_NewObjectOutputStream(outputStream); |
265 | #endif |
266 | } else { |
267 | rv = NewObjectOutputWrappedStorageStream( |
268 | getter_AddRefs(objectOutput), getter_AddRefs(storageStream), false); |
269 | 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/dom/xul/nsXULPrototypeCache.cpp" , 269); return rv; } } while (false); |
270 | mOutputStreamTable.InsertOrUpdate(uri, storageStream); |
271 | } |
272 | objectOutput.forget(stream); |
273 | return NS_OK; |
274 | } |
275 | |
276 | nsresult nsXULPrototypeCache::FinishOutputStream(CacheType cacheType, |
277 | nsIURI* uri) { |
278 | nsresult rv; |
279 | StartupCache* sc = StartupCache::GetSingleton(); |
280 | if (!sc) return NS_ERROR_NOT_AVAILABLE; |
281 | |
282 | nsCOMPtr<nsIStorageStream> storageStream; |
283 | bool found = mOutputStreamTable.Get(uri, getter_AddRefs(storageStream)); |
284 | if (!found) return NS_ERROR_UNEXPECTED; |
285 | nsCOMPtr<nsIOutputStream> outputStream = do_QueryInterface(storageStream); |
286 | outputStream->Close(); |
287 | |
288 | UniqueFreePtr<char[]> buf; |
289 | uint32_t len; |
290 | rv = NewBufferFromStorageStream(storageStream, &buf, &len); |
291 | 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/dom/xul/nsXULPrototypeCache.cpp" , 291); return rv; } } while (false); |
292 | |
293 | if (!mStartupCacheURITable.GetEntry(uri)) { |
294 | nsAutoCString spec; |
295 | rv = PathifyURIForType(cacheType, uri, spec); |
296 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return NS_ERROR_NOT_AVAILABLE; |
297 | rv = sc->PutBuffer(spec.get(), std::move(buf), len); |
298 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
299 | mOutputStreamTable.Remove(uri); |
300 | mStartupCacheURITable.PutEntry(uri); |
301 | } |
302 | } |
303 | |
304 | return rv; |
305 | } |
306 | |
307 | // We have data if we're in the middle of writing it or we already |
308 | // have it in the cache. |
309 | nsresult nsXULPrototypeCache::HasData(CacheType cacheType, nsIURI* uri, |
310 | bool* exists) { |
311 | if (mOutputStreamTable.Get(uri, nullptr)) { |
312 | *exists = true; |
313 | return NS_OK; |
314 | } |
315 | nsAutoCString spec; |
316 | nsresult rv = PathifyURIForType(cacheType, uri, spec); |
317 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
318 | *exists = false; |
319 | return NS_OK; |
320 | } |
321 | UniquePtr<char[]> buf; |
322 | StartupCache* sc = StartupCache::GetSingleton(); |
323 | if (sc) { |
324 | *exists = sc->HasEntry(spec.get()); |
325 | } else { |
326 | *exists = false; |
327 | } |
328 | return NS_OK; |
329 | } |
330 | |
331 | nsresult nsXULPrototypeCache::BeginCaching(nsIURI* aURI) { |
332 | nsresult rv, tmp; |
333 | |
334 | nsAutoCString path; |
335 | aURI->GetPathQueryRef(path); |
336 | if (!(StringEndsWith(path, ".xul"_ns) || StringEndsWith(path, ".xhtml"_ns))) { |
337 | return NS_ERROR_NOT_AVAILABLE; |
338 | } |
339 | |
340 | StartupCache* startupCache = StartupCache::GetSingleton(); |
341 | if (!startupCache) return NS_ERROR_FAILURE; |
342 | |
343 | if (StaticPrefs::nglayout_debug_disable_xul_cache()) { |
344 | return NS_ERROR_NOT_AVAILABLE; |
345 | } |
346 | |
347 | // Get the chrome directory to validate against the one stored in the |
348 | // cache file, or to store there if we're generating a new file. |
349 | nsCOMPtr<nsIFile> chromeDir; |
350 | rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR"AChrom", getter_AddRefs(chromeDir)); |
351 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv; |
352 | nsAutoCString chromePath; |
353 | rv = chromeDir->GetPersistentDescriptor(chromePath); |
354 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv; |
355 | |
356 | // XXXbe we assume the first package's locale is the same as the locale of |
357 | // all subsequent packages of cached chrome URIs.... |
358 | nsAutoCString package; |
359 | rv = aURI->GetHost(package); |
360 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv; |
361 | nsAutoCString locale; |
362 | LocaleService::GetInstance()->GetAppLocaleAsBCP47(locale); |
363 | |
364 | nsAutoCString fileChromePath, fileLocale; |
365 | |
366 | const char* buf = nullptr; |
367 | uint32_t len, amtRead; |
368 | nsCOMPtr<nsIObjectInputStream> objectInput; |
369 | |
370 | rv = startupCache->GetBuffer(kXULCacheInfoKey, &buf, &len); |
371 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) |
372 | rv = NewObjectInputStreamFromBuffer(buf, len, getter_AddRefs(objectInput)); |
373 | |
374 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
375 | rv = objectInput->ReadCString(fileLocale); |
376 | tmp = objectInput->ReadCString(fileChromePath); |
377 | if (NS_FAILED(tmp)((bool)(__builtin_expect(!!(NS_FAILED_impl(tmp)), 0)))) { |
378 | rv = tmp; |
379 | } |
380 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || |
381 | (!fileChromePath.Equals(chromePath) || !fileLocale.Equals(locale))) { |
382 | // Our cache won't be valid in this case, we'll need to rewrite. |
383 | // XXX This blows away work that other consumers (like |
384 | // mozJSModuleLoader) have done, need more fine-grained control. |
385 | startupCache->InvalidateCache(); |
386 | mStartupCacheURITable.Clear(); |
387 | rv = NS_ERROR_UNEXPECTED; |
388 | } |
389 | } else if (rv != NS_ERROR_NOT_AVAILABLE) |
390 | // NS_ERROR_NOT_AVAILABLE is normal, usually if there's no cachefile. |
391 | return rv; |
392 | |
393 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
394 | // Either the cache entry was invalid or it didn't exist, so write it now. |
395 | nsCOMPtr<nsIObjectOutputStream> objectOutput; |
396 | nsCOMPtr<nsIInputStream> inputStream; |
397 | nsCOMPtr<nsIStorageStream> storageStream; |
398 | rv = NewObjectOutputWrappedStorageStream( |
399 | getter_AddRefs(objectOutput), getter_AddRefs(storageStream), false); |
400 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
401 | rv = objectOutput->WriteStringZ(locale.get()); |
402 | tmp = objectOutput->WriteStringZ(chromePath.get()); |
403 | if (NS_FAILED(tmp)((bool)(__builtin_expect(!!(NS_FAILED_impl(tmp)), 0)))) { |
404 | rv = tmp; |
405 | } |
406 | tmp = objectOutput->Close(); |
407 | if (NS_FAILED(tmp)((bool)(__builtin_expect(!!(NS_FAILED_impl(tmp)), 0)))) { |
408 | rv = tmp; |
409 | } |
410 | tmp = storageStream->NewInputStream(0, getter_AddRefs(inputStream)); |
411 | if (NS_FAILED(tmp)((bool)(__builtin_expect(!!(NS_FAILED_impl(tmp)), 0)))) { |
412 | rv = tmp; |
413 | } |
414 | } |
415 | |
416 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
417 | uint64_t len64; |
418 | rv = inputStream->Available(&len64); |
419 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
420 | if (len64 <= UINT32_MAX(4294967295U)) |
421 | len = (uint32_t)len64; |
422 | else |
423 | rv = NS_ERROR_FILE_TOO_BIG; |
424 | } |
425 | } |
426 | |
427 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
428 | auto putBuf = UniqueFreePtr<char[]>( |
429 | reinterpret_cast<char*>(malloc(sizeof(char) * len))); |
430 | rv = inputStream->Read(putBuf.get(), len, &amtRead); |
431 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && len == amtRead) |
432 | rv = startupCache->PutBuffer(kXULCacheInfoKey, std::move(putBuf), len); |
433 | else { |
434 | rv = NS_ERROR_UNEXPECTED; |
435 | } |
436 | } |
437 | |
438 | // Failed again, just bail. |
439 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
440 | startupCache->InvalidateCache(); |
441 | mStartupCacheURITable.Clear(); |
442 | return NS_ERROR_FAILURE; |
443 | } |
444 | } |
445 | |
446 | return NS_OK; |
447 | } |
448 | |
449 | void nsXULPrototypeCache::MarkInCCGeneration(uint32_t aGeneration) { |
450 | for (const auto& prototype : mPrototypeTable.Values()) { |
451 | prototype->MarkInCCGeneration(aGeneration); |
452 | } |
453 | } |
454 | |
455 | MOZ_DEFINE_MALLOC_SIZE_OF(CacheMallocSizeOf)static size_t CacheMallocSizeOf(const void* aPtr) { mozilla:: dmd::Report(aPtr); return moz_malloc_size_of(aPtr); } |
456 | |
457 | static void ReportSize(const nsCString& aPath, size_t aAmount, |
458 | const nsCString& aDescription, |
459 | nsIHandleReportCallback* aHandleReport, |
460 | nsISupports* aData) { |
461 | nsAutoCString path("explicit/xul-prototype-cache/"); |
462 | path += aPath; |
463 | aHandleReport->Callback(""_ns, path, nsIMemoryReporter::KIND_HEAP, |
464 | nsIMemoryReporter::UNITS_BYTES, aAmount, aDescription, |
465 | aData); |
466 | } |
467 | |
468 | /* static */ |
469 | void nsXULPrototypeCache::CollectMemoryReports( |
470 | nsIHandleReportCallback* aHandleReport, nsISupports* aData) { |
471 | if (!sInstance) { |
472 | return; |
473 | } |
474 | |
475 | MallocSizeOf mallocSizeOf = CacheMallocSizeOf; |
476 | size_t other = mallocSizeOf(sInstance); |
477 | |
478 | #define REPORT_SIZE(_path, _amount, _desc) \ |
479 | ReportSize(_path, _amount, nsLiteralCString(_desc), aHandleReport, aData) |
480 | |
481 | other += sInstance->mPrototypeTable.ShallowSizeOfExcludingThis(mallocSizeOf); |
482 | // TODO Report content in mPrototypeTable? |
483 | |
484 | other += sInstance->mStencilTable.ShallowSizeOfExcludingThis(mallocSizeOf); |
485 | // TODO Report content inside mStencilTable? |
486 | |
487 | other += |
488 | sInstance->mStartupCacheURITable.ShallowSizeOfExcludingThis(mallocSizeOf); |
489 | |
490 | other += |
491 | sInstance->mOutputStreamTable.ShallowSizeOfExcludingThis(mallocSizeOf); |
492 | other += |
493 | sInstance->mInputStreamTable.ShallowSizeOfExcludingThis(mallocSizeOf); |
494 | |
495 | REPORT_SIZE("other"_ns, other, |
496 | "Memory used by " |
497 | "the instance and tables of the XUL prototype cache."); |
498 | |
499 | #undef REPORT_SIZE |
500 | } |