Bug 1373579: Part 2 - Deserialize StructuredCloneBlob in segments rather than a single large allocation. r?billm
MozReview-Commit-ID: QZqPKSTheG
--- a/dom/base/StructuredCloneBlob.cpp
+++ b/dom/base/StructuredCloneBlob.cpp
@@ -128,19 +128,24 @@ StructuredCloneBlob::ReadStructuredClone
uint32_t blobCount;
if (!JS_ReadUint32Pair(aReader, &blobOffset, &blobCount)) {
return false;
}
if (blobCount) {
BlobImpls().AppendElements(&aHolder->BlobImpls()[blobOffset], blobCount);
}
- JSStructuredCloneData data(length, length, 4096);
- if (!JS_ReadBytes(aReader, data.Start(), length)) {
- return false;
+ JSStructuredCloneData data;
+ size_t size = 0;
+ while (length) {
+ char* buffer = data.AllocateBytes(length, &size);
+ if (!buffer || !JS_ReadBytes(aReader, buffer, size)) {
+ return false;
+ }
+ length -= size;
}
mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>(mStructuredCloneScope,
&StructuredCloneHolder::sCallbacks,
this);
mBuffer->adopt(Move(data), version, &StructuredCloneHolder::sCallbacks);
return true;
--- a/mfbt/BufferList.h
+++ b/mfbt/BufferList.h
@@ -258,16 +258,20 @@ class BufferList : private AllocPolicy
const char* Start() const { return mSegments[0].mData; }
IterImpl Iter() const { return IterImpl(*this); }
// Copies aSize bytes from aData into the BufferList. The storage for these
// bytes may be split across multiple buffers. Size() is increased by aSize.
inline bool WriteBytes(const char* aData, size_t aSize);
+ // Allocates a buffer of at most |aMaxBytes| bytes and, if successful, returns
+ // that buffer, and places its size in |aSize|.
+ inline char* AllocateBytes(size_t aMaxSize, size_t* aSize);
+
// Copies possibly non-contiguous byte range starting at aIter into
// aData. aIter is advanced by aSize bytes. Returns false if it runs out of
// data before aSize.
inline bool ReadBytes(IterImpl& aIter, char* aData, size_t aSize) const;
// Return a new BufferList that shares storage with this BufferList. The new
// BufferList is read-only. It allows iteration over aSize bytes starting at
// aIter. Borrow can fail, in which case *aSuccess will be false upon
@@ -308,17 +312,17 @@ private:
explicit BufferList(AllocPolicy aAP)
: AllocPolicy(aAP),
mOwning(false),
mSize(0),
mStandardCapacity(0)
{
}
- void* AllocateSegment(size_t aSize, size_t aCapacity)
+ char* AllocateSegment(size_t aSize, size_t aCapacity)
{
MOZ_RELEASE_ASSERT(mOwning);
MOZ_ASSERT(aSize <= aCapacity);
char* data = this->template pod_malloc<char>(aCapacity);
if (!data) {
return nullptr;
}
@@ -339,44 +343,58 @@ private:
template<typename AllocPolicy>
bool
BufferList<AllocPolicy>::WriteBytes(const char* aData, size_t aSize)
{
MOZ_RELEASE_ASSERT(mOwning);
MOZ_RELEASE_ASSERT(mStandardCapacity);
size_t copied = 0;
- size_t remaining = aSize;
+ size_t toCopy = 0;
+ while (copied < aSize) {
+ char* data = AllocateBytes(aSize - copied, &toCopy);
+ if (!data) {
+ return false;
+ }
+ memcpy(data, aData + copied, toCopy);
+ copied += toCopy;
+ }
+
+ return true;
+}
+
+template<typename AllocPolicy>
+char*
+BufferList<AllocPolicy>::AllocateBytes(size_t aMaxSize, size_t* aSize)
+{
+ MOZ_RELEASE_ASSERT(mOwning);
+ MOZ_RELEASE_ASSERT(mStandardCapacity);
if (!mSegments.empty()) {
Segment& lastSegment = mSegments.back();
- size_t toCopy = std::min(aSize, lastSegment.mCapacity - lastSegment.mSize);
- memcpy(lastSegment.mData + lastSegment.mSize, aData, toCopy);
- lastSegment.mSize += toCopy;
- mSize += toCopy;
+ size_t capacity = lastSegment.mCapacity - lastSegment.mSize;
+ if (capacity) {
+ size_t size = std::min(aMaxSize, capacity);
+ char* data = lastSegment.mData + lastSegment.mSize;
- copied += toCopy;
- remaining -= toCopy;
+ lastSegment.mSize += size;
+ mSize += size;
+
+ *aSize = size;
+ return data;
+ }
}
- while (remaining) {
- size_t toCopy = std::min(remaining, mStandardCapacity);
-
- void* data = AllocateSegment(toCopy, mStandardCapacity);
- if (!data) {
- return false;
- }
- memcpy(data, aData + copied, toCopy);
-
- copied += toCopy;
- remaining -= toCopy;
+ size_t size = std::min(aMaxSize, mStandardCapacity);
+ char* data = AllocateSegment(size, mStandardCapacity);
+ if (data) {
+ *aSize = size;
}
-
- return true;
+ return data;
}
template<typename AllocPolicy>
bool
BufferList<AllocPolicy>::ReadBytes(IterImpl& aIter, char* aData, size_t aSize) const
{
size_t copied = 0;
size_t remaining = aSize;