diff options
author | Martok <martok@martoks-place.de> | 2023-01-03 22:55:13 +0100 |
---|---|---|
committer | Martok <martok@martoks-place.de> | 2023-01-04 00:49:05 +0100 |
commit | 919a966dc2177a7abbe7792dda00d9e033209996 (patch) | |
tree | 521106f4a0eb65fa0f637180fa2eb0687e7e7e11 /image | |
parent | b618b3fb767e61f73732a0385f733357571314b0 (diff) | |
download | uxp-919a966dc2177a7abbe7792dda00d9e033209996.tar.gz |
Issue #2073 - m-c 1383404: make SourceBuffer::Compact more efficient (squashed)
The first part also means that Compact no longer needs the SurfaceCache lock (used to be via CreateChunk->CanHold),
which avoids potential deadlocks during shutdown that m-c 523950 would otherwise cause
Diffstat (limited to 'image')
-rw-r--r-- | image/ImageFactory.cpp | 47 | ||||
-rw-r--r-- | image/ImageFactory.h | 3 | ||||
-rw-r--r-- | image/SourceBuffer.cpp | 31 | ||||
-rw-r--r-- | image/SourceBuffer.h | 33 | ||||
-rw-r--r-- | image/imgTools.cpp | 19 |
5 files changed, 79 insertions, 54 deletions
diff --git a/image/ImageFactory.cpp b/image/ImageFactory.cpp index 428be1424e..343f7b582b 100644 --- a/image/ImageFactory.cpp +++ b/image/ImageFactory.cpp @@ -111,8 +111,32 @@ BadImage(const char* aMessage, RefPtr<T>& aImage) return aImage.forget(); } +static void +SetSourceSizeHint(RasterImage* aImage, uint32_t aSize) +{ + // Pass anything usable on so that the RasterImage can preallocate + // its source buffer. + if (aSize == 0) { + return; + } + + // Bound by something reasonable + uint32_t sizeHint = std::min<uint32_t>(aSize, 20000000); + nsresult rv = aImage->SetSourceSizeHint(sizeHint); + if (NS_FAILED(rv)) { + // Flush memory, try to get some back, and try again. + rv = nsMemory::HeapMinimize(true); + nsresult rv2 = aImage->SetSourceSizeHint(sizeHint); + // If we've still failed at this point, things are going downhill. + if (NS_FAILED(rv) || NS_FAILED(rv2)) { + NS_WARNING("About to hit OOM in imagelib!"); + } + } +} + /* static */ already_AddRefed<Image> -ImageFactory::CreateAnonymousImage(const nsCString& aMimeType) +ImageFactory::CreateAnonymousImage(const nsCString& aMimeType, + uint32_t aSizeHint /* = 0 */) { nsresult rv; @@ -127,6 +151,7 @@ ImageFactory::CreateAnonymousImage(const nsCString& aMimeType) return BadImage("RasterImage::Init failed", newImage); } + SetSourceSizeHint(newImage, aSizeHint); return newImage.forget(); } @@ -231,25 +256,7 @@ ImageFactory::CreateRasterImage(nsIRequest* aRequest, newImage->SetInnerWindowID(aInnerWindowId); - uint32_t len = GetContentSize(aRequest); - - // Pass anything usable on so that the RasterImage can preallocate - // its source buffer. - if (len > 0) { - // Bound by something reasonable - uint32_t sizeHint = std::min<uint32_t>(len, 20000000); - rv = newImage->SetSourceSizeHint(sizeHint); - if (NS_FAILED(rv)) { - // Flush memory, try to get some back, and try again. - rv = nsMemory::HeapMinimize(true); - nsresult rv2 = newImage->SetSourceSizeHint(sizeHint); - // If we've still failed at this point, things are going downhill. - if (NS_FAILED(rv) || NS_FAILED(rv2)) { - NS_WARNING("About to hit OOM in imagelib!"); - } - } - } - + SetSourceSizeHint(newImage, GetContentSize(aRequest)); return newImage.forget(); } diff --git a/image/ImageFactory.h b/image/ImageFactory.h index 6c2e0f5045..fdd6460ec1 100644 --- a/image/ImageFactory.h +++ b/image/ImageFactory.h @@ -51,9 +51,10 @@ public: * the usual image loading mechanism. * * @param aMimeType The mimetype of the image. + * @param aSizeHint The length of the source data for the image. */ static already_AddRefed<Image> - CreateAnonymousImage(const nsCString& aMimeType); + CreateAnonymousImage(const nsCString& aMimeType, uint32_t aSizeHint = 0); /** * Creates a new multipart/x-mixed-replace image wrapper, and initializes it diff --git a/image/SourceBuffer.cpp b/image/SourceBuffer.cpp index de066e29fc..5961cc66ff 100644 --- a/image/SourceBuffer.cpp +++ b/image/SourceBuffer.cpp @@ -204,30 +204,27 @@ SourceBuffer::Compact() return NS_OK; } - Maybe<Chunk> newChunk = CreateChunk(length, /* aRoundUp = */ false); - if (MOZ_UNLIKELY(!newChunk || newChunk->AllocationFailed())) { - NS_WARNING("Failed to allocate chunk for SourceBuffer compacting - OOM?"); + Chunk& mergeChunk = mChunks[0]; + if (MOZ_UNLIKELY(!mergeChunk.SetCapacity(length))) { + NS_WARNING("Failed to reallocate chunk for SourceBuffer compacting - OOM?"); return NS_OK; } - // Copy our old chunks into the new chunk. - for (uint32_t i = 0 ; i < mChunks.Length() ; ++i) { - size_t offset = newChunk->Length(); - MOZ_ASSERT(offset < newChunk->Capacity()); - MOZ_ASSERT(offset + mChunks[i].Length() <= newChunk->Capacity()); + // Copy our old chunks into the newly reallocated first chunk. + for (uint32_t i = 1 ; i < mChunks.Length() ; ++i) { + size_t offset = mergeChunk.Length(); + MOZ_ASSERT(offset < mergeChunk.Capacity()); + MOZ_ASSERT(offset + mChunks[i].Length() <= mergeChunk.Capacity()); - memcpy(newChunk->Data() + offset, mChunks[i].Data(), mChunks[i].Length()); - newChunk->AddLength(mChunks[i].Length()); + memcpy(mergeChunk.Data() + offset, mChunks[i].Data(), mChunks[i].Length()); + mergeChunk.AddLength(mChunks[i].Length()); } - MOZ_ASSERT(newChunk->Length() == newChunk->Capacity(), + MOZ_ASSERT(mergeChunk.Length() == mergeChunk.Capacity(), "Compacted chunk has slack space"); - // Replace the old chunks with the new, compact chunk. - mChunks.Clear(); - if (MOZ_UNLIKELY(NS_FAILED(AppendChunk(Move(newChunk))))) { - return HandleError(NS_ERROR_OUT_OF_MEMORY); - } + // Remove the redundant chunks. + mChunks.RemoveElementsAt(1, mChunks.Length() - 1); mChunks.Compact(); return NS_OK; @@ -317,7 +314,7 @@ SourceBuffer::ExpectLength(size_t aExpectedLength) return NS_OK; } - if (MOZ_UNLIKELY(NS_FAILED(AppendChunk(CreateChunk(aExpectedLength))))) { + if (MOZ_UNLIKELY(NS_FAILED(AppendChunk(CreateChunk(aExpectedLength, /* aRoundUp */ false))))) { return HandleError(NS_ERROR_OUT_OF_MEMORY); } diff --git a/image/SourceBuffer.h b/image/SourceBuffer.h index e5aff1dcdd..6e3ef7a538 100644 --- a/image/SourceBuffer.h +++ b/image/SourceBuffer.h @@ -358,7 +358,7 @@ private: // Chunk type and chunk-related methods. ////////////////////////////////////////////////////////////////////////////// - class Chunk + class Chunk final { public: explicit Chunk(size_t aCapacity) @@ -366,13 +366,18 @@ private: , mLength(0) { MOZ_ASSERT(aCapacity > 0, "Creating zero-capacity chunk"); - mData.reset(new (fallible) char[mCapacity]); + mData = static_cast<char*>(malloc(mCapacity)); + } + + ~Chunk() + { + free(mData); } Chunk(Chunk&& aOther) : mCapacity(aOther.mCapacity) , mLength(aOther.mLength) - , mData(Move(aOther.mData)) + , mData(aOther.mData) { aOther.mCapacity = aOther.mLength = 0; aOther.mData = nullptr; @@ -380,9 +385,10 @@ private: Chunk& operator=(Chunk&& aOther) { + free(mData); mCapacity = aOther.mCapacity; mLength = aOther.mLength; - mData = Move(aOther.mData); + mData = aOther.mData; aOther.mCapacity = aOther.mLength = 0; aOther.mData = nullptr; return *this; @@ -395,7 +401,7 @@ private: char* Data() const { MOZ_ASSERT(mData, "Allocation failed but nobody checked for it"); - return mData.get(); + return mData; } void AddLength(size_t aAdditionalLength) @@ -404,13 +410,26 @@ private: mLength += aAdditionalLength; } + bool SetCapacity(size_t aCapacity) + { + MOZ_ASSERT(mData, "Allocation failed but nobody checked for it"); + char* data = static_cast<char*>(realloc(mData, aCapacity)); + if (!data) { + return false; + } + + mData = data; + mCapacity = aCapacity; + return true; + } + private: Chunk(const Chunk&) = delete; Chunk& operator=(const Chunk&) = delete; size_t mCapacity; size_t mLength; - UniquePtr<char[]> mData; + char* mData; }; nsresult AppendChunk(Maybe<Chunk>&& aChunk); @@ -454,7 +473,7 @@ private: mutable Mutex mMutex; /// The data in this SourceBuffer, stored as a series of Chunks. - FallibleTArray<Chunk> mChunks; + AutoTArray<Chunk, 1> mChunks; /// Consumers which are waiting to be notified when new data is available. nsTArray<RefPtr<IResumable>> mWaitingConsumers; diff --git a/image/imgTools.cpp b/image/imgTools.cpp index 29905c1ab3..3ac31102e5 100644 --- a/image/imgTools.cpp +++ b/image/imgTools.cpp @@ -67,15 +67,6 @@ imgTools::DecodeImage(nsIInputStream* aInStr, NS_ENSURE_ARG_POINTER(aInStr); - // Create a new image container to hold the decoded data. - nsAutoCString mimeType(aMimeType); - RefPtr<image::Image> image = ImageFactory::CreateAnonymousImage(mimeType); - RefPtr<ProgressTracker> tracker = image->GetProgressTracker(); - - if (image->HasError()) { - return NS_ERROR_FAILURE; - } - // Prepare the input stream. nsCOMPtr<nsIInputStream> inStream = aInStr; if (!NS_InputStreamIsBuffered(aInStr)) { @@ -92,6 +83,16 @@ imgTools::DecodeImage(nsIInputStream* aInStr, NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(length <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG); + // Create a new image container to hold the decoded data. + nsAutoCString mimeType(aMimeType); + RefPtr<image::Image> image = + ImageFactory::CreateAnonymousImage(mimeType, uint32_t(length)); + RefPtr<ProgressTracker> tracker = image->GetProgressTracker(); + + if (image->HasError()) { + return NS_ERROR_FAILURE; + } + // Send the source data to the Image. rv = image->OnImageDataAvailable(nullptr, nullptr, inStream, 0, uint32_t(length)); |