зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
12c03087aa
Коммит
3357fd0d3a
|
@ -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
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
Загрузка…
Ссылка в новой задаче