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