tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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