mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 16:28:38 +09:00
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
This commit is contained in:
parent
e96122ede2
commit
03a4a17ccf
6 changed files with 80 additions and 54 deletions
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ PageIconProtocolHandler.prototype = {
|
|||
|
||||
try {
|
||||
channel.contentType = mime;
|
||||
channel.contentLength = len;
|
||||
// Pass the icon data to the output stream.
|
||||
let stream = Cc["@mozilla.org/binaryoutputstream;1"]
|
||||
.createInstance(Ci.nsIBinaryOutputStream);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue