SharedScriptCache.h (8941B)
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 #ifndef mozilla_dom_SharedScriptCache_h 8 #define mozilla_dom_SharedScriptCache_h 9 10 #include "PLDHashTable.h" // PLDHashEntryHdr 11 #include "js/loader/LoadedScript.h" // JS::loader::LoadedScript 12 #include "js/loader/ScriptFetchOptions.h" // JS::loader::ScriptFetchOptions 13 #include "js/loader/ScriptKind.h" // JS::loader::ScriptKind 14 #include "js/loader/ScriptLoadRequest.h" // JS::loader::ScriptLoadRequest 15 #include "mozilla/CORSMode.h" // mozilla::CORSMode 16 #include "mozilla/MemoryReporting.h" // MallocSizeOf 17 #include "mozilla/Mutex.h" // Mutex, GUARDED_BY, MutexAutoLock 18 #include "mozilla/RefPtr.h" // RefPtr 19 #include "mozilla/SharedSubResourceCache.h" // SharedSubResourceCache, SharedSubResourceCacheLoadingValueBase, SubResourceNetworkMetadataHolder 20 #include "mozilla/ThreadSafety.h" // MOZ_GUARDED_BY 21 #include "mozilla/WeakPtr.h" // SupportsWeakPtr 22 #include "mozilla/dom/CacheExpirationTime.h" // CacheExpirationTime 23 #include "mozilla/dom/SRIMetadata.h" // mozilla::dom::SRIMetadata 24 #include "nsIMemoryReporter.h" // nsIMemoryReporter, NS_DECL_NSIMEMORYREPORTER 25 #include "nsIPrincipal.h" // nsIPrincipal 26 #include "nsISupports.h" // nsISupports, NS_DECL_ISUPPORTS 27 #include "nsStringFwd.h" // nsACString 28 29 namespace mozilla { 30 namespace dom { 31 32 class ScriptLoader; 33 class ScriptLoadData; 34 35 class ScriptHashKey : public PLDHashEntryHdr { 36 public: 37 using KeyType = const ScriptHashKey&; 38 using KeyTypePointer = const ScriptHashKey*; 39 40 explicit ScriptHashKey(const ScriptHashKey& aKey) 41 : PLDHashEntryHdr(), 42 mURI(aKey.mURI), 43 mPartitionPrincipal(aKey.mPartitionPrincipal), 44 mLoaderPrincipal(aKey.mLoaderPrincipal), 45 mKind(aKey.mKind), 46 mCORSMode(aKey.mCORSMode), 47 mReferrerPolicy(aKey.mReferrerPolicy), 48 mSRIMetadata(aKey.mSRIMetadata), 49 mNonce(aKey.mNonce), 50 mHintCharset(aKey.mHintCharset) { 51 MOZ_COUNT_CTOR(ScriptHashKey); 52 } 53 54 explicit ScriptHashKey(const ScriptHashKey* aKey) : ScriptHashKey(*aKey) {} 55 56 ScriptHashKey(ScriptHashKey&& aKey) 57 : PLDHashEntryHdr(), 58 mURI(std::move(aKey.mURI)), 59 mPartitionPrincipal(std::move(aKey.mPartitionPrincipal)), 60 mLoaderPrincipal(std::move(aKey.mLoaderPrincipal)), 61 mKind(std::move(aKey.mKind)), 62 mCORSMode(std::move(aKey.mCORSMode)), 63 mReferrerPolicy(std::move(aKey.mReferrerPolicy)), 64 mSRIMetadata(std::move(aKey.mSRIMetadata)), 65 mNonce(std::move(aKey.mNonce)), 66 mHintCharset(std::move(aKey.mHintCharset)) { 67 MOZ_COUNT_CTOR(ScriptHashKey); 68 } 69 70 ScriptHashKey(ScriptLoader* aLoader, 71 const JS::loader::ScriptLoadRequest* aRequest, 72 const JS::loader::LoadedScript* aLoadedScript); 73 ScriptHashKey(ScriptLoader* aLoader, 74 const JS::loader::ScriptLoadRequest* aRequest, 75 mozilla::dom::ReferrerPolicy aReferrerPolicy, 76 const JS::loader::ScriptFetchOptions* aFetchOptions, 77 const nsCOMPtr<nsIURI> aURI); 78 explicit ScriptHashKey(const ScriptLoadData& aLoadData); 79 80 MOZ_COUNTED_DTOR(ScriptHashKey) 81 82 const ScriptHashKey& GetKey() const { return *this; } 83 const ScriptHashKey* GetKeyPointer() const { return this; } 84 85 bool KeyEquals(const ScriptHashKey* aKey) const { return KeyEquals(*aKey); } 86 87 bool KeyEquals(const ScriptHashKey&) const; 88 89 static const ScriptHashKey* KeyToPointer(const ScriptHashKey& aKey) { 90 return &aKey; 91 } 92 static PLDHashNumber HashKey(const ScriptHashKey* aKey) { 93 return nsURIHashKey::HashKey(aKey->mURI); 94 } 95 96 nsIPrincipal* LoaderPrincipal() const { return mLoaderPrincipal; } 97 nsIPrincipal* PartitionPrincipal() const { return mPartitionPrincipal; } 98 99 nsIURI* URI() const { return mURI; } 100 101 enum { ALLOW_MEMMOVE = true }; 102 103 protected: 104 // Order the fields from the most important one as much as possible, while 105 // packing them, in order to use the same order between the definition and 106 // the KeyEquals implementation. 107 108 // The script's URI. This should distinguish the cache entry in most case. 109 const nsCOMPtr<nsIURI> mURI; 110 111 // If single content process has multiple principals, mPartitionPrincipal 112 // should distinguish them. 113 const nsCOMPtr<nsIPrincipal> mPartitionPrincipal; 114 115 // NOTE: mLoaderPrincipal is only for SharedSubResourceCache logic, 116 // and not part of KeyEquals. 117 const nsCOMPtr<nsIPrincipal> mLoaderPrincipal; 118 119 // Other fields should be unique per each script in general. 120 const JS::loader::ScriptKind mKind; 121 const CORSMode mCORSMode; 122 const mozilla::dom::ReferrerPolicy mReferrerPolicy; 123 124 const SRIMetadata mSRIMetadata; 125 const nsString mNonce; 126 127 // charset attribute for classic script. 128 // module always use UTF-8. 129 nsString mHintCharset; 130 }; 131 132 class ScriptLoadData final 133 : public SupportsWeakPtr, 134 public nsISupports, 135 public SharedSubResourceCacheLoadingValueBase<ScriptLoadData> { 136 protected: 137 ~ScriptLoadData() {} 138 139 public: 140 ScriptLoadData(ScriptLoader* aLoader, JS::loader::ScriptLoadRequest* aRequest, 141 JS::loader::LoadedScript* aLoadedScript); 142 143 NS_DECL_ISUPPORTS 144 145 // Only completed loads are used for the cache. 146 bool IsLoading() const override { return false; } 147 bool IsCancelled() const override { return false; } 148 bool IsSyncLoad() const override { return true; } 149 150 SubResourceNetworkMetadataHolder* GetNetworkMetadata() const override { 151 return mNetworkMetadata.get(); 152 } 153 154 void StartLoading() override {} 155 void SetLoadCompleted() override {} 156 void OnCoalescedTo(const ScriptLoadData& aExistingLoad) override {} 157 void Cancel() override {} 158 159 void DidCancelLoad() {} 160 161 bool ShouldDefer() const { return false; } 162 163 JS::loader::LoadedScript* ValueForCache() const { 164 return mLoadedScript.get(); 165 } 166 167 const CacheExpirationTime& ExpirationTime() const { return mExpirationTime; } 168 169 ScriptLoader& Loader() { return *mLoader; } 170 171 const ScriptHashKey& CacheKey() const { return mKey; } 172 173 private: 174 CacheExpirationTime mExpirationTime = CacheExpirationTime::Never(); 175 ScriptLoader* mLoader; 176 ScriptHashKey mKey; 177 RefPtr<JS::loader::LoadedScript> mLoadedScript; 178 RefPtr<SubResourceNetworkMetadataHolder> mNetworkMetadata; 179 }; 180 181 struct SharedScriptCacheTraits { 182 using Loader = ScriptLoader; 183 using Key = ScriptHashKey; 184 using Value = JS::loader::LoadedScript; 185 using LoadingValue = ScriptLoadData; 186 187 static ScriptHashKey KeyFromLoadingValue(const LoadingValue& aValue) { 188 return ScriptHashKey(aValue); 189 } 190 }; 191 192 class SharedScriptCache final 193 : public SharedSubResourceCache<SharedScriptCacheTraits, SharedScriptCache>, 194 public nsIMemoryReporter { 195 public: 196 using Base = 197 SharedSubResourceCache<SharedScriptCacheTraits, SharedScriptCache>; 198 199 NS_DECL_ISUPPORTS 200 NS_DECL_NSIMEMORYREPORTER 201 202 SharedScriptCache(); 203 void Init(); 204 205 bool MaybeScheduleUpdateDiskCache(); 206 void UpdateDiskCache(); 207 208 void EncodeAndCompress(); 209 void SaveToDiskCache(); 210 211 void InvalidateInProcess(); 212 213 // This has to be static because it's also called for loaders that don't have 214 // a sheet cache (loaders that are not owned by a document). 215 static void LoadCompleted(SharedScriptCache*, ScriptLoadData&); 216 using Base::LoadCompleted; 217 static void Clear(const Maybe<bool>& aChrome = Nothing(), 218 const Maybe<nsCOMPtr<nsIPrincipal>>& aPrincipal = Nothing(), 219 const Maybe<nsCString>& aSchemelessSite = Nothing(), 220 const Maybe<OriginAttributesPattern>& aPattern = Nothing(), 221 const Maybe<nsCString>& aURL = Nothing()); 222 223 static void Invalidate(); 224 225 static void PrepareForLastCC(); 226 227 protected: 228 ~SharedScriptCache(); 229 230 private: 231 class EncodeItem { 232 public: 233 EncodeItem(JS::Stencil* aStencil, JS::TranscodeBuffer&& aSRI, 234 JS::loader::LoadedScript* aLoadedScript) 235 : mStencil(aStencil), 236 mSRI(std::move(aSRI)), 237 mLoadedScript(aLoadedScript) {} 238 239 // These fields can be touched from multiple threads. 240 RefPtr<JS::Stencil> mStencil; 241 JS::TranscodeBuffer mSRI; 242 Vector<uint8_t> mCompressed; 243 244 // This can be dereferenced only from the main thread. 245 // Reading the pointer itself is allowed also off main thread. 246 RefPtr<JS::loader::LoadedScript> mLoadedScript; 247 }; 248 249 Mutex mEncodeMutex{"SharedScriptCache::mEncodeMutex"}; 250 Vector<EncodeItem> mEncodeItems MOZ_GUARDED_BY(mEncodeMutex); 251 }; 252 253 } // namespace dom 254 } // namespace mozilla 255 256 #endif // mozilla_dom_SharedScriptCache_h