| 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 | } |