Line data Source code
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 "plstr.h"
10 : #include "nsXULPrototypeDocument.h"
11 : #include "nsIServiceManager.h"
12 : #include "nsIURI.h"
13 :
14 : #include "nsIFile.h"
15 : #include "nsIObjectInputStream.h"
16 : #include "nsIObjectOutputStream.h"
17 : #include "nsIObserverService.h"
18 : #include "nsIStringStream.h"
19 : #include "nsIStorageStream.h"
20 :
21 : #include "nsAppDirectoryServiceDefs.h"
22 :
23 : #include "js/TracingAPI.h"
24 :
25 : #include "mozilla/StyleSheetInlines.h"
26 : #include "mozilla/Preferences.h"
27 : #include "mozilla/scache/StartupCache.h"
28 : #include "mozilla/scache/StartupCacheUtils.h"
29 : #include "mozilla/Telemetry.h"
30 : #include "mozilla/intl/LocaleService.h"
31 :
32 : using namespace mozilla;
33 : using namespace mozilla::scache;
34 : using mozilla::intl::LocaleService;
35 :
36 : static bool gDisableXULCache = false; // enabled by default
37 : static const char kDisableXULCachePref[] = "nglayout.debug.disable_xul_cache";
38 : static const char kXULCacheInfoKey[] = "nsXULPrototypeCache.startupCache";
39 : static const char kXULCachePrefix[] = "xulcache";
40 :
41 : //----------------------------------------------------------------------
42 :
43 : static void
44 3 : UpdategDisableXULCache()
45 : {
46 : // Get the value of "nglayout.debug.disable_xul_cache" preference
47 3 : gDisableXULCache =
48 3 : Preferences::GetBool(kDisableXULCachePref, gDisableXULCache);
49 :
50 : // Sets the flag if the XUL cache is disabled
51 3 : if (gDisableXULCache) {
52 0 : Telemetry::Accumulate(Telemetry::XUL_CACHE_DISABLED, true);
53 : }
54 :
55 3 : }
56 :
57 : static void
58 0 : DisableXULCacheChangedCallback(const char* aPref, void* aClosure)
59 : {
60 0 : bool wasEnabled = !gDisableXULCache;
61 0 : UpdategDisableXULCache();
62 :
63 0 : if (wasEnabled && gDisableXULCache) {
64 0 : nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
65 0 : if (cache) {
66 : // AbortCaching() calls Flush() for us.
67 0 : cache->AbortCaching();
68 : }
69 : }
70 0 : }
71 :
72 : //----------------------------------------------------------------------
73 :
74 : nsXULPrototypeCache* nsXULPrototypeCache::sInstance = nullptr;
75 :
76 :
77 3 : nsXULPrototypeCache::nsXULPrototypeCache()
78 : {
79 3 : }
80 :
81 :
82 0 : nsXULPrototypeCache::~nsXULPrototypeCache()
83 : {
84 0 : FlushScripts();
85 0 : }
86 :
87 :
88 15 : NS_IMPL_ISUPPORTS(nsXULPrototypeCache, nsIObserver)
89 :
90 : /* static */ nsXULPrototypeCache*
91 772 : nsXULPrototypeCache::GetInstance()
92 : {
93 772 : if (!sInstance) {
94 3 : NS_ADDREF(sInstance = new nsXULPrototypeCache());
95 :
96 3 : UpdategDisableXULCache();
97 :
98 : Preferences::RegisterCallback(DisableXULCacheChangedCallback,
99 3 : kDisableXULCachePref);
100 :
101 : nsCOMPtr<nsIObserverService> obsSvc =
102 6 : mozilla::services::GetObserverService();
103 3 : if (obsSvc) {
104 3 : nsXULPrototypeCache *p = sInstance;
105 3 : obsSvc->AddObserver(p, "chrome-flush-skin-caches", false);
106 3 : obsSvc->AddObserver(p, "chrome-flush-caches", false);
107 3 : obsSvc->AddObserver(p, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
108 3 : obsSvc->AddObserver(p, "startupcache-invalidate", false);
109 : }
110 :
111 : }
112 772 : return sInstance;
113 : }
114 :
115 : //----------------------------------------------------------------------
116 :
117 : NS_IMETHODIMP
118 0 : nsXULPrototypeCache::Observe(nsISupports* aSubject,
119 : const char *aTopic,
120 : const char16_t *aData)
121 : {
122 0 : if (!strcmp(aTopic, "chrome-flush-skin-caches")) {
123 0 : FlushSkinFiles();
124 : }
125 0 : else if (!strcmp(aTopic, "chrome-flush-caches") ||
126 0 : !strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
127 0 : Flush();
128 : }
129 0 : else if (!strcmp(aTopic, "startupcache-invalidate")) {
130 0 : AbortCaching();
131 : }
132 : else {
133 0 : NS_WARNING("Unexpected observer topic.");
134 : }
135 0 : return NS_OK;
136 : }
137 :
138 : nsXULPrototypeDocument*
139 6 : nsXULPrototypeCache::GetPrototype(nsIURI* aURI)
140 : {
141 6 : if (!aURI)
142 0 : return nullptr;
143 :
144 12 : nsCOMPtr<nsIURI> uriWithoutRef;
145 6 : aURI->CloneIgnoringRef(getter_AddRefs(uriWithoutRef));
146 :
147 6 : nsXULPrototypeDocument* protoDoc = mPrototypeTable.GetWeak(uriWithoutRef);
148 6 : if (protoDoc)
149 0 : return protoDoc;
150 :
151 6 : nsresult rv = BeginCaching(aURI);
152 6 : if (NS_FAILED(rv))
153 0 : return nullptr;
154 :
155 : // No prototype in XUL memory cache. Spin up the cache Service.
156 12 : nsCOMPtr<nsIObjectInputStream> ois;
157 6 : rv = GetInputStream(aURI, getter_AddRefs(ois));
158 6 : if (NS_FAILED(rv))
159 0 : return nullptr;
160 :
161 12 : RefPtr<nsXULPrototypeDocument> newProto;
162 6 : rv = NS_NewXULPrototypeDocument(getter_AddRefs(newProto));
163 6 : if (NS_FAILED(rv))
164 0 : return nullptr;
165 :
166 6 : rv = newProto->Read(ois);
167 6 : if (NS_SUCCEEDED(rv)) {
168 6 : rv = PutPrototype(newProto);
169 : } else {
170 0 : newProto = nullptr;
171 : }
172 :
173 6 : mInputStreamTable.Remove(aURI);
174 6 : return newProto;
175 : }
176 :
177 : nsresult
178 6 : nsXULPrototypeCache::PutPrototype(nsXULPrototypeDocument* aDocument)
179 : {
180 6 : if (!aDocument->GetURI()) {
181 0 : return NS_ERROR_FAILURE;
182 : }
183 :
184 12 : nsCOMPtr<nsIURI> uri;
185 6 : aDocument->GetURI()->CloneIgnoringRef(getter_AddRefs(uri));
186 :
187 : // Put() releases any old value and addrefs the new one
188 6 : mPrototypeTable.Put(uri, aDocument);
189 :
190 6 : return NS_OK;
191 : }
192 :
193 : mozilla::StyleSheet*
194 89 : nsXULPrototypeCache::GetStyleSheet(nsIURI* aURI,
195 : StyleBackendType aType)
196 : {
197 89 : StyleSheetTable& table = StyleSheetTableFor(aType);
198 89 : return table.GetWeak(aURI);
199 : }
200 :
201 : nsresult
202 37 : nsXULPrototypeCache::PutStyleSheet(StyleSheet* aStyleSheet,
203 : StyleBackendType aType)
204 : {
205 37 : nsIURI* uri = aStyleSheet->GetSheetURI();
206 :
207 37 : StyleSheetTable& table = StyleSheetTableFor(aType);
208 37 : table.Put(uri, aStyleSheet);
209 :
210 37 : return NS_OK;
211 : }
212 :
213 : JSScript*
214 38 : nsXULPrototypeCache::GetScript(nsIURI* aURI)
215 : {
216 38 : return mScriptTable.Get(aURI);
217 : }
218 :
219 : nsresult
220 37 : nsXULPrototypeCache::PutScript(nsIURI* aURI,
221 : JS::Handle<JSScript*> aScriptObject)
222 : {
223 37 : MOZ_ASSERT(aScriptObject, "Need a non-NULL script");
224 :
225 : #ifdef DEBUG_BUG_392650
226 : if (mScriptTable.Get(aURI)) {
227 : nsAutoCString scriptName;
228 : aURI->GetSpec(scriptName);
229 : nsAutoCString message("Loaded script ");
230 : message += scriptName;
231 : message += " twice (bug 392650)";
232 : NS_WARNING(message.get());
233 : }
234 : #endif
235 :
236 37 : mScriptTable.Put(aURI, aScriptObject);
237 :
238 37 : return NS_OK;
239 : }
240 :
241 : nsXBLDocumentInfo*
242 26 : nsXULPrototypeCache::GetXBLDocumentInfo(nsIURI* aURL,
243 : StyleBackendType aType)
244 : {
245 26 : MOZ_ASSERT(aType != StyleBackendType::None,
246 : "Please use either gecko or servo when looking up for the cache!");
247 26 : return XBLDocTableFor(aType).GetWeak(aURL);
248 : }
249 :
250 : nsresult
251 26 : nsXULPrototypeCache::PutXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo)
252 : {
253 26 : nsIURI* uri = aDocumentInfo->DocumentURI();
254 : XBLDocTable& table =
255 26 : XBLDocTableFor(aDocumentInfo->GetDocument()->GetStyleBackendType());
256 :
257 26 : nsXBLDocumentInfo* info = table.GetWeak(uri);
258 26 : if (!info) {
259 26 : table.Put(uri, aDocumentInfo);
260 : }
261 26 : return NS_OK;
262 : }
263 :
264 : void
265 0 : nsXULPrototypeCache::FlushSkinFiles()
266 : {
267 : StyleBackendType tableTypes[] = { StyleBackendType::Gecko,
268 0 : StyleBackendType::Servo };
269 :
270 0 : for (auto tableType : tableTypes) {
271 : // Flush out skin XBL files from the cache.
272 0 : XBLDocTable& xblDocTable = XBLDocTableFor(tableType);
273 0 : for (auto iter = xblDocTable.Iter(); !iter.Done(); iter.Next()) {
274 0 : nsAutoCString str;
275 0 : iter.Key()->GetPath(str);
276 0 : if (strncmp(str.get(), "/skin", 5) == 0) {
277 0 : iter.Remove();
278 : }
279 : }
280 :
281 : // Now flush out our skin stylesheets from the cache.
282 0 : StyleSheetTable& table = StyleSheetTableFor(tableType);
283 0 : for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
284 0 : nsAutoCString str;
285 0 : iter.Data()->GetSheetURI()->GetPath(str);
286 0 : if (strncmp(str.get(), "/skin", 5) == 0) {
287 0 : iter.Remove();
288 : }
289 : }
290 :
291 : // Iterate over all the remaining XBL and make sure cached
292 : // scoped skin stylesheets are flushed and refetched by the
293 : // prototype bindings.
294 0 : for (auto iter = xblDocTable.Iter(); !iter.Done(); iter.Next()) {
295 0 : iter.Data()->FlushSkinStylesheets();
296 : }
297 : }
298 0 : }
299 :
300 : void
301 0 : nsXULPrototypeCache::FlushScripts()
302 : {
303 0 : mScriptTable.Clear();
304 0 : }
305 :
306 : void
307 0 : nsXULPrototypeCache::Flush()
308 : {
309 0 : mPrototypeTable.Clear();
310 0 : mScriptTable.Clear();
311 0 : mGeckoStyleSheetTable.Clear();
312 0 : mServoStyleSheetTable.Clear();
313 0 : mGeckoXBLDocTable.Clear();
314 0 : mServoXBLDocTable.Clear();
315 0 : }
316 :
317 :
318 : bool
319 765 : nsXULPrototypeCache::IsEnabled()
320 : {
321 765 : return !gDisableXULCache;
322 : }
323 :
324 : void
325 0 : nsXULPrototypeCache::AbortCaching()
326 : {
327 : #ifdef DEBUG_brendan
328 : NS_BREAK();
329 : #endif
330 :
331 : // Flush the XUL cache for good measure, in case we cached a bogus/downrev
332 : // script, somehow.
333 0 : Flush();
334 :
335 : // Clear the cache set
336 0 : mStartupCacheURITable.Clear();
337 0 : }
338 :
339 :
340 : nsresult
341 0 : nsXULPrototypeCache::WritePrototype(nsXULPrototypeDocument* aPrototypeDocument)
342 : {
343 0 : nsresult rv = NS_OK, rv2 = NS_OK;
344 :
345 0 : if (!StartupCache::GetSingleton())
346 0 : return NS_OK;
347 :
348 0 : nsCOMPtr<nsIURI> protoURI = aPrototypeDocument->GetURI();
349 :
350 0 : nsCOMPtr<nsIObjectOutputStream> oos;
351 0 : rv = GetOutputStream(protoURI, getter_AddRefs(oos));
352 0 : NS_ENSURE_SUCCESS(rv, rv);
353 :
354 0 : rv = aPrototypeDocument->Write(oos);
355 0 : NS_ENSURE_SUCCESS(rv, rv);
356 0 : FinishOutputStream(protoURI);
357 0 : return NS_FAILED(rv) ? rv : rv2;
358 : }
359 :
360 : nsresult
361 43 : nsXULPrototypeCache::GetInputStream(nsIURI* uri, nsIObjectInputStream** stream)
362 : {
363 86 : nsAutoCString spec(kXULCachePrefix);
364 43 : nsresult rv = PathifyURI(uri, spec);
365 43 : if (NS_FAILED(rv))
366 0 : return NS_ERROR_NOT_AVAILABLE;
367 :
368 86 : UniquePtr<char[]> buf;
369 : uint32_t len;
370 86 : nsCOMPtr<nsIObjectInputStream> ois;
371 43 : StartupCache* sc = StartupCache::GetSingleton();
372 43 : if (!sc)
373 0 : return NS_ERROR_NOT_AVAILABLE;
374 :
375 43 : rv = sc->GetBuffer(spec.get(), &buf, &len);
376 43 : if (NS_FAILED(rv))
377 0 : return NS_ERROR_NOT_AVAILABLE;
378 :
379 43 : rv = NewObjectInputStreamFromBuffer(Move(buf), len, getter_AddRefs(ois));
380 43 : NS_ENSURE_SUCCESS(rv, rv);
381 :
382 43 : mInputStreamTable.Put(uri, ois);
383 :
384 43 : ois.forget(stream);
385 43 : return NS_OK;
386 : }
387 :
388 : nsresult
389 37 : nsXULPrototypeCache::FinishInputStream(nsIURI* uri) {
390 37 : mInputStreamTable.Remove(uri);
391 37 : return NS_OK;
392 : }
393 :
394 : nsresult
395 0 : nsXULPrototypeCache::GetOutputStream(nsIURI* uri, nsIObjectOutputStream** stream)
396 : {
397 : nsresult rv;
398 0 : nsCOMPtr<nsIObjectOutputStream> objectOutput;
399 0 : nsCOMPtr<nsIStorageStream> storageStream;
400 0 : bool found = mOutputStreamTable.Get(uri, getter_AddRefs(storageStream));
401 0 : if (found) {
402 0 : objectOutput = do_CreateInstance("mozilla.org/binaryoutputstream;1");
403 0 : if (!objectOutput) return NS_ERROR_OUT_OF_MEMORY;
404 : nsCOMPtr<nsIOutputStream> outputStream
405 0 : = do_QueryInterface(storageStream);
406 0 : objectOutput->SetOutputStream(outputStream);
407 : } else {
408 0 : rv = NewObjectOutputWrappedStorageStream(getter_AddRefs(objectOutput),
409 0 : getter_AddRefs(storageStream),
410 0 : false);
411 0 : NS_ENSURE_SUCCESS(rv, rv);
412 0 : mOutputStreamTable.Put(uri, storageStream);
413 : }
414 0 : objectOutput.forget(stream);
415 0 : return NS_OK;
416 : }
417 :
418 : nsresult
419 0 : nsXULPrototypeCache::FinishOutputStream(nsIURI* uri)
420 : {
421 : nsresult rv;
422 0 : StartupCache* sc = StartupCache::GetSingleton();
423 0 : if (!sc)
424 0 : return NS_ERROR_NOT_AVAILABLE;
425 :
426 0 : nsCOMPtr<nsIStorageStream> storageStream;
427 0 : bool found = mOutputStreamTable.Get(uri, getter_AddRefs(storageStream));
428 0 : if (!found)
429 0 : return NS_ERROR_UNEXPECTED;
430 : nsCOMPtr<nsIOutputStream> outputStream
431 0 : = do_QueryInterface(storageStream);
432 0 : outputStream->Close();
433 :
434 0 : UniquePtr<char[]> buf;
435 : uint32_t len;
436 0 : rv = NewBufferFromStorageStream(storageStream, &buf, &len);
437 0 : NS_ENSURE_SUCCESS(rv, rv);
438 :
439 0 : if (!mStartupCacheURITable.GetEntry(uri)) {
440 0 : nsAutoCString spec(kXULCachePrefix);
441 0 : rv = PathifyURI(uri, spec);
442 0 : if (NS_FAILED(rv))
443 0 : return NS_ERROR_NOT_AVAILABLE;
444 0 : rv = sc->PutBuffer(spec.get(), buf.get(), len);
445 0 : if (NS_SUCCEEDED(rv)) {
446 0 : mOutputStreamTable.Remove(uri);
447 0 : mStartupCacheURITable.PutEntry(uri);
448 : }
449 : }
450 :
451 0 : return rv;
452 : }
453 :
454 : // We have data if we're in the middle of writing it or we already
455 : // have it in the cache.
456 : nsresult
457 0 : nsXULPrototypeCache::HasData(nsIURI* uri, bool* exists)
458 : {
459 0 : if (mOutputStreamTable.Get(uri, nullptr)) {
460 0 : *exists = true;
461 0 : return NS_OK;
462 : }
463 0 : nsAutoCString spec(kXULCachePrefix);
464 0 : nsresult rv = PathifyURI(uri, spec);
465 0 : if (NS_FAILED(rv)) {
466 0 : *exists = false;
467 0 : return NS_OK;
468 : }
469 0 : UniquePtr<char[]> buf;
470 : uint32_t len;
471 0 : StartupCache* sc = StartupCache::GetSingleton();
472 0 : if (sc) {
473 0 : rv = sc->GetBuffer(spec.get(), &buf, &len);
474 : } else {
475 0 : *exists = false;
476 0 : return NS_OK;
477 : }
478 0 : *exists = NS_SUCCEEDED(rv);
479 0 : return NS_OK;
480 : }
481 :
482 : nsresult
483 6 : nsXULPrototypeCache::BeginCaching(nsIURI* aURI)
484 : {
485 : nsresult rv, tmp;
486 :
487 12 : nsAutoCString path;
488 6 : aURI->GetPath(path);
489 6 : if (!StringEndsWith(path, NS_LITERAL_CSTRING(".xul")))
490 0 : return NS_ERROR_NOT_AVAILABLE;
491 :
492 6 : StartupCache* startupCache = StartupCache::GetSingleton();
493 6 : if (!startupCache)
494 0 : return NS_ERROR_FAILURE;
495 :
496 6 : if (gDisableXULCache)
497 0 : return NS_ERROR_NOT_AVAILABLE;
498 :
499 : // Get the chrome directory to validate against the one stored in the
500 : // cache file, or to store there if we're generating a new file.
501 12 : nsCOMPtr<nsIFile> chromeDir;
502 6 : rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR, getter_AddRefs(chromeDir));
503 6 : if (NS_FAILED(rv))
504 0 : return rv;
505 12 : nsAutoCString chromePath;
506 6 : rv = chromeDir->GetNativePath(chromePath);
507 6 : if (NS_FAILED(rv))
508 0 : return rv;
509 :
510 : // XXXbe we assume the first package's locale is the same as the locale of
511 : // all subsequent packages of cached chrome URIs....
512 12 : nsAutoCString package;
513 6 : rv = aURI->GetHost(package);
514 6 : if (NS_FAILED(rv))
515 0 : return rv;
516 12 : nsAutoCString locale;
517 6 : LocaleService::GetInstance()->GetAppLocaleAsLangTag(locale);
518 :
519 12 : nsAutoCString fileChromePath, fileLocale;
520 :
521 12 : UniquePtr<char[]> buf;
522 : uint32_t len, amtRead;
523 12 : nsCOMPtr<nsIObjectInputStream> objectInput;
524 :
525 6 : rv = startupCache->GetBuffer(kXULCacheInfoKey, &buf, &len);
526 6 : if (NS_SUCCEEDED(rv))
527 12 : rv = NewObjectInputStreamFromBuffer(Move(buf), len,
528 18 : getter_AddRefs(objectInput));
529 :
530 6 : if (NS_SUCCEEDED(rv)) {
531 6 : rv = objectInput->ReadCString(fileLocale);
532 6 : tmp = objectInput->ReadCString(fileChromePath);
533 6 : if (NS_FAILED(tmp)) {
534 0 : rv = tmp;
535 : }
536 12 : if (NS_FAILED(rv) ||
537 12 : (!fileChromePath.Equals(chromePath) ||
538 6 : !fileLocale.Equals(locale))) {
539 : // Our cache won't be valid in this case, we'll need to rewrite.
540 : // XXX This blows away work that other consumers (like
541 : // mozJSComponentLoader) have done, need more fine-grained control.
542 0 : startupCache->InvalidateCache();
543 0 : mStartupCacheURITable.Clear();
544 0 : rv = NS_ERROR_UNEXPECTED;
545 : }
546 0 : } else if (rv != NS_ERROR_NOT_AVAILABLE)
547 : // NS_ERROR_NOT_AVAILABLE is normal, usually if there's no cachefile.
548 0 : return rv;
549 :
550 6 : if (NS_FAILED(rv)) {
551 : // Either the cache entry was invalid or it didn't exist, so write it now.
552 0 : nsCOMPtr<nsIObjectOutputStream> objectOutput;
553 0 : nsCOMPtr<nsIInputStream> inputStream;
554 0 : nsCOMPtr<nsIStorageStream> storageStream;
555 0 : rv = NewObjectOutputWrappedStorageStream(getter_AddRefs(objectOutput),
556 0 : getter_AddRefs(storageStream),
557 0 : false);
558 0 : if (NS_SUCCEEDED(rv)) {
559 0 : rv = objectOutput->WriteStringZ(locale.get());
560 0 : tmp = objectOutput->WriteStringZ(chromePath.get());
561 0 : if (NS_FAILED(tmp)) {
562 0 : rv = tmp;
563 : }
564 0 : tmp = objectOutput->Close();
565 0 : if (NS_FAILED(tmp)) {
566 0 : rv = tmp;
567 : }
568 0 : tmp = storageStream->NewInputStream(0, getter_AddRefs(inputStream));
569 0 : if (NS_FAILED(tmp)) {
570 0 : rv = tmp;
571 : }
572 : }
573 :
574 0 : if (NS_SUCCEEDED(rv)) {
575 : uint64_t len64;
576 0 : rv = inputStream->Available(&len64);
577 0 : if (NS_SUCCEEDED(rv)) {
578 0 : if (len64 <= UINT32_MAX)
579 0 : len = (uint32_t)len64;
580 : else
581 0 : rv = NS_ERROR_FILE_TOO_BIG;
582 : }
583 : }
584 :
585 0 : if (NS_SUCCEEDED(rv)) {
586 0 : buf = MakeUnique<char[]>(len);
587 0 : rv = inputStream->Read(buf.get(), len, &amtRead);
588 0 : if (NS_SUCCEEDED(rv) && len == amtRead)
589 0 : rv = startupCache->PutBuffer(kXULCacheInfoKey, buf.get(), len);
590 : else {
591 0 : rv = NS_ERROR_UNEXPECTED;
592 : }
593 : }
594 :
595 : // Failed again, just bail.
596 0 : if (NS_FAILED(rv)) {
597 0 : startupCache->InvalidateCache();
598 0 : mStartupCacheURITable.Clear();
599 0 : return NS_ERROR_FAILURE;
600 : }
601 : }
602 :
603 6 : return NS_OK;
604 : }
605 :
606 : void
607 0 : nsXULPrototypeCache::MarkInCCGeneration(uint32_t aGeneration)
608 : {
609 : StyleBackendType tableTypes[] = { StyleBackendType::Gecko,
610 0 : StyleBackendType::Servo };
611 :
612 0 : for (auto tableType : tableTypes) {
613 0 : XBLDocTable& xblDocTable = XBLDocTableFor(tableType);
614 0 : for (auto iter = xblDocTable.Iter(); !iter.Done(); iter.Next()) {
615 0 : iter.Data()->MarkInCCGeneration(aGeneration);
616 : }
617 : }
618 0 : for (auto iter = mPrototypeTable.Iter(); !iter.Done(); iter.Next()) {
619 0 : iter.Data()->MarkInCCGeneration(aGeneration);
620 : }
621 0 : }
622 :
623 : void
624 1 : nsXULPrototypeCache::MarkInGC(JSTracer* aTrc)
625 : {
626 38 : for (auto iter = mScriptTable.Iter(); !iter.Done(); iter.Next()) {
627 37 : JS::Heap<JSScript*>& script = iter.Data();
628 37 : JS::TraceEdge(aTrc, &script, "nsXULPrototypeCache script");
629 : }
630 1 : }
|