Bug 1474793 - Part 13: Build and use shared memory user agent style sheets in parent and content processes. r=emilio,kmag

MozReview-Commit-ID: JasksR7F22Z

Depends on D17199

Differential Revision: https://phabricator.services.mozilla.com/D17200

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Cameron McCormack 2019-03-30 00:23:49 +00:00
Родитель 12c03087aa
Коммит 3357fd0d3a
11 изменённых файлов: 387 добавлений и 37 удалений

Просмотреть файл

@ -591,7 +591,9 @@ NS_INTERFACE_MAP_END
mozilla::ipc::IPCResult ContentChild::RecvSetXPCOMProcessAttributes(
const XPCOMInitData& aXPCOMInit, const StructuredCloneData& aInitialData,
nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache,
nsTArray<SystemFontListEntry>&& aFontList) {
nsTArray<SystemFontListEntry>&& aFontList,
const Maybe<SharedMemoryHandle>& aSharedUASheetHandle,
const uintptr_t& aSharedUASheetAddress) {
if (!sShutdownCanary) {
return IPC_OK();
}
@ -599,6 +601,7 @@ mozilla::ipc::IPCResult ContentChild::RecvSetXPCOMProcessAttributes(
mLookAndFeelCache = std::move(aLookAndFeelIntCache);
mFontList = std::move(aFontList);
gfx::gfxVars::SetValuesForInitialize(aXPCOMInit.gfxNonDefaultVarUpdates());
InitSharedUASheets(aSharedUASheetHandle, aSharedUASheetAddress);
InitXPCOM(aXPCOMInit, aInitialData);
InitGraphicsDeviceData(aXPCOMInit.contentDeviceData());
@ -1198,6 +1201,20 @@ void ContentChild::InitGraphicsDeviceData(const ContentDeviceData& aData) {
gfxPlatform::InitChild(aData);
}
void ContentChild::InitSharedUASheets(const Maybe<SharedMemoryHandle>& aHandle,
uintptr_t aAddress) {
MOZ_ASSERT_IF(!aHandle, !aAddress);
if (!aAddress) {
return;
}
// Map the shared memory storing the user agent style sheets. Do this as
// early as possible to maximize the chance of being able to map at the
// address we want.
nsLayoutStylesheetCache::SetSharedMemory(*aHandle, aAddress);
}
void ContentChild::InitXPCOM(
const XPCOMInitData& aXPCOMInit,
const mozilla::dom::ipc::StructuredCloneData& aInitialData) {

Просмотреть файл

@ -7,6 +7,7 @@
#ifndef mozilla_dom_ContentChild_h
#define mozilla_dom_ContentChild_h
#include "base/shared_memory.h"
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/PBrowserOrId.h"
@ -125,6 +126,9 @@ class ContentChild final : public PContentChild,
void InitXPCOM(const XPCOMInitData& aXPCOMInit,
const mozilla::dom::ipc::StructuredCloneData& aInitialData);
void InitSharedUASheets(const Maybe<base::SharedMemoryHandle>& aHandle,
uintptr_t aAddress);
void InitGraphicsDeviceData(const ContentDeviceData& aData);
static ContentChild* GetSingleton() { return sSingleton; }
@ -585,7 +589,9 @@ class ContentChild final : public PContentChild,
mozilla::ipc::IPCResult RecvSetXPCOMProcessAttributes(
const XPCOMInitData& aXPCOMInit, const StructuredCloneData& aInitialData,
nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache,
nsTArray<SystemFontListEntry>&& aFontList);
nsTArray<SystemFontListEntry>&& aFontList,
const Maybe<base::SharedMemoryHandle>& aSharedUASheetHandle,
const uintptr_t& aSharedUASheetAddress);
mozilla::ipc::IPCResult RecvProvideAnonymousTemporaryFile(
const uint64_t& aID, const FileDescOrError& aFD);

Просмотреть файл

@ -2464,8 +2464,21 @@ void ContentParent::InitInternal(ProcessPriority aInitialPriority) {
ScreenManager& screenManager = ScreenManager::GetSingleton();
screenManager.CopyScreensToRemote(this);
// Send the UA sheet shared memory buffer and the address it is mapped at.
auto cache = nsLayoutStylesheetCache::Singleton();
Maybe<SharedMemoryHandle> sharedUASheetHandle;
uintptr_t sharedUASheetAddress = cache->GetSharedMemoryAddress();
SharedMemoryHandle handle;
if (cache->ShareToProcess(OtherPid(), &handle)) {
sharedUASheetHandle.emplace(handle);
} else {
sharedUASheetAddress = 0;
}
Unused << SendSetXPCOMProcessAttributes(xpcomInit, initialData, lnfCache,
fontList);
fontList, sharedUASheetHandle,
sharedUASheetAddress);
ipc::WritableSharedMap* sharedData =
nsFrameMessageManager::sParentProcessManager->SharedData();

Просмотреть файл

@ -101,6 +101,7 @@ using mozilla::dom::BrowsingContextId from "mozilla/dom/ipc/IdType.h";
using mozilla::dom::BrowsingContextTransaction from "mozilla/dom/BrowsingContext.h";
using mozilla::dom::BrowsingContextFieldEpochs from "mozilla/dom/BrowsingContext.h";
using mozilla::dom::BrowsingContextInitializer from "mozilla/dom/BrowsingContext.h";
using base::SharedMemoryHandle from "base/shared_memory.h";
union ChromeRegistryItem
{
@ -563,7 +564,9 @@ child:
StructuredCloneData initialData,
LookAndFeelInt[] lookAndFeelIntCache,
/* used on MacOSX and Linux only: */
SystemFontListEntry[] systemFontList);
SystemFontListEntry[] systemFontList,
SharedMemoryHandle? sharedUASheetHandle,
uintptr_t sharedUASheetAddress);
// Notify child that last-pb-context-exited notification was observed
async LastPrivateDocShellDestroyed();

Просмотреть файл

@ -23,6 +23,7 @@
#include "mozilla/StyleSheetInlines.h"
#include "mozAutoDocUpdate.h"
#include "nsLayoutStylesheetCache.h"
namespace mozilla {
@ -303,6 +304,10 @@ StyleSheetInfo::StyleSheetInfo(StyleSheetInfo& aCopy, StyleSheet* aPrimarySheet)
mSourceURL(aCopy.mSourceURL),
mContents(Servo_StyleSheet_Clone(aCopy.mContents.get(), aPrimarySheet)
.Consume()),
// Cloning aCopy.mContents will still leave us with some references to
// data in shared memory (for example, any SelectorList objects will still
// be shared), so continue to keep it alive.
mSharedMemory(aCopy.mSharedMemory),
mURLData(aCopy.mURLData)
#ifdef DEBUG
,
@ -315,7 +320,12 @@ StyleSheetInfo::StyleSheetInfo(StyleSheetInfo& aCopy, StyleSheet* aPrimarySheet)
MOZ_COUNT_CTOR(StyleSheetInfo);
}
StyleSheetInfo::~StyleSheetInfo() { MOZ_COUNT_DTOR(StyleSheetInfo); }
StyleSheetInfo::~StyleSheetInfo() {
MOZ_COUNT_DTOR(StyleSheetInfo);
// Drop the sheet contents before the shared memory.
mContents = nullptr;
}
StyleSheetInfo* StyleSheetInfo::CloneFor(StyleSheet* aPrimarySheet) {
return new StyleSheetInfo(*this, aPrimarySheet);
@ -326,9 +336,15 @@ MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleSheetMallocEnclosingSizeOf)
size_t StyleSheetInfo::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
size_t n = aMallocSizeOf(this);
n += Servo_StyleSheet_SizeOfIncludingThis(
ServoStyleSheetMallocSizeOf, ServoStyleSheetMallocEnclosingSizeOf,
mContents);
// If this sheet came from shared memory, then it will be counted by
// nsLayoutStylesheetCache in the parent process.
if (!mSharedMemory) {
n += Servo_StyleSheet_SizeOfIncludingThis(
ServoStyleSheetMallocSizeOf, ServoStyleSheetMallocEnclosingSizeOf,
mContents);
}
return n;
}
@ -1165,4 +1181,35 @@ OriginFlags StyleSheet::GetOrigin() {
Servo_StyleSheet_GetOrigin(Inner().mContents));
}
void StyleSheet::SetSharedContents(nsLayoutStylesheetCache::Shm* aSharedMemory,
const ServoCssRules* aSharedRules) {
MOZ_ASSERT(aSharedMemory);
MOZ_ASSERT(!IsComplete());
SetURLExtraData();
// Hold a strong reference to the shared memory that aSharedRules comes
// from, so that we don't end up releasing the shared memory before the
// StyleSheetInner.
Inner().mSharedMemory = aSharedMemory;
Inner().mContents =
Servo_StyleSheet_FromSharedData(Inner().mURLData, aSharedRules).Consume();
// Don't call FinishParse(), since that tries to set source map URLs,
// which we don't have.
}
const ServoCssRules* StyleSheet::ToShared(
RawServoSharedMemoryBuilder* aBuilder) {
// Assert some things we assume when creating a StyleSheet using shared
// memory.
MOZ_ASSERT(GetReferrerPolicy() == net::RP_Unset);
MOZ_ASSERT(GetCORSMode() == CORS_NONE);
MOZ_ASSERT(Inner().mIntegrity.IsEmpty());
MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(Principal()));
return Servo_SharedMemoryBuilder_AddStylesheet(aBuilder, Inner().mContents);
}
} // namespace mozilla

Просмотреть файл

@ -25,6 +25,8 @@
class nsINode;
class nsIPrincipal;
struct nsLayoutStylesheetCacheShm;
struct RawServoSharedMemoryBuilder;
namespace mozilla {
@ -376,6 +378,17 @@ class StyleSheet final : public nsICSSLoaderObserver, public nsWrapperCache {
}
}
// Copy the contents of this style sheet into the shared memory buffer managed
// by aBuilder. Returns the pointer into the buffer that the sheet contents
// were stored at. (The returned pointer is to an Arc<Locked<Rules>> value.)
const ServoCssRules* ToShared(RawServoSharedMemoryBuilder* aBuilder);
// Sets the contents of this style sheet to the specified aSharedRules
// pointer, which must be a pointer somewhere in the aSharedMemory buffer
// as previously returned by a ToShared() call.
void SetSharedContents(nsLayoutStylesheetCacheShm* aSharedMemory,
const ServoCssRules* aSharedRules);
private:
dom::ShadowRoot* GetContainingShadow() const;

Просмотреть файл

@ -15,6 +15,7 @@
#include "nsIURI.h"
class nsIPrincipal;
struct nsLayoutStylesheetCacheShm;
namespace mozilla {
class StyleSheet;
@ -77,6 +78,12 @@ struct StyleSheetInfo final {
RefPtr<const RawServoStyleSheetContents> mContents;
// The shared memory buffer that stores the rules in the style sheet, if
// this style sheet was loaded from the style sheet cache's shared memory.
//
// We need to hold on to this so it doesn't go away before we do.
RefPtr<nsLayoutStylesheetCacheShm> mSharedMemory;
// XXX We already have mSheetURI, mBaseURI, and mPrincipal.
//
// Can we somehow replace them with URLExtraData directly? The issue

Просмотреть файл

@ -7,7 +7,7 @@
/* list of user agent style sheets that nsLayoutStylesheetCache manages */
/*
* STYLE_SHEET(identifier_, url_, lazy_)
* STYLE_SHEET(identifier_, url_, shared_)
*
* identifier_
* An identifier for the style sheet, suitable for use as an enum class value.
@ -15,22 +15,23 @@
* url_
* The URL of the style sheet.
*
* lazy_
* A boolean indicating whether the sheet is loaded lazily.
* shared_
* A boolean indicating whether the sheet can be safely placed in shared
* memory.
*/
STYLE_SHEET(ContentEditable, "resource://gre/res/contenteditable.css", true)
STYLE_SHEET(CounterStyles, "resource://gre-resources/counterstyles.css", false)
STYLE_SHEET(CounterStyles, "resource://gre-resources/counterstyles.css", true)
STYLE_SHEET(DesignMode, "resource://gre/res/designmode.css", true)
STYLE_SHEET(Forms, "resource://gre-resources/forms.css", true)
STYLE_SHEET(HTML, "resource://gre-resources/html.css", false)
STYLE_SHEET(HTML, "resource://gre-resources/html.css", true)
STYLE_SHEET(MathML, "resource://gre-resources/mathml.css", true)
STYLE_SHEET(MinimalXUL, "chrome://global/content/minimal-xul.css", false)
STYLE_SHEET(MinimalXUL, "chrome://global/content/minimal-xul.css", true)
STYLE_SHEET(NoFrames, "resource://gre-resources/noframes.css", true)
STYLE_SHEET(NoScript, "resource://gre-resources/noscript.css", true)
STYLE_SHEET(PluginProblem, "resource://gre-resources/pluginproblem.css", true)
STYLE_SHEET(Quirk, "resource://gre-resources/quirk.css", false)
STYLE_SHEET(Quirk, "resource://gre-resources/quirk.css", true)
STYLE_SHEET(Scrollbars, "chrome://global/skin/scrollbars.css", true)
STYLE_SHEET(SVG, "resource://gre/res/svg.css", false)
STYLE_SHEET(SVG, "resource://gre/res/svg.css", true)
STYLE_SHEET(UA, "resource://gre-resources/ua.css", true)
STYLE_SHEET(XUL, "chrome://global/content/xul.css", true)
STYLE_SHEET(XUL, "chrome://global/content/xul.css", false)

Просмотреть файл

@ -14,8 +14,10 @@
#include "mozilla/Telemetry.h"
#include "mozilla/css/Loader.h"
#include "mozilla/dom/SRIMetadata.h"
#include "mozilla/ipc/SharedMemory.h"
#include "MainThreadUtils.h"
#include "nsColor.h"
#include "nsContentUtils.h"
#include "nsIConsoleService.h"
#include "nsIFile.h"
#include "nsIObserverService.h"
@ -26,6 +28,8 @@
#include "nsServiceManagerUtils.h"
#include "nsXULAppAPI.h"
#include <mozilla/ServoBindings.h>
using namespace mozilla;
using namespace mozilla::css;
@ -49,9 +53,9 @@ nsresult nsLayoutStylesheetCache::Observe(nsISupports* aSubject,
return NS_OK;
}
#define STYLE_SHEET(identifier_, url_, lazy_) \
#define STYLE_SHEET(identifier_, url_, shared_) \
NotNull<StyleSheet*> nsLayoutStylesheetCache::identifier_##Sheet() { \
if (lazy_ && !m##identifier_##Sheet) { \
if (!m##identifier_##Sheet) { \
LoadSheetURL(url_, &m##identifier_##Sheet, eAgentSheetFeatures, eCrash); \
} \
return WrapNotNull(m##identifier_##Sheet); \
@ -94,6 +98,10 @@ void nsLayoutStylesheetCache::Shutdown() {
for (auto& r : URLExtraData::sShared) {
r = nullptr;
}
// Some content processes don't get around to consuming the shared memory
// buffer we store in sSharedMemory (e.g. a preloaded content process that
// doesn't get a document loaded in it), so clear it out here to avoid leaks.
sSharedMemory = nullptr;
}
void nsLayoutStylesheetCache::SetUserContentCSSURL(nsIURI* aURI) {
@ -106,10 +114,19 @@ MOZ_DEFINE_MALLOC_SIZE_OF(LayoutStylesheetCacheMallocSizeOf)
NS_IMETHODIMP
nsLayoutStylesheetCache::CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize) {
MOZ_COLLECT_REPORT("explicit/layout/style-sheet-cache", KIND_HEAP,
MOZ_COLLECT_REPORT("explicit/layout/style-sheet-cache/unshared", KIND_HEAP,
UNITS_BYTES,
SizeOfIncludingThis(LayoutStylesheetCacheMallocSizeOf),
"Memory used for some built-in style sheets.");
"Memory used for built-in style sheets that are not "
"shared between processes.");
if (XRE_IsParentProcess()) {
MOZ_COLLECT_REPORT(
"explicit/layout/style-sheet-cache/shared", KIND_NONHEAP, UNITS_BYTES,
mSharedMemory ? mUsedSharedMemory : 0,
"Memory used for built-in style sheets that are shared to "
"child processes.");
}
return NS_OK;
}
@ -120,7 +137,7 @@ size_t nsLayoutStylesheetCache::SizeOfIncludingThis(
#define MEASURE(s) n += s ? s->SizeOfIncludingThis(aMallocSizeOf) : 0;
#define STYLE_SHEET(identifier_, url_, lazy_) MEASURE(m##identifier_##Sheet);
#define STYLE_SHEET(identifier_, url_, shared_) MEASURE(m##identifier_##Sheet);
#include "mozilla/UserAgentStyleSheetList.h"
#undef STYLE_SHEET
@ -136,7 +153,7 @@ size_t nsLayoutStylesheetCache::SizeOfIncludingThis(
return n;
}
nsLayoutStylesheetCache::nsLayoutStylesheetCache() {
nsLayoutStylesheetCache::nsLayoutStylesheetCache() : mUsedSharedMemory(0) {
nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
NS_ASSERTION(obsSvc, "No global observer service?");
@ -147,17 +164,9 @@ nsLayoutStylesheetCache::nsLayoutStylesheetCache() {
obsSvc->AddObserver(this, "chrome-flush-caches", false);
}
// Load user style sheets.
InitFromProfile();
// And make sure that we load our UA sheets. No need to do this
// per-profile, since they're profile-invariant.
#define STYLE_SHEET(identifier_, url_, lazy_) \
if (!lazy_) { \
LoadSheetURL(url_, &m##identifier_##Sheet, eAgentSheetFeatures, eCrash); \
}
#include "mozilla/UserAgentStyleSheetList.h"
#undef STYLE_SHEET
if (XRE_IsParentProcess()) {
// We know we need xul.css for the UI, so load that now too:
XULSheet();
@ -170,9 +179,147 @@ nsLayoutStylesheetCache::nsLayoutStylesheetCache() {
gUserContentSheetURL = nullptr;
}
// The remaining sheets are created on-demand do to their use being rarer
// (which helps save memory for Firefox OS apps) or because they need to
// be re-loadable in DependentPrefChanged.
// If we are the in the parent process, then we load all of the UA sheets that
// are shareable and store them into shared memory. In both the parent and
// the content process, we load these sheets out of shared memory.
//
// The shared memory buffer's format is a Header object, which contains
// internal pointers to each of the shared style sheets, followed by the style
// sheets themselves.
if (StaticPrefs::layout_css_shared_memory_ua_sheets_enabled()) {
if (XRE_IsParentProcess()) {
MOZ_ASSERT(!sSharedMemory);
// Load the style sheets and store them in a new shared memory buffer.
InitSharedSheetsInParent();
} else if (sSharedMemory) {
// Use the shared memory handle that was given to us by a SetSharedMemory
// call under ContentChild::InitXPCOM.
mSharedMemory = sSharedMemory.forget();
}
}
// If we get here and we don't have a shared memory handle, then it means
// either we failed to create the shared memory buffer in the parent process
// (unexpected), or we failed to map the shared memory buffer at the address
// we needed in the content process (might happen).
//
// In the parent process, this means we'll just leave our eagerly loaded
// non-shared sheets in the mFooSheet fields. In a content process, we'll
// lazily load our own copies of the sheets later.
if (mSharedMemory) {
Header* header = static_cast<Header*>(mSharedMemory->mShm.memory());
MOZ_RELEASE_ASSERT(header->mMagic == Header::kMagic);
#define STYLE_SHEET(identifier_, url_, shared_) \
if (shared_) { \
LoadSheetFromSharedMemory(url_, &m##identifier_##Sheet, \
eAgentSheetFeatures, mSharedMemory, header, \
UserAgentStyleSheetID::identifier_); \
}
#include "mozilla/UserAgentStyleSheetList.h"
#undef STYLE_SHEET
}
}
void nsLayoutStylesheetCache::LoadSheetFromSharedMemory(
const char* aURL, RefPtr<StyleSheet>* aSheet, SheetParsingMode aParsingMode,
Shm* aSharedMemory, Header* aHeader, UserAgentStyleSheetID aSheetID) {
auto i = size_t(aSheetID);
auto sheet = MakeRefPtr<StyleSheet>(
aParsingMode, CORS_NONE, mozilla::net::RP_Unset, dom::SRIMetadata());
nsCOMPtr<nsIURI> uri;
MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), aURL));
sheet->SetPrincipal(nsContentUtils::GetSystemPrincipal());
sheet->SetURIs(uri, uri, uri);
sheet->SetSharedContents(aSharedMemory, aHeader->mSheets[i]);
sheet->SetComplete();
URLExtraData::sShared[i] = sheet->URLData();
*aSheet = sheet.forget();
}
void nsLayoutStylesheetCache::InitSharedSheetsInParent() {
MOZ_ASSERT(XRE_IsParentProcess());
mSharedMemory = new Shm();
mSharedMemory->mShm.Create(kSharedMemorySize);
// We need to choose an address to map the shared memory in the parent process
// that we'll also be able to use in content processes. There's no way to
// pick an address that is guaranteed to be free in future content processes,
// so instead we pick an address that is some distance away from current heap
// allocations and hope that by the time the content process maps the shared
// memory, that address will be free.
//
// On 64 bit, we have a large amount of address space, so we pick an address
// half way through the next 8 GiB of free space, and this has a very good
// chance of succeeding. On 32 bit, address space is more constrained. We
// only have 3 GiB of space to work with, and we don't want to pick a location
// right in the middle, since that could cause future large allocations to
// fail. So we pick an address half way through the next 512 MiB of free
// space. Experimentally this seems to work 9 times out of 10; this is good
// enough, as it means only 1 in 10 content processes will have its own unique
// copies of the UA style sheets, and we're still getting a significant
// overall memory saving.
//
// In theory ASLR could reduce the likelihood of the mapping succeeding in
// content processes, due to our expectations of where the heap is being
// wrong, but in practice this isn't an issue.
#ifdef HAVE_64BIT_BUILD
constexpr size_t kOffset = 0x200000000ULL; // 8 GiB
#else
constexpr size_t kOffset = 0x20000000; // 512 MiB
#endif
void* address = nullptr;
if (void* p = base::SharedMemory::FindFreeAddressSpace(2 * kOffset)) {
address = reinterpret_cast<void*>(uintptr_t(p) + kOffset);
}
if (!mSharedMemory->mShm.Map(kSharedMemorySize, address)) {
// Failed to map at the address we computed for some reason. Fall back
// to just allocating at a location of the OS's choosing, and hope that
// it works in the content process.
mSharedMemory->mShm.Map(kSharedMemorySize);
}
Header* header = static_cast<Header*>(mSharedMemory->mShm.memory());
header->mMagic = Header::kMagic;
#ifdef DEBUG
for (auto ptr : header->mSheets) {
MOZ_RELEASE_ASSERT(!ptr, "expected shared memory to have been zeroed");
}
#endif
UniquePtr<RawServoSharedMemoryBuilder> builder(
Servo_SharedMemoryBuilder_Create(
header->mBuffer, kSharedMemorySize - offsetof(Header, mBuffer)));
// Copy each one into the shared memory, and record its pointer.
#define STYLE_SHEET(identifier_, url_, shared_) \
if (shared_) { \
StyleSheet* sheet = identifier_##Sheet(); \
size_t i = size_t(UserAgentStyleSheetID::identifier_); \
URLExtraData::sShared[i] = sheet->URLData(); \
header->mSheets[i] = sheet->ToShared(builder.get()); \
}
#include "mozilla/UserAgentStyleSheetList.h"
#undef STYLE_SHEET
// Record how must of the shared memory we have used, for memory reporting
// later. We round up to the nearest page since the free space at the end
// of the page isn't really usable for anything else.
//
// TODO(heycam): This won't be true on Windows unless we allow creating the
// shared memory with SEC_RESERVE so that the pages are reserved but not
// committed.
size_t pageSize = ipc::SharedMemory::SystemPageSize();
mUsedSharedMemory =
(Servo_SharedMemoryBuilder_GetLength(builder.get()) + pageSize - 1) &
~(pageSize - 1);
}
nsLayoutStylesheetCache::~nsLayoutStylesheetCache() {
@ -423,9 +570,32 @@ void nsLayoutStylesheetCache::BuildPreferenceSheet(
#undef NS_GET_R_G_B
}
/* static */ void nsLayoutStylesheetCache::SetSharedMemory(
const base::SharedMemoryHandle& aHandle, uintptr_t aAddress) {
MOZ_ASSERT(!XRE_IsParentProcess());
MOZ_ASSERT(!gStyleCache,
"Too late, nsLayoutStylesheetCache already created!");
MOZ_ASSERT(!sSharedMemory, "Shouldn't call this more than once");
RefPtr<Shm> shm = new Shm();
if (shm->mShm.SetHandle(aHandle, /* read_only */ true) &&
shm->mShm.Map(kSharedMemorySize, reinterpret_cast<void*>(aAddress))) {
sSharedMemory = shm.forget();
}
}
bool nsLayoutStylesheetCache::ShareToProcess(
base::ProcessId aProcessId, base::SharedMemoryHandle* aHandle) {
MOZ_ASSERT(XRE_IsParentProcess());
return mSharedMemory &&
mSharedMemory->mShm.ShareToProcess(aProcessId, aHandle);
}
mozilla::StaticRefPtr<nsLayoutStylesheetCache>
nsLayoutStylesheetCache::gStyleCache;
mozilla::StaticRefPtr<mozilla::css::Loader> nsLayoutStylesheetCache::gCSSLoader;
mozilla::StaticRefPtr<nsIURI> nsLayoutStylesheetCache::gUserContentSheetURL;
StaticRefPtr<nsLayoutStylesheetCacheShm> nsLayoutStylesheetCache::sSharedMemory;

Просмотреть файл

@ -9,6 +9,7 @@
#include "nsIMemoryReporter.h"
#include "nsIObserver.h"
#include "base/shared_memory.h"
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/PreferenceSheet.h"
@ -32,15 +33,28 @@ enum FailureAction { eCrash = 0, eLogToConsole };
} // namespace css
} // namespace mozilla
// Reference counted wrapper around a base::SharedMemory that will store the
// User Agent style sheets.
struct nsLayoutStylesheetCacheShm final {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsLayoutStylesheetCacheShm)
base::SharedMemory mShm;
private:
~nsLayoutStylesheetCacheShm() = default;
};
class nsLayoutStylesheetCache final : public nsIObserver,
public nsIMemoryReporter {
public:
using Shm = nsLayoutStylesheetCacheShm;
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIMEMORYREPORTER
static nsLayoutStylesheetCache* Singleton();
#define STYLE_SHEET(identifier_, url_, lazy_) \
#define STYLE_SHEET(identifier_, url_, shared_) \
mozilla::NotNull<mozilla::StyleSheet*> identifier_##Sheet();
#include "mozilla/UserAgentStyleSheetList.h"
#undef STYLE_SHEET
@ -58,11 +72,47 @@ class nsLayoutStylesheetCache final : public nsIObserver,
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
// Set the shared memory segment to load the shared UA sheets from.
// Called early on in a content process' life from
// ContentChild::InitSharedUASheets, before the nsLayoutStylesheetCache
// singleton has been created.
static void SetSharedMemory(const base::SharedMemoryHandle& aHandle,
uintptr_t aAddress);
// Obtain a shared memory handle for the shared UA sheets to pass into a
// content process. Called by ContentParent::InitInternal shortly after
// a content process has been created.
bool ShareToProcess(base::ProcessId aProcessId,
base::SharedMemoryHandle* aHandle);
// Returns the address of the shared memory segment that holds the shared UA
// sheets.
uintptr_t GetSharedMemoryAddress() {
return mSharedMemory ? uintptr_t(mSharedMemory->mShm.memory()) : 0;
}
// Size of the shared memory buffer we'll create to store the shared UA
// sheets. We choose a value that is big enough on both 64 bit and 32 bit.
//
// If this isn't big enough for the current contents of the shared UA
// sheets, we'll crash under InitSharedSheetsInParent.
static constexpr size_t kSharedMemorySize = 1024 * 400;
private:
// Shared memory header.
struct Header {
static constexpr uint32_t kMagic = 0x55415353;
uint32_t mMagic; // Must be set to kMagic.
const ServoCssRules* mSheets[size_t(mozilla::UserAgentStyleSheetID::Count)];
uint8_t mBuffer[1];
};
nsLayoutStylesheetCache();
~nsLayoutStylesheetCache();
void InitFromProfile();
void InitSharedSheetsInParent();
void InitSharedSheetsInChild(already_AddRefed<Shm> aSharedMemory);
void InitMemoryReporter();
void LoadSheetURL(const char* aURL, RefPtr<mozilla::StyleSheet>* aSheet,
mozilla::css::SheetParsingMode aParsingMode,
@ -73,6 +123,11 @@ class nsLayoutStylesheetCache final : public nsIObserver,
void LoadSheet(nsIURI* aURI, RefPtr<mozilla::StyleSheet>* aSheet,
mozilla::css::SheetParsingMode aParsingMode,
mozilla::css::FailureAction aFailureAction);
void LoadSheetFromSharedMemory(const char* aURL,
RefPtr<mozilla::StyleSheet>* aSheet,
mozilla::css::SheetParsingMode aParsingMode,
Shm* aSharedMemory, Header* aHeader,
mozilla::UserAgentStyleSheetID aSheetID);
void BuildPreferenceSheet(RefPtr<mozilla::StyleSheet>* aSheet,
const mozilla::PreferenceSheet::Prefs&);
@ -80,7 +135,7 @@ class nsLayoutStylesheetCache final : public nsIObserver,
static mozilla::StaticRefPtr<mozilla::css::Loader> gCSSLoader;
static mozilla::StaticRefPtr<nsIURI> gUserContentSheetURL;
#define STYLE_SHEET(identifier_, url_, lazy_) \
#define STYLE_SHEET(identifier_, url_, shared_) \
RefPtr<mozilla::StyleSheet> m##identifier_##Sheet;
#include "mozilla/UserAgentStyleSheetList.h"
#undef STYLE_SHEET
@ -89,6 +144,17 @@ class nsLayoutStylesheetCache final : public nsIObserver,
RefPtr<mozilla::StyleSheet> mContentPreferenceSheet;
RefPtr<mozilla::StyleSheet> mUserChromeSheet;
RefPtr<mozilla::StyleSheet> mUserContentSheet;
// Shared memory segment storing shared style sheets.
RefPtr<Shm> mSharedMemory;
// How much of the shared memory buffer we ended up using. Used for memory
// reporting.
size_t mUsedSharedMemory;
// The shared memory to use once the nsLayoutStylesheetCache instance is
// created.
static mozilla::StaticRefPtr<Shm> sSharedMemory;
};
#endif

Просмотреть файл

@ -1082,6 +1082,13 @@ VARCACHE_PREF(
RelaxedAtomicBool, false
)
// Are shared memory User Agent style sheets enabled?
VARCACHE_PREF(
"layout.css.shared-memory-ua-sheets.enabled",
layout_css_shared_memory_ua_sheets_enabled,
bool, false
)
//---------------------------------------------------------------------------
// JavaScript prefs
//---------------------------------------------------------------------------