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