Bug 1470365: Part 3 - Use shared memory for StringBundles loaded in the content process. r=erahm,smaug

MozReview-Commit-ID: LunnQyndnBf

--HG--
extra : rebase_source : f67e08fc83e8c2e280d886b2d69150c09fb48200
extra : absorb_source : 3b9b226aaca168e3b6537f3031ff22275bd27133
This commit is contained in:
Kris Maglione 2018-06-29 22:53:12 -07:00
parent d89b3482b9
commit e6da28f1ce
9 changed files with 143 additions and 8 deletions

View File

@ -3962,6 +3962,18 @@ nsContentUtils::EnsureStringBundle(PropertiesFile aFile)
void
nsContentUtils::AsyncPrecreateStringBundles()
{
// We only ever want to pre-create bundles in the parent process.
//
// All nsContentUtils bundles are shared between the parent and child
// precesses, and the shared memory regions that back them *must* be created
// in the parent, and then sent to all children.
//
// If we attempt to create a bundle in the child before its memory region is
// available, we need to create a temporary non-shared bundle, and later
// replace that with the shared memory copy. So attempting to pre-load in the
// child is wasteful and unnecessary.
MOZ_ASSERT(XRE_IsParentProcess());
for (uint32_t bundleIndex = 0; bundleIndex < PropertiesFile_COUNT; ++bundleIndex) {
nsresult rv = NS_IdleDispatchToCurrentThread(
NS_NewRunnableFunction("AsyncPrecreateStringBundles",

View File

@ -85,6 +85,7 @@
#include "GMPServiceChild.h"
#include "NullPrincipal.h"
#include "nsISimpleEnumerator.h"
#include "nsIStringBundle.h"
#include "nsIWorkerDebuggerManager.h"
#if !defined(XP_WIN)
@ -2262,11 +2263,6 @@ ContentChild::RecvRegisterChrome(InfallibleTArray<ChromePackage>&& packages,
static_cast<nsChromeRegistryContent*>(registrySvc.get());
chromeRegistry->RegisterRemoteChrome(packages, resources, overrides,
locale, reset);
static bool preloadDone = false;
if (!preloadDone) {
preloadDone = true;
nsContentUtils::AsyncPrecreateStringBundles();
}
return IPC_OK();
}
@ -2536,6 +2532,20 @@ ContentChild::RecvAsyncMessage(const nsString& aMsg,
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvRegisterStringBundles(nsTArray<mozilla::dom::StringBundleDescriptor>&& aDescriptors)
{
nsCOMPtr<nsIStringBundleService> stringBundleService =
services::GetStringBundleService();
for (auto& descriptor : aDescriptors) {
stringBundleService->RegisterContentBundle(descriptor.bundleURL(), descriptor.mapFile(),
descriptor.mapSize());
}
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvGeolocationUpdate(nsIDOMGeoPosition* aPosition)
{

View File

@ -394,6 +394,8 @@ public:
const IPC::Principal& aPrincipal,
const ClonedMessageData& aData) override;
mozilla::ipc::IPCResult RecvRegisterStringBundles(nsTArray<StringBundleDescriptor>&& stringBundles) override;
virtual mozilla::ipc::IPCResult RecvGeolocationUpdate(nsIDOMGeoPosition* aPosition) override;
virtual mozilla::ipc::IPCResult RecvGeolocationError(const uint16_t& errorCode) override;

View File

@ -146,6 +146,7 @@
#include "nsISiteSecurityService.h"
#include "nsISound.h"
#include "nsISpellChecker.h"
#include "nsIStringBundle.h"
#include "nsISupportsPrimitives.h"
#include "nsITimer.h"
#include "nsIURIFixup.h"
@ -1277,6 +1278,17 @@ ContentParent::GetAllEvenIfDead(nsTArray<ContentParent*>& aArray)
}
}
void
ContentParent::BroadcastStringBundle(const StringBundleDescriptor& aBundle)
{
AutoTArray<StringBundleDescriptor, 1> array;
array.AppendElement(aBundle);
for (auto* cp : AllProcesses(eLive)) {
Unused << cp->SendRegisterStringBundles(array);
}
}
const nsAString&
ContentParent::GetRemoteType() const
{
@ -2317,6 +2329,10 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority)
static_cast<nsChromeRegistryChrome*>(registrySvc.get());
chromeRegistry->SendRegisteredChrome(this);
nsCOMPtr<nsIStringBundleService> stringBundleService =
services::GetStringBundleService();
stringBundleService->SendContentBundles(this);
if (gAppData) {
nsCString version(gAppData->version);
nsCString buildID(gAppData->buildID);

View File

@ -204,6 +204,8 @@ public:
static void GetAllEvenIfDead(nsTArray<ContentParent*>& aArray);
static void BroadcastStringBundle(const StringBundleDescriptor&);
const nsAString& GetRemoteType() const;
virtual void DoGetRemoteType(nsAString& aRemoteType, ErrorResult& aError) const override

View File

@ -289,6 +289,13 @@ struct XPCOMInitData
DynamicScalarDefinition[] dynamicScalarDefs;
};
struct StringBundleDescriptor
{
nsCString bundleURL;
FileDescriptor mapFile;
uint32_t mapSize;
};
/**
* The PContent protocol is a top-level protocol between the UI process
* and a content process. There is exactly one PContentParent/PContentChild pair
@ -457,6 +464,8 @@ child:
async ClearSiteDataReloadNeeded(nsString origin);
async RegisterStringBundles(StringBundleDescriptor[] stringBundles);
// nsIPermissionManager messages
async AddPermission(Permission permission);

View File

@ -9,6 +9,15 @@
%{C++
#include "mozilla/MemoryReporting.h"
namespace mozilla {
namespace dom {
class ContentParent;
}
namespace ipc {
class FileDescriptor;
}
}
// Define Contractid and CID
// {D85A17C1-AA7C-11d2-9B8C-00805F8A16D9}
#define NS_STRINGBUNDLESERVICE_CID \
@ -99,5 +108,11 @@ interface nsIStringBundleService : nsISupports
%{C++
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
virtual void SendContentBundles(mozilla::dom::ContentParent* aContentParent) const = 0;
virtual void RegisterContentBundle(const nsCString& aBundleURL,
const mozilla::ipc::FileDescriptor& aMapFile,
size_t aMapSize) = 0;
%}
};

View File

@ -32,6 +32,7 @@
#include "mozilla/ResultExtensions.h"
#include "mozilla/URLPreloader.h"
#include "mozilla/ResultExtensions.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ipc/SharedStringMap.h"
// for async loading
@ -42,6 +43,8 @@
using namespace mozilla;
using mozilla::dom::ContentParent;
using mozilla::dom::StringBundleDescriptor;
using mozilla::dom::ipc::SharedStringMap;
using mozilla::dom::ipc::SharedStringMapBuilder;
using mozilla::ipc::FileDescriptor;
@ -223,6 +226,17 @@ public:
bool Initialized() const { return mStringMap || mMapFile.isSome(); }
StringBundleDescriptor GetDescriptor() const
{
MOZ_ASSERT(Initialized());
StringBundleDescriptor descriptor;
descriptor.bundleURL() = BundleURL();
descriptor.mapFile() = CloneFileDescriptor();
descriptor.mapSize() = MapSize();
return descriptor;
}
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
static SharedStringBundle* Cast(nsIStringBundle* aStringBundle)
@ -462,6 +476,9 @@ SharedStringBundle::LoadProperties()
}
mStringMap = new SharedStringMap(std::move(builder));
ContentParent::BroadcastStringBundle(GetDescriptor());
return NS_OK;
}
@ -998,6 +1015,52 @@ nsStringBundleService::FlushBundles()
return NS_OK;
}
void
nsStringBundleService::SendContentBundles(ContentParent* aContentParent) const
{
nsTArray<StringBundleDescriptor> bundles;
for (auto* entry : mSharedBundles) {
auto bundle = SharedStringBundle::Cast(entry->mBundle);
if (bundle->Initialized()) {
bundles.AppendElement(bundle->GetDescriptor());
}
}
Unused << aContentParent->SendRegisterStringBundles(std::move(bundles));
}
void
nsStringBundleService::RegisterContentBundle(const nsCString& aBundleURL,
const FileDescriptor& aMapFile,
size_t aMapSize)
{
RefPtr<StringBundleProxy> proxy;
bundleCacheEntry_t* cacheEntry = mBundleMap.Get(aBundleURL);
if (cacheEntry) {
if (RefPtr<SharedStringBundle> shared = do_QueryObject(cacheEntry->mBundle)) {
return;
}
proxy = do_QueryObject(cacheEntry->mBundle);
MOZ_ASSERT(proxy);
cacheEntry->remove();
delete cacheEntry;
}
auto bundle = MakeRefPtr<SharedStringBundle>(aBundleURL.get(), mOverrideStrings);
bundle->SetMapFile(aMapFile, aMapSize);
if (proxy) {
proxy->Retarget(bundle);
}
cacheEntry = insertIntoCache(bundle.forget(), aBundleURL);
mSharedBundles.insertBack(cacheEntry);
}
void
nsStringBundleService::getStringBundle(const char *aURLSpec,
nsIStringBundle **aResult)
@ -1063,7 +1126,7 @@ nsStringBundleService::getStringBundle(const char *aURLSpec,
bundleCacheEntry_t *
nsStringBundleService::insertIntoCache(already_AddRefed<nsIStringBundle> aBundle,
const nsCString &aHashKey)
const nsACString& aHashKey)
{
bundleCacheEntry_t *cacheEntry;

View File

@ -51,6 +51,12 @@ public:
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
void SendContentBundles(mozilla::dom::ContentParent* aContentParent) const override;
void RegisterContentBundle(const nsCString& aBundleURL,
const mozilla::ipc::FileDescriptor& aMapFile,
size_t aMapSize) override;
private:
virtual ~nsStringBundleService();
@ -61,8 +67,8 @@ private:
void flushBundleCache();
bundleCacheEntry_t *insertIntoCache(already_AddRefed<nsIStringBundle> aBundle,
const nsCString &aHashKey);
bundleCacheEntry_t* insertIntoCache(already_AddRefed<nsIStringBundle> aBundle,
const nsACString &aHashKey);
nsDataHashtable<nsCStringHashKey, bundleCacheEntry_t*> mBundleMap;
mozilla::LinkedList<bundleCacheEntry_t> mBundleCache;