Bug 1059797 - Really share the same zlib inflate buffers for SeekableZStream chunks. r=nfroyd

This commit is contained in:
Mike Hommey 2015-02-10 16:04:37 +09:00
parent a81fc4b8c8
commit 693a41b39b
3 changed files with 58 additions and 25 deletions

View file

@ -72,7 +72,7 @@ SeekableZStream::DecompressChunk(void *where, size_t chunk, size_t length)
DEBUG_LOG("DecompressChunk #%" PRIdSize " @%p (%" PRIdSize "/% " PRIdSize ")", DEBUG_LOG("DecompressChunk #%" PRIdSize " @%p (%" PRIdSize "/% " PRIdSize ")",
chunk, where, length, chunkLen); chunk, where, length, chunkLen);
zxx_stream zStream; zxx_stream zStream(&allocator);
zStream.avail_in = (isLastChunk ? totalSize : uint32_t(offsetTable[chunk + 1])) zStream.avail_in = (isLastChunk ? totalSize : uint32_t(offsetTable[chunk + 1]))
- uint32_t(offsetTable[chunk]); - uint32_t(offsetTable[chunk]);
zStream.next_in = const_cast<Bytef *>(buffer + uint32_t(offsetTable[chunk])); zStream.next_in = const_cast<Bytef *>(buffer + uint32_t(offsetTable[chunk]));

View file

@ -139,6 +139,9 @@ private:
/* Deflate dictionary */ /* Deflate dictionary */
Array<unsigned char> dictionary; Array<unsigned char> dictionary;
/* Special allocator for inflate to use the same buffers for every chunk */
zxx_stream::StaticAllocator allocator;
}; };
inline void inline void

View file

@ -12,7 +12,6 @@
#include "Utils.h" #include "Utils.h"
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
/** /**
* Helper class wrapping z_stream to avoid malloc() calls during * Helper class wrapping z_stream to avoid malloc() calls during
@ -30,7 +29,12 @@
class zxx_stream: public z_stream class zxx_stream: public z_stream
{ {
public: public:
zxx_stream() { /* Forward declaration */
class StaticAllocator;
explicit zxx_stream(StaticAllocator *allocator_=nullptr)
: allocator(allocator_)
{
memset(this, 0, sizeof(z_stream)); memset(this, 0, sizeof(z_stream));
zalloc = Alloc; zalloc = Alloc;
zfree = Free; zfree = Free;
@ -40,45 +44,38 @@ public:
private: private:
static void *Alloc(void *data, uInt items, uInt size) static void *Alloc(void *data, uInt items, uInt size)
{ {
size_t buf_size = items * size;
zxx_stream *zStream = reinterpret_cast<zxx_stream *>(data); zxx_stream *zStream = reinterpret_cast<zxx_stream *>(data);
if (zStream->allocator) {
if (items == 1 && buf_size <= zStream->stateBuf.size) { return zStream->allocator->Alloc(items, size);
return zStream->stateBuf.get();
} else if (buf_size == zStream->windowBuf.size) {
return zStream->windowBuf.get();
} else {
MOZ_CRASH("No ZStreamBuf for allocation");
} }
size_t buf_size = items * size;
return ::operator new(buf_size);
} }
static void Free(void *data, void *ptr) static void Free(void *data, void *ptr)
{ {
zxx_stream *zStream = reinterpret_cast<zxx_stream *>(data); zxx_stream *zStream = reinterpret_cast<zxx_stream *>(data);
if (zStream->allocator) {
if (zStream->stateBuf.Equals(ptr)) { zStream->allocator->Free(ptr);
zStream->stateBuf.Release();
} else if (zStream->windowBuf.Equals(ptr)) {
zStream->windowBuf.Release();
} else { } else {
MOZ_CRASH("Pointer doesn't match a ZStreamBuf"); ::operator delete(ptr);
} }
} }
/** /**
* Helper class for each buffer. * Helper class for each buffer in StaticAllocator.
*/ */
template <size_t Size> template <size_t Size>
class ZStreamBuf class ZStreamBuf
{ {
public: public:
ZStreamBuf() : buf(new char[Size]), inUse(false) { } ZStreamBuf() : inUse(false) { }
char *get() char *get()
{ {
if (!inUse) { if (!inUse) {
inUse = true; inUse = true;
return buf.get(); return buf;
} else { } else {
MOZ_CRASH("ZStreamBuf already in use"); MOZ_CRASH("ZStreamBuf already in use");
} }
@ -86,21 +83,54 @@ private:
void Release() void Release()
{ {
memset(buf.get(), 0, Size); memset(buf, 0, Size);
inUse = false; inUse = false;
} }
bool Equals(const void *other) { return other == buf.get(); } bool Equals(const void *other) { return other == buf; }
static const size_t size = Size; static const size_t size = Size;
private: private:
mozilla::UniquePtr<char[]> buf; char buf[Size];
bool inUse; bool inUse;
}; };
ZStreamBuf<0x3000> stateBuf; // 0x3000 is an arbitrary size above 10K. public:
ZStreamBuf<1 << MAX_WBITS> windowBuf; /**
* Special allocator that uses static buffers to allocate from.
*/
class StaticAllocator
{
public:
void *Alloc(uInt items, uInt size)
{
if (items == 1 && size <= stateBuf.size) {
return stateBuf.get();
} else if (items * size == windowBuf.size) {
return windowBuf.get();
} else {
MOZ_CRASH("No ZStreamBuf for allocation");
}
}
void Free(void *ptr)
{
if (stateBuf.Equals(ptr)) {
stateBuf.Release();
} else if (windowBuf.Equals(ptr)) {
windowBuf.Release();
} else {
MOZ_CRASH("Pointer doesn't match a ZStreamBuf");
}
}
ZStreamBuf<0x3000> stateBuf; // 0x3000 is an arbitrary size above 10K.
ZStreamBuf<1 << MAX_WBITS> windowBuf;
};
private:
StaticAllocator *allocator;
}; };
/** /**