Bug 1463587: Part 4 - Add blob support to SharedMap. r=erahm,baku

I was hoping to avoid supporting blobs here, but some parts of the
WebExtensions framework rely on being able to store Blobs in
initialProcessData, and can't be migrated without adding blob support.

This patch adds an ordered array of BlobImpls for all extant keys, clones them
to all child processes when updating the serialized maps, and initializes
StructuredCloneData instances with indexes into the combined array.

MozReview-Commit-ID: IdSv5FHbPbE

--HG--
extra : rebase_source : 3020af12859ce3470bd31e9c3b7f5c919e1b9665
This commit is contained in:
Kris Maglione 2018-06-27 16:35:53 -07:00
parent 47c200749a
commit 345b497bc6
5 changed files with 76 additions and 9 deletions

View File

@ -2573,10 +2573,18 @@ ContentChild::RecvRegisterStringBundles(nsTArray<mozilla::dom::StringBundleDescr
mozilla::ipc::IPCResult
ContentChild::RecvUpdateSharedData(const FileDescriptor& aMapFile,
const uint32_t& aMapSize,
nsTArray<IPCBlob>&& aBlobs,
nsTArray<nsCString>&& aChangedKeys)
{
if (mSharedData) {
mSharedData->Update(aMapFile, aMapSize, std::move(aChangedKeys));
nsTArray<RefPtr<BlobImpl>> blobImpls(aBlobs.Length());
for (auto& ipcBlob : aBlobs) {
blobImpls.AppendElement(IPCBlobUtils::Deserialize(ipcBlob));
}
mSharedData->Update(aMapFile, aMapSize,
std::move(blobImpls),
std::move(aChangedKeys));
}
return IPC_OK();

View File

@ -406,6 +406,7 @@ public:
mozilla::ipc::IPCResult RecvUpdateSharedData(const FileDescriptor& aMapFile,
const uint32_t& aMapSize,
nsTArray<IPCBlob>&& aBlobs,
nsTArray<nsCString>&& aChangedKeys) override;
virtual mozilla::ipc::IPCResult RecvGeolocationUpdate(nsIDOMGeoPosition* aPosition) override;

View File

@ -467,6 +467,7 @@ child:
async RegisterStringBundles(StringBundleDescriptor[] stringBundles);
async UpdateSharedData(FileDescriptor mapFile, uint32_t aSize,
IPCBlob[] blobs,
nsCString[] changedKeys);
// nsIPermissionManager messages

View File

@ -11,6 +11,7 @@
#include "ScriptPreloader-inl.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/IPCBlobUtils.h"
#include "mozilla/dom/ProcessGlobal.h"
#include "mozilla/dom/ScriptSettings.h"
@ -97,8 +98,11 @@ SharedMap::Entry::Read(JSContext* aCx,
StructuredCloneData holder;
if (!holder.CopyExternalData(Data(), Size())) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
if (mBlobCount) {
holder.BlobImpls().AppendElements(Blobs());
}
holder.Read(aCx, aRetVal, aRv);
}
@ -113,6 +117,7 @@ SharedMap::CloneMapFile()
void
SharedMap::Update(const FileDescriptor& aMapFile, size_t aMapSize,
nsTArray<RefPtr<BlobImpl>>&& aBlobs,
nsTArray<nsCString>&& aChangedKeys)
{
MOZ_DIAGNOSTIC_ASSERT(!mWritable);
@ -127,6 +132,8 @@ SharedMap::Update(const FileDescriptor& aMapFile, size_t aMapSize,
mEntries.Clear();
mEntryArray.reset();
mBlobImpls = std::move(aBlobs);
AutoEntryScript aes(GetParentObject(), "SharedMap change event");
JSContext* cx = aes.cx();
@ -198,10 +205,11 @@ SharedMap::Entry::TakeData(StructuredCloneData&& aHolder)
mData = AsVariant(std::move(aHolder));
mSize = Holder().Data().Size();
mBlobCount = Holder().BlobImpls().Length();
}
void
SharedMap::Entry::ExtractData(char* aDestPtr, uint32_t aNewOffset)
SharedMap::Entry::ExtractData(char* aDestPtr, uint32_t aNewOffset, uint16_t aNewBlobOffset)
{
if (mData.is<StructuredCloneData>()) {
char* ptr = aDestPtr;
@ -216,6 +224,7 @@ SharedMap::Entry::ExtractData(char* aDestPtr, uint32_t aNewOffset)
}
mData = AsVariant(aNewOffset);
mBlobOffset = aNewBlobOffset;
}
Result<Ok, nsresult>
@ -320,9 +329,11 @@ WritableSharedMap::Serialize()
size_t dataSize = 0;
size_t headerSize = sizeof(count);
size_t blobCount = 0;
for (auto& entry : IterHash(mEntries)) {
headerSize += entry->HeaderSize();
blobCount += entry->BlobCount();
dataSize += entry->Size();
AlignTo(&dataSize, kStructuredCloneAlign);
@ -339,18 +350,30 @@ WritableSharedMap::Serialize()
auto ptr = mem.Get<char>();
// We need to build the new array of blobs before we overwrite the existing
// one, since previously-serialized entries will store their blob references
// as indexes into our blobs array.
nsTArray<RefPtr<BlobImpl>> blobImpls(blobCount);
for (auto& entry : IterHash(mEntries)) {
AlignTo(&offset, kStructuredCloneAlign);
entry->ExtractData(&ptr[offset], offset);
entry->ExtractData(&ptr[offset], offset, blobImpls.Length());
entry->Code(header);
offset += entry->Size();
if (entry->BlobCount()) {
mBlobImpls.AppendElements(entry->Blobs());
}
}
mBlobImpls = std::move(blobImpls);
// FIXME: We should create a separate OutputBuffer class which can encode to
// a static memory region rather than dynamically allocating and then
// copying.
MOZ_ASSERT(header.cursor() == headerSize);
memcpy(ptr.get(), header.Get(), header.cursor());
// We've already updated offsets at this point. We need this to succeed.
@ -374,12 +397,24 @@ WritableSharedMap::BroadcastChanges()
nsTArray<ContentParent*> parents;
ContentParent::GetAll(parents);
for (auto& parent : parents) {
nsTArray<IPCBlob> blobs(mBlobImpls.Length());
for (auto& blobImpl : mBlobImpls) {
nsresult rv = IPCBlobUtils::Serialize(blobImpl, parent,
*blobs.AppendElement());
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
}
Unused << parent->SendUpdateSharedData(CloneMapFile(), mMap.size(),
mChangedKeys);
blobs, mChangedKeys);
}
if (mReadOnly) {
nsTArray<RefPtr<BlobImpl>> blobImpls(mBlobImpls);
mReadOnly->Update(CloneMapFile(), mMap.size(),
std::move(blobImpls),
std::move(mChangedKeys));
}
@ -407,8 +442,7 @@ WritableSharedMap::Set(JSContext* aCx,
return;
}
if (!holder.BlobImpls().IsEmpty() ||
!holder.InputStreams().IsEmpty()) {
if (!holder.InputStreams().IsEmpty()) {
aRv.Throw(NS_ERROR_INVALID_ARG);
return;
}

View File

@ -122,6 +122,7 @@ public:
* changed (UTF-8-encoded) keys.
*/
void Update(const FileDescriptor& aMapFile, size_t aMapSize,
nsTArray<RefPtr<BlobImpl>>&& aBlobs,
nsTArray<nsCString>&& aChangedKeys);
@ -156,6 +157,8 @@ protected:
buffer.codeString(mName);
buffer.codeUint32(DataOffset());
buffer.codeUint32(mSize);
buffer.codeUint16(mBlobOffset);
buffer.codeUint16(mBlobCount);
MOZ_ASSERT(buffer.cursor() == startOffset + HeaderSize());
}
@ -168,7 +171,9 @@ protected:
{
return (sizeof(uint16_t) + mName.Length() +
sizeof(DataOffset()) +
sizeof(mSize));
sizeof(mSize) +
sizeof(mBlobOffset) +
sizeof(mBlobCount));
}
/**
@ -193,7 +198,7 @@ protected:
* snapshot, and must not be accessed again until the SharedMap mMap has been
* updated to point to it.
*/
void ExtractData(char* aDestPtr, uint32_t aNewOffset);
void ExtractData(char* aDestPtr, uint32_t aNewOffset, uint16_t aNewBlobOffset);
// Returns the UTF-8-encoded name of the entry, which is used as its key in
// the map.
@ -228,6 +233,19 @@ protected:
return mData.as<uint32_t>();
}
public:
uint16_t BlobOffset() const { return mBlobOffset; }
uint16_t BlobCount() const { return mBlobCount; }
Span<const RefPtr<BlobImpl>> Blobs()
{
if (mData.is<StructuredCloneData>()) {
return mData.as<StructuredCloneData>().BlobImpls();
}
return {&mMap.mBlobImpls[mBlobOffset], BlobCount()};
}
private:
// Returns the temporary StructuredCloneData object containing the entry's
// value. This is *only* value when mData contains a StructuredCloneDAta
// object.
@ -258,10 +276,15 @@ protected:
// The size, in bytes, of the entry's structured clone data.
uint32_t mSize = 0;
uint16_t mBlobOffset = 0;
uint16_t mBlobCount = 0;
};
const nsTArray<Entry*>& EntryArray() const;
nsTArray<RefPtr<BlobImpl>> mBlobImpls;
// Rebuilds the entry hashtable mEntries from the values serialized in the
// current snapshot, if necessary. The hashtable is rebuilt lazily after
// construction and after every Update() call, so this function must be called