GlobalStyleSheetCache.cpp (22186B)
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 "GlobalStyleSheetCache.h" 8 9 #include "MainThreadUtils.h" 10 #include "mozilla/MemoryReporting.h" 11 #include "mozilla/NeverDestroyed.h" 12 #include "mozilla/Preferences.h" 13 #include "mozilla/ServoBindings.h" 14 #include "mozilla/StaticPrefs_layout.h" 15 #include "mozilla/StyleSheet.h" 16 #include "mozilla/StyleSheetInlines.h" 17 #include "mozilla/css/Loader.h" 18 #include "mozilla/dom/ReferrerInfo.h" 19 #include "mozilla/dom/SRIMetadata.h" 20 #include "mozilla/ipc/SharedMemoryHandle.h" 21 #include "mozilla/ipc/SharedMemoryMapping.h" 22 #include "nsAppDirectoryServiceDefs.h" 23 #include "nsContentUtils.h" 24 #include "nsExceptionHandler.h" 25 #include "nsIConsoleService.h" 26 #include "nsIFile.h" 27 #include "nsIObserverService.h" 28 #include "nsIXULRuntime.h" 29 #include "nsNetUtil.h" 30 #include "nsPrintfCString.h" 31 #include "nsServiceManagerUtils.h" 32 #include "nsXULAppAPI.h" 33 34 namespace mozilla { 35 36 // The GlobalStyleSheetCache is responsible for sharing user agent style sheet 37 // contents across processes using shared memory. Here is a high level view of 38 // how that works: 39 // 40 // * In the parent process, in the GlobalStyleSheetCache constructor (which is 41 // called early on in a process' lifetime), we parse all UA style sheets into 42 // Gecko StyleSheet objects. 43 // 44 // * The constructor calls InitSharedSheetsInParent, which creates a shared 45 // memory segment that we know ahead of time will be big enough to store the 46 // UA sheets. 47 // 48 // * It then creates a Rust SharedMemoryBuilder object and passes it a pointer 49 // to the start of the shared memory. 50 // 51 // * For each UA sheet, we call Servo_SharedMemoryBuilder_AddStylesheet, which 52 // takes the StylesheetContents::rules (an Arc<Locked<CssRules>>), produces a 53 // deep clone of it, and writes that clone into the shared memory: 54 // 55 // * The deep clone isn't a clone() call, but a call to ToShmem::to_shmem. The 56 // ToShmem trait must be implemented on every type that is reachable under 57 // the Arc<Locked<CssRules>>. The to_shmem call for each type will clone the 58 // value, but any heap allocation will be cloned and placed into the shared 59 // memory buffer, rather than heap allocated. 60 // 61 // * For most types, the ToShmem implementation is simple, and we just 62 // #[derive(ToShmem)] it. For the types that need special handling due to 63 // having heap allocations (Vec<T>, Box<T>, Arc<T>, etc.) we have impls that 64 // call to_shmem on the heap allocated data, and then create a new container 65 // (e.g. using Box::from_raw) that points into the shared memory. 66 // 67 // * Arc<T> and Locked<T> want to perform atomic writes on data that needs to 68 // be in the shared memory buffer (the reference count for Arc<T>, and the 69 // SharedRwLock's AtomicRefCell for Locked<T>), so we add special modes to 70 // those objects that skip the writes. For Arc<T>, that means never 71 // dropping the object since we don't track the reference count. That's 72 // fine, since we want to just drop the entire shared memory buffer at 73 // shutdown. For Locked<T>, we just panic on attempting to take the lock 74 // for writing. That's also fine, since we don't want devtools being able 75 // to modify UA sheets. 76 // 77 // * For Atoms in Rust, static atoms are represented by an index into the 78 // static atom table. Then if we need to Deref the Atom we look up the 79 // table. We panic if any Atom we encounter in the UA style sheets is 80 // not a static atom. 81 // 82 // * For each UA sheet, we create a new C++ StyleSheet object using the shared 83 // memory clone of the sheet contents, and throw away the original heap 84 // allocated one. (We could avoid creating a new C++ StyleSheet object 85 // wrapping the shared contents, and update the original StyleSheet object's 86 // contents, but it's doubtful that matters.) 87 // 88 // * When we initially map the shared memory in the parent process in 89 // InitSharedSheetsInParent, we choose an address which is far away from the 90 // current extent of the heap. Although not too far, since we don't want to 91 // unnecessarily fragment the virtual address space. 92 // 93 // * In the child process, as early as possible (in 94 // ContentChild::InitSharedUASheets), we try to map the shared memory at that 95 // same address, then pass the shared memory buffer to 96 // GlobalStyleSheetCache::SetSharedMemory. Since we map at the same 97 // address, this means any internal pointers in the UA sheets back into the 98 // shared memory buffer that were written by the parent process are valid in 99 // the child process too. 100 // 101 // * In practice, mapping at the address we need in the child process this works 102 // nearly all the time. If we fail to map at the address we need, the child 103 // process falls back to parsing and allocating its own copy of the UA sheets. 104 105 using namespace mozilla; 106 using namespace css; 107 108 mozilla::ipc::ReadOnlySharedMemoryHandle& sSharedMemoryHandle() { 109 static NeverDestroyed<mozilla::ipc::ReadOnlySharedMemoryHandle> handle; 110 return *handle; 111 } 112 113 #define PREF_LEGACY_STYLESHEET_CUSTOMIZATION \ 114 "toolkit.legacyUserProfileCustomizations.stylesheets" 115 116 NS_IMPL_ISUPPORTS(GlobalStyleSheetCache, nsIObserver, nsIMemoryReporter) 117 118 nsresult GlobalStyleSheetCache::Observe(nsISupports* aSubject, 119 const char* aTopic, 120 const char16_t* aData) { 121 if (!strcmp(aTopic, "profile-before-change")) { 122 mUserContentSheet = nullptr; 123 mUserChromeSheet = nullptr; 124 } else if (!strcmp(aTopic, "profile-do-change")) { 125 InitFromProfile(); 126 } else { 127 MOZ_ASSERT_UNREACHABLE("Unexpected observer topic."); 128 } 129 return NS_OK; 130 } 131 132 static constexpr struct { 133 nsLiteralCString mURL; 134 BuiltInStyleSheetFlags mFlags; 135 } kBuiltInSheetInfo[] = { 136 #define STYLE_SHEET(identifier_, url_, flags_) \ 137 {nsLiteralCString(url_), BuiltInStyleSheetFlags::flags_}, 138 #include "mozilla/BuiltInStyleSheetList.h" 139 #undef STYLE_SHEET 140 }; 141 142 NotNull<StyleSheet*> GlobalStyleSheetCache::BuiltInSheet( 143 BuiltInStyleSheet aSheet) { 144 auto& slot = mBuiltIns[aSheet]; 145 if (!slot) { 146 const auto& info = kBuiltInSheetInfo[size_t(aSheet)]; 147 const auto parsingMode = (info.mFlags & BuiltInStyleSheetFlags::UA) 148 ? eAgentSheetFeatures 149 : eAuthorSheetFeatures; 150 MOZ_ASSERT(info.mFlags & BuiltInStyleSheetFlags::UA || 151 info.mFlags & BuiltInStyleSheetFlags::Author); 152 slot = LoadSheetURL(info.mURL, parsingMode, eCrash); 153 } 154 return WrapNotNull(slot); 155 } 156 157 StyleSheet* GlobalStyleSheetCache::GetUserContentSheet() { 158 return mUserContentSheet; 159 } 160 161 StyleSheet* GlobalStyleSheetCache::GetUserChromeSheet() { 162 return mUserChromeSheet; 163 } 164 165 void GlobalStyleSheetCache::Shutdown() { 166 gCSSLoader = nullptr; 167 NS_WARNING_ASSERTION(!gStyleCache || !gUserContentSheetURL, 168 "Got the URL but never used?"); 169 gStyleCache = nullptr; 170 gUserContentSheetURL = nullptr; 171 for (auto& r : URLExtraData::sShared) { 172 r = nullptr; 173 } 174 // We want to leak the shared memory forever, rather than cleaning up all 175 // potential DOM references and such that chrome code may have created. 176 } 177 178 void GlobalStyleSheetCache::SetUserContentCSSURL(nsIURI* aURI) { 179 MOZ_ASSERT(XRE_IsContentProcess(), "Only used in content processes."); 180 gUserContentSheetURL = aURI; 181 } 182 183 MOZ_DEFINE_MALLOC_SIZE_OF(LayoutStylesheetCacheMallocSizeOf) 184 185 NS_IMETHODIMP 186 GlobalStyleSheetCache::CollectReports(nsIHandleReportCallback* aHandleReport, 187 nsISupports* aData, bool aAnonymize) { 188 MOZ_COLLECT_REPORT("explicit/layout/style-sheet-cache/unshared", KIND_HEAP, 189 UNITS_BYTES, 190 SizeOfIncludingThis(LayoutStylesheetCacheMallocSizeOf), 191 "Memory used for built-in style sheets that are not " 192 "shared between processes."); 193 194 if (XRE_IsParentProcess()) { 195 MOZ_COLLECT_REPORT( 196 "explicit/layout/style-sheet-cache/shared", KIND_NONHEAP, UNITS_BYTES, 197 sSharedMemory.IsEmpty() ? 0 : sUsedSharedMemory, 198 "Memory used for built-in style sheets that are shared to " 199 "child processes."); 200 } 201 202 return NS_OK; 203 } 204 205 size_t GlobalStyleSheetCache::SizeOfIncludingThis( 206 MallocSizeOf aMallocSizeOf) const { 207 size_t n = aMallocSizeOf(this); 208 209 #define MEASURE(s) n += s ? s->SizeOfIncludingThis(aMallocSizeOf) : 0; 210 211 for (const auto& sheet : mBuiltIns) { 212 MEASURE(sheet); 213 } 214 215 MEASURE(mUserChromeSheet); 216 MEASURE(mUserContentSheet); 217 218 // Measurement of the following members may be added later if DMD finds it is 219 // worthwhile: 220 // - gCSSLoader 221 222 return n; 223 } 224 225 GlobalStyleSheetCache::GlobalStyleSheetCache() { 226 nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService(); 227 NS_ASSERTION(obsSvc, "No global observer service?"); 228 229 if (obsSvc) { 230 obsSvc->AddObserver(this, "profile-before-change", false); 231 obsSvc->AddObserver(this, "profile-do-change", false); 232 } 233 234 // Load user style sheets. 235 InitFromProfile(); 236 237 if (XRE_IsParentProcess()) { 238 // We know we need xul.css for the UI, so load that now too: 239 XULSheet(); 240 } 241 242 if (gUserContentSheetURL) { 243 MOZ_ASSERT(XRE_IsContentProcess(), "Only used in content processes."); 244 mUserContentSheet = 245 LoadSheet(gUserContentSheetURL, eUserSheetFeatures, eLogToConsole); 246 gUserContentSheetURL = nullptr; 247 } 248 249 // If we are the in the parent process, then we load all of the UA sheets that 250 // are shareable and store them into shared memory. In both the parent and 251 // the content process, we load these sheets out of shared memory. 252 // 253 // The shared memory buffer's format is a Header object, which contains 254 // internal pointers to each of the shared style sheets, followed by the style 255 // sheets themselves. 256 if (StaticPrefs::layout_css_shared_memory_ua_sheets_enabled()) { 257 if (XRE_IsParentProcess()) { 258 // Load the style sheets and store them in a new shared memory buffer. 259 InitSharedSheetsInParent(); 260 } else if (!sSharedMemory.IsEmpty()) { 261 // Use the shared memory that was given to us by a SetSharedMemory call 262 // under ContentChild::InitXPCOM. 263 MOZ_ASSERT(sSharedMemory.data(), 264 "GlobalStyleSheetCache::SetSharedMemory should have mapped " 265 "the shared memory"); 266 } 267 } 268 269 // If we get here and we don't have a shared memory handle, then it means 270 // either we failed to create the shared memory buffer in the parent process 271 // (unexpected), or we failed to map the shared memory buffer at the address 272 // we needed in the content process (might happen). 273 // 274 // If sSharedMemory is non-null, but it is not currently mapped, then it means 275 // we are in the parent process, and we failed to re-map the memory after 276 // freezing it. (We keep sSharedMemory around so that we can still share it 277 // to content processes.) 278 // 279 // In the parent process, this means we'll just leave our eagerly loaded 280 // non-shared sheets in the mFooSheet fields. In a content process, we'll 281 // lazily load our own copies of the sheets later. 282 if (!sSharedMemory.IsEmpty()) { 283 if (const auto* header = 284 reinterpret_cast<const Header*>(sSharedMemory.data())) { 285 MOZ_RELEASE_ASSERT(header->mMagic == Header::kMagic); 286 287 for (auto kind : MakeEnumeratedRange(BuiltInStyleSheet::Count)) { 288 const auto& info = kBuiltInSheetInfo[size_t(kind)]; 289 if (info.mFlags & BuiltInStyleSheetFlags::NotShared) { 290 continue; 291 } 292 const auto parsingMode = (info.mFlags & BuiltInStyleSheetFlags::UA) 293 ? eAgentSheetFeatures 294 : eAuthorSheetFeatures; 295 LoadSheetFromSharedMemory(info.mURL, &mBuiltIns[kind], parsingMode, 296 header, kind); 297 } 298 } 299 } 300 } 301 302 void GlobalStyleSheetCache::LoadSheetFromSharedMemory( 303 const nsACString& aURL, RefPtr<StyleSheet>* aSheet, 304 SheetParsingMode aParsingMode, const Header* aHeader, 305 BuiltInStyleSheet aSheetID) { 306 auto i = size_t(aSheetID); 307 308 auto sheet = 309 MakeRefPtr<StyleSheet>(aParsingMode, CORS_NONE, dom::SRIMetadata()); 310 311 nsCOMPtr<nsIURI> uri; 312 MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), aURL)); 313 314 nsCOMPtr<nsIReferrerInfo> referrerInfo = 315 dom::ReferrerInfo::CreateForExternalCSSResources(sheet, uri); 316 sheet->SetURIs(uri, uri, referrerInfo, nsContentUtils::GetSystemPrincipal()); 317 sheet->SetSharedContents(aHeader->mSheets[i]); 318 sheet->SetComplete(); 319 URLExtraData::sShared[i] = sheet->URLData(); 320 321 *aSheet = std::move(sheet); 322 } 323 324 void GlobalStyleSheetCache::InitSharedSheetsInParent() { 325 MOZ_ASSERT(XRE_IsParentProcess()); 326 MOZ_RELEASE_ASSERT(sSharedMemory.IsEmpty()); 327 328 auto handle = ipc::shared_memory::CreateFreezable(kSharedMemorySize); 329 if (NS_WARN_IF(!handle)) { 330 return; 331 } 332 333 // We need to choose an address to map the shared memory in the parent process 334 // that we'll also be able to use in content processes. There's no way to 335 // pick an address that is guaranteed to be free in future content processes, 336 // so instead we pick an address that is some distance away from current heap 337 // allocations and hope that by the time the content process maps the shared 338 // memory, that address will be free. 339 // 340 // On 64 bit, we have a large amount of address space, so we pick an address 341 // half way through the next 8 GiB of free space, and this has a very good 342 // chance of succeeding. On 32 bit, address space is more constrained. We 343 // only have 3 GiB of space to work with, and we don't want to pick a location 344 // right in the middle, since that could cause future large allocations to 345 // fail. So we pick an address half way through the next 512 MiB of free 346 // space. Experimentally this seems to work 9 times out of 10; this is good 347 // enough, as it means only 1 in 10 content processes will have its own unique 348 // copies of the UA style sheets, and we're still getting a significant 349 // overall memory saving. 350 // 351 // In theory ASLR could reduce the likelihood of the mapping succeeding in 352 // content processes, due to our expectations of where the heap is being 353 // wrong, but in practice this isn't an issue. 354 #ifdef HAVE_64BIT_BUILD 355 constexpr size_t kOffset = 0x200000000ULL; // 8 GiB 356 #else 357 constexpr size_t kOffset = 0x20000000; // 512 MiB 358 #endif 359 360 void* address = nullptr; 361 if (void* p = ipc::shared_memory::FindFreeAddressSpace(2 * kOffset)) { 362 address = reinterpret_cast<void*>(uintptr_t(p) + kOffset); 363 } 364 365 auto mapping = std::move(handle).Map(address); 366 if (!mapping) { 367 // Failed to map at the address we computed for some reason. Fall back 368 // to just allocating at a location of the OS's choosing, and hope that 369 // it works in the content process. 370 auto handle = std::move(mapping).Unmap(); 371 mapping = std::move(handle).Map(); 372 if (NS_WARN_IF(!mapping)) { 373 return; 374 } 375 } 376 address = mapping.Address(); 377 378 auto* header = static_cast<Header*>(address); 379 header->mMagic = Header::kMagic; 380 #ifdef DEBUG 381 for (const auto* ptr : header->mSheets) { 382 MOZ_RELEASE_ASSERT(!ptr, "expected shared memory to have been zeroed"); 383 } 384 #endif 385 386 UniquePtr<StyleSharedMemoryBuilder> builder(Servo_SharedMemoryBuilder_Create( 387 header->mBuffer, kSharedMemorySize - offsetof(Header, mBuffer))); 388 389 nsCString message; 390 391 // Copy each one into the shared memory, and record its pointer. 392 // 393 // Normally calling ToShared on UA sheets should not fail. It happens 394 // in practice in odd cases that seem like corrupted installations; see bug 395 // 1621773. On failure, return early and fall back to non-shared sheets. 396 for (auto kind : MakeEnumeratedRange(BuiltInStyleSheet::Count)) { 397 auto i = size_t(kind); 398 const auto& info = kBuiltInSheetInfo[i]; 399 if (info.mFlags & BuiltInStyleSheetFlags::NotShared) { 400 continue; 401 } 402 StyleSheet* sheet = BuiltInSheet(kind); 403 URLExtraData::sShared[i] = sheet->URLData(); 404 header->mSheets[i] = sheet->ToShared(builder.get(), message); 405 if (!header->mSheets[i]) { 406 CrashReporter::AppendAppNotesToCrashReport("\n"_ns + message); 407 return; 408 } 409 } 410 411 // Finished writing into the shared memory. Freeze it, so that a process 412 // can't confuse other processes by changing the UA style sheet contents. 413 auto readOnlyHandle = std::move(mapping).Freeze(); 414 if (NS_WARN_IF(!readOnlyHandle)) { 415 return; 416 } 417 418 auto roMapping = readOnlyHandle.Map(address); 419 420 // Record how must of the shared memory we have used, for memory reporting 421 // later. We round up to the nearest page since the free space at the end 422 // of the page isn't really usable for anything else. 423 // 424 // TODO(heycam): This won't be true on Windows unless we allow creating the 425 // shared memory with SEC_RESERVE so that the pages are reserved but not 426 // committed. 427 size_t pageSize = ipc::shared_memory::SystemPageSize(); 428 sUsedSharedMemory = 429 (Servo_SharedMemoryBuilder_GetLength(builder.get()) + pageSize - 1) & 430 ~(pageSize - 1); 431 432 sSharedMemory = std::move(roMapping).Release(); 433 sSharedMemoryHandle() = std::move(readOnlyHandle); 434 } 435 436 GlobalStyleSheetCache::~GlobalStyleSheetCache() { 437 UnregisterWeakMemoryReporter(this); 438 } 439 440 void GlobalStyleSheetCache::InitMemoryReporter() { 441 RegisterWeakMemoryReporter(this); 442 } 443 444 /* static */ 445 GlobalStyleSheetCache* GlobalStyleSheetCache::Singleton() { 446 MOZ_ASSERT(NS_IsMainThread()); 447 448 if (!gStyleCache) { 449 gStyleCache = new GlobalStyleSheetCache; 450 gStyleCache->InitMemoryReporter(); 451 452 // For each pref that controls a CSS feature that a UA style sheet depends 453 // on (such as a pref that enables a property that a UA style sheet uses), 454 // register DependentPrefChanged as a callback to ensure that the relevant 455 // style sheets will be re-parsed. 456 // Preferences::RegisterCallback(&DependentPrefChanged, 457 // "layout.css.example-pref.enabled"); 458 } 459 460 return gStyleCache; 461 } 462 463 void GlobalStyleSheetCache::InitFromProfile() { 464 if (!Preferences::GetBool(PREF_LEGACY_STYLESHEET_CUSTOMIZATION)) { 465 return; 466 } 467 468 nsCOMPtr<nsIXULRuntime> appInfo = 469 do_GetService("@mozilla.org/xre/app-info;1"); 470 if (appInfo) { 471 bool inSafeMode = false; 472 appInfo->GetInSafeMode(&inSafeMode); 473 if (inSafeMode) { 474 return; 475 } 476 } 477 nsCOMPtr<nsIFile> contentFile; 478 nsCOMPtr<nsIFile> chromeFile; 479 480 NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR, getter_AddRefs(contentFile)); 481 if (!contentFile) { 482 // if we don't have a profile yet, that's OK! 483 return; 484 } 485 486 contentFile->Clone(getter_AddRefs(chromeFile)); 487 if (!chromeFile) { 488 return; 489 } 490 491 contentFile->Append(u"userContent.css"_ns); 492 chromeFile->Append(u"userChrome.css"_ns); 493 494 mUserContentSheet = LoadSheetFile(contentFile, eUserSheetFeatures); 495 mUserChromeSheet = LoadSheetFile(chromeFile, eUserSheetFeatures); 496 } 497 498 RefPtr<StyleSheet> GlobalStyleSheetCache::LoadSheetURL( 499 const nsACString& aURL, SheetParsingMode aParsingMode, 500 FailureAction aFailureAction) { 501 nsCOMPtr<nsIURI> uri; 502 NS_NewURI(getter_AddRefs(uri), aURL); 503 return LoadSheet(uri, aParsingMode, aFailureAction); 504 } 505 506 RefPtr<StyleSheet> GlobalStyleSheetCache::LoadSheetFile( 507 nsIFile* aFile, SheetParsingMode aParsingMode) { 508 bool exists = false; 509 aFile->Exists(&exists); 510 if (!exists) { 511 return nullptr; 512 } 513 514 nsCOMPtr<nsIURI> uri; 515 NS_NewFileURI(getter_AddRefs(uri), aFile); 516 return LoadSheet(uri, aParsingMode, eLogToConsole); 517 } 518 519 static void ErrorLoadingSheet(nsIURI* aURI, const char* aMsg, 520 FailureAction aFailureAction) { 521 nsPrintfCString errorMessage("%s loading built-in stylesheet '%s'", aMsg, 522 aURI ? aURI->GetSpecOrDefault().get() : ""); 523 if (aFailureAction == eLogToConsole) { 524 nsCOMPtr<nsIConsoleService> cs = 525 do_GetService(NS_CONSOLESERVICE_CONTRACTID); 526 if (cs) { 527 cs->LogStringMessage(NS_ConvertUTF8toUTF16(errorMessage).get()); 528 return; 529 } 530 } 531 532 MOZ_CRASH_UNSAFE(errorMessage.get()); 533 } 534 535 RefPtr<StyleSheet> GlobalStyleSheetCache::LoadSheet( 536 nsIURI* aURI, SheetParsingMode aParsingMode, FailureAction aFailureAction) { 537 if (!aURI) { 538 ErrorLoadingSheet(aURI, "null URI", eCrash); 539 return nullptr; 540 } 541 542 if (!gCSSLoader) { 543 gCSSLoader = new Loader; 544 } 545 546 auto result = gCSSLoader->LoadSheetSync(aURI, aParsingMode, 547 css::Loader::UseSystemPrincipal::Yes); 548 if (MOZ_UNLIKELY(result.isErr())) { 549 ErrorLoadingSheet( 550 aURI, 551 nsPrintfCString("LoadSheetSync failed with error %" PRIx32, 552 static_cast<uint32_t>(result.unwrapErr())) 553 .get(), 554 aFailureAction); 555 } 556 return result.unwrapOr(nullptr); 557 } 558 559 /* static */ void GlobalStyleSheetCache::SetSharedMemory( 560 ipc::ReadOnlySharedMemoryHandle aHandle, uintptr_t aAddress) { 561 MOZ_ASSERT(!XRE_IsParentProcess()); 562 MOZ_ASSERT(!gStyleCache, "Too late, GlobalStyleSheetCache already created!"); 563 MOZ_ASSERT(sSharedMemory.IsEmpty(), "Shouldn't call this more than once"); 564 565 auto mapping = aHandle.Map(reinterpret_cast<void*>(aAddress)); 566 if (!mapping) { 567 return; 568 } 569 570 sSharedMemory = std::move(mapping).Release(); 571 sSharedMemoryHandle() = std::move(aHandle); 572 } 573 574 ipc::ReadOnlySharedMemoryHandle GlobalStyleSheetCache::CloneHandle() { 575 MOZ_ASSERT(XRE_IsParentProcess()); 576 if (sSharedMemoryHandle().IsValid()) { 577 return sSharedMemoryHandle().Clone(); 578 } 579 return nullptr; 580 } 581 582 StaticRefPtr<GlobalStyleSheetCache> GlobalStyleSheetCache::gStyleCache; 583 StaticRefPtr<css::Loader> GlobalStyleSheetCache::gCSSLoader; 584 StaticRefPtr<nsIURI> GlobalStyleSheetCache::gUserContentSheetURL; 585 586 ipc::shared_memory::LeakedReadOnlyMapping GlobalStyleSheetCache::sSharedMemory; 587 size_t GlobalStyleSheetCache::sUsedSharedMemory; 588 589 } // namespace mozilla