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 : 90eeb7fad21eac93582ef9244180998d22267373
extra : source : cebf1f055d1dfb505e96cebf7e4284b35a419dd6
This commit is contained in:
Kris Maglione 2018-06-27 16:35:53 -07:00
Родитель 8316d5a0c0
Коммит 1aa45ee72a
5 изменённых файлов: 77 добавлений и 10 удалений

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

@ -2568,10 +2568,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();

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

@ -404,6 +404,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;

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

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

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

@ -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;
@ -210,12 +218,13 @@ SharedMap::Entry::ExtractData(char* aDestPtr, uint32_t aNewOffset)
ptr += aSize;
return true;
});
MOZ_ASSERT(ptr - aDestPtr == mSize);
MOZ_ASSERT(uint32_t(ptr - aDestPtr) == mSize);
} else {
memcpy(aDestPtr, Data(), mSize);
}
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;
}

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

@ -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