1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef nsXULPrototypeCache_h__
7 #define nsXULPrototypeCache_h__
8 
9 #include "nsBaseHashtable.h"
10 #include "nsCOMPtr.h"
11 #include "nsIObserver.h"
12 #include "nsInterfaceHashtable.h"
13 #include "nsRefPtrHashtable.h"
14 #include "nsURIHashKey.h"
15 #include "nsXULPrototypeDocument.h"
16 #include "nsIStorageStream.h"
17 
18 #include "mozilla/scache/StartupCache.h"
19 
20 class nsIHandleReportCallback;
21 namespace mozilla {
22 class StyleSheet;
23 }  // namespace mozilla
24 
25 /**
26  * The XUL prototype cache can be used to store and retrieve shared data for
27  * XUL documents, style sheets, XBL, and scripts.
28  *
29  * The cache has two levels:
30  *  1. In-memory hashtables
31  *  2. The on-disk cache file.
32  */
33 class nsXULPrototypeCache : public nsIObserver {
34  public:
35   // nsISupports
36   NS_DECL_THREADSAFE_ISUPPORTS
37   NS_DECL_NSIOBSERVER
38 
IsCached(nsIURI * aURI)39   bool IsCached(nsIURI* aURI) { return GetPrototype(aURI) != nullptr; }
40   void AbortCaching();
41 
42   /**
43    * Whether the prototype cache is enabled.
44    */
45   bool IsEnabled();
46 
47   /**
48    * Flush the cache; remove all XUL prototype documents, style
49    * sheets, and scripts.
50    */
51   void Flush();
52 
53   // The following methods are used to put and retrive various items into and
54   // from the cache.
55 
56   nsXULPrototypeDocument* GetPrototype(nsIURI* aURI);
57   nsresult PutPrototype(nsXULPrototypeDocument* aDocument);
58 
59   JSScript* GetScript(nsIURI* aURI);
60   nsresult PutScript(nsIURI* aURI, JS::Handle<JSScript*> aScriptObject);
61 
62   /**
63    * Get a style sheet by URI. If the style sheet is not in the cache,
64    * returns nullptr.
65    */
66   mozilla::StyleSheet* GetStyleSheet(nsIURI* aURI);
67 
68   /**
69    * Store a style sheet in the cache. The key, style sheet's URI is obtained
70    * from the style sheet itself.
71    */
72   nsresult PutStyleSheet(RefPtr<mozilla::StyleSheet>&& aStyleSheet);
73 
74   /**
75    * Write the XUL prototype document to a cache file. The proto must be
76    * fully loaded.
77    */
78   nsresult WritePrototype(nsXULPrototypeDocument* aPrototypeDocument);
79 
80   /**
81    * This interface allows partial reads and writes from the buffers in the
82    * startupCache.
83    */
84   nsresult GetInputStream(nsIURI* aURI, nsIObjectInputStream** objectInput);
85   nsresult FinishInputStream(nsIURI* aURI);
86   nsresult GetOutputStream(nsIURI* aURI, nsIObjectOutputStream** objectOutput);
87   nsresult FinishOutputStream(nsIURI* aURI);
88   nsresult HasData(nsIURI* aURI, bool* exists);
89 
90   static nsXULPrototypeCache* GetInstance();
MaybeGetInstance()91   static nsXULPrototypeCache* MaybeGetInstance() { return sInstance; }
92 
ReleaseGlobals()93   static void ReleaseGlobals() { NS_IF_RELEASE(sInstance); }
94 
95   void MarkInCCGeneration(uint32_t aGeneration);
96   void MarkInGC(JSTracer* aTrc);
97   void FlushScripts();
98 
99   static void CollectMemoryReports(nsIHandleReportCallback* aHandleReport,
100                                    nsISupports* aData);
101 
102  protected:
103   friend nsresult NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID,
104                                           void** aResult);
105 
106   nsXULPrototypeCache();
107   virtual ~nsXULPrototypeCache();
108 
109   static nsXULPrototypeCache* sInstance;
110 
111   using StyleSheetTable = nsRefPtrHashtable<nsURIHashKey, mozilla::StyleSheet>;
112 
113   nsRefPtrHashtable<nsURIHashKey, nsXULPrototypeDocument>
114       mPrototypeTable;  // owns the prototypes
115   StyleSheetTable mStyleSheetTable;
116 
117   class ScriptHashKey : public nsURIHashKey {
118    public:
ScriptHashKey(const nsIURI * aKey)119     explicit ScriptHashKey(const nsIURI* aKey) : nsURIHashKey(aKey) {}
120     ScriptHashKey(ScriptHashKey&&) = default;
121 
122     // Mark ALLOW_MEMMOVE as false, as hash tables containing JS:Heap<T>
123     // values must be copied rather than memmoved.
124     enum { ALLOW_MEMMOVE = false };
125 
126     JS::Heap<JSScript*> mScript;
127   };
128 
129   nsTHashtable<ScriptHashKey> mScriptTable;
130 
131   // URIs already written to the startup cache, to prevent double-caching.
132   nsTHashtable<nsURIHashKey> mStartupCacheURITable;
133 
134   nsInterfaceHashtable<nsURIHashKey, nsIStorageStream> mOutputStreamTable;
135   nsInterfaceHashtable<nsURIHashKey, nsIObjectInputStream> mInputStreamTable;
136 
137   // Bootstrap caching service
138   nsresult BeginCaching(nsIURI* aDocumentURI);
139 };
140 
141 #endif  // nsXULPrototypeCache_h__
142