author | Mike Hommey <mh+mozilla@glandium.org> |
Tue, 28 Oct 2014 16:45:17 +0900 | |
changeset 212712 | 44c6d392bbc850ee299189c17da888bfd8b3fa91 |
parent 212711 | 48099863baecf556a76a607811064e06daa88671 |
child 212713 | 3bec46585a18ef6f25c335d9a44bc287ac97dae7 |
push id | 51042 |
push user | ryanvm@gmail.com |
push date | Tue, 28 Oct 2014 20:25:03 +0000 |
treeherder | mozilla-inbound@53d84829b2b8 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | froydnj |
bugs | 1059797 |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/mozglue/linker/Mappable.cpp +++ b/mozglue/linker/Mappable.cpp @@ -99,17 +99,17 @@ MappableExtractFile::Create(const char * /* Map the temporary file for use as inflate buffer */ MappedPtr buffer(MemoryRange::mmap(nullptr, stream->GetUncompressedSize(), PROT_WRITE, MAP_SHARED, fd, 0)); if (buffer == MAP_FAILED) { ERROR("Couldn't map %s to decompress library", file.get()); return nullptr; } - z_stream zStream = stream->GetZStream(buffer); + zxx_stream zStream = stream->GetZStream(buffer); /* Decompress */ if (inflateInit2(&zStream, -MAX_WBITS) != Z_OK) { ERROR("inflateInit failed: %s", zStream.msg); return nullptr; } if (inflate(&zStream, Z_FINISH) != Z_STREAM_END) { ERROR("inflate failed: %s", zStream.msg);
--- a/mozglue/linker/Mappable.h +++ b/mozglue/linker/Mappable.h @@ -175,17 +175,17 @@ private: /* Zip reference */ mozilla::RefPtr<Zip> zip; /* Decompression buffer */ mozilla::UniquePtr<_MappableBuffer> buffer; /* Zlib data */ - z_stream zStream; + zxx_stream zStream; }; /** * Mappable implementation for seekable zStreams. * Inflates the mapped bits in a temporary buffer, on demand. */ class MappableSeekableZStream: public Mappable {
--- a/mozglue/linker/SeekableZStream.cpp +++ b/mozglue/linker/SeekableZStream.cpp @@ -67,18 +67,17 @@ SeekableZStream::DecompressChunk(void *w size_t chunkLen = isLastChunk ? lastChunkSize : chunkSize; if (length == 0 || length > chunkLen) length = chunkLen; DEBUG_LOG("DecompressChunk #%" PRIdSize " @%p (%" PRIdSize "/% " PRIdSize ")", chunk, where, length, chunkLen); - z_stream zStream; - memset(&zStream, 0, sizeof(zStream)); + zxx_stream zStream; zStream.avail_in = (isLastChunk ? totalSize : uint32_t(offsetTable[chunk + 1])) - uint32_t(offsetTable[chunk]); zStream.next_in = const_cast<Bytef *>(buffer + uint32_t(offsetTable[chunk])); zStream.avail_out = length; zStream.next_out = reinterpret_cast<Bytef *>(where); /* Decompress chunk */ if (inflateInit2(&zStream, windowBits) != Z_OK) {
--- a/mozglue/linker/Zip.h +++ b/mozglue/linker/Zip.h @@ -5,17 +5,108 @@ #ifndef Zip_h #define Zip_h #include <cstring> #include <stdint.h> #include <vector> #include <zlib.h> #include "Utils.h" +#include "mozilla/Assertions.h" #include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" + +/** + * Helper class wrapping z_stream to avoid malloc() calls during + * inflate. Do not use for deflate. + * inflateInit allocates two buffers: + * - one for its internal state, which is "approximately 10K bytes" according + * to inflate.h from zlib. + * - one for the compression window, which depends on the window size passed + * to inflateInit2, but is never greater than 32K (1 << MAX_WBITS). + * Those buffers are created at instantiation time instead of when calling + * inflateInit2. When inflateInit2 is called, it will call zxx_stream::Alloc + * to get both these buffers. zxx_stream::Alloc will choose one of the + * pre-allocated buffers depending on the requested size. + */ +class zxx_stream: public z_stream +{ +public: + zxx_stream() { + memset(this, 0, sizeof(z_stream)); + zalloc = Alloc; + zfree = Free; + opaque = this; + } + +private: + static void *Alloc(void *data, uInt items, uInt size) + { + size_t buf_size = items * size; + zxx_stream *zStream = reinterpret_cast<zxx_stream *>(data); + + if (items == 1 && buf_size <= zStream->stateBuf.size) { + return zStream->stateBuf.get(); + } else if (buf_size == zStream->windowBuf.size) { + return zStream->windowBuf.get(); + } else { + MOZ_CRASH("No ZStreamBuf for allocation"); + } + } + + static void Free(void *data, void *ptr) + { + zxx_stream *zStream = reinterpret_cast<zxx_stream *>(data); + + if (zStream->stateBuf.Equals(ptr)) { + zStream->stateBuf.Release(); + } else if (zStream->windowBuf.Equals(ptr)) { + zStream->windowBuf.Release(); + } else { + MOZ_CRASH("Pointer doesn't match a ZStreamBuf"); + } + } + + /** + * Helper class for each buffer. + */ + template <size_t Size> + class ZStreamBuf + { + public: + ZStreamBuf() : buf(new char[Size]), inUse(false) { } + + char *get() + { + if (!inUse) { + inUse = true; + return buf.get(); + } else { + MOZ_CRASH("ZStreamBuf already in use"); + } + } + + void Release() + { + memset(buf.get(), 0, Size); + inUse = false; + } + + bool Equals(const void *other) { return other == buf.get(); } + + static const size_t size = Size; + + private: + mozilla::UniquePtr<char[]> buf; + bool inUse; + }; + + ZStreamBuf<0x3000> stateBuf; // 0x3000 is an arbitrary size above 10K. + ZStreamBuf<1 << MAX_WBITS> windowBuf; +}; /** * Forward declaration */ class ZipCollection; /** * Class to handle access to Zip archive streams. The Zip archive is mapped @@ -82,24 +173,23 @@ public: * Getters */ const void *GetBuffer() { return compressedBuf; } size_t GetSize() { return compressedSize; } size_t GetUncompressedSize() { return uncompressedSize; } Type GetType() { return type; } /** - * Returns a z_stream for use with inflate functions using the given + * Returns a zxx_stream for use with inflate functions using the given * buffer as inflate output. The caller is expected to allocate enough * memory for the Stream uncompressed size. */ - z_stream GetZStream(void *buf) + zxx_stream GetZStream(void *buf) { - z_stream zStream; - memset(&zStream, 0, sizeof(zStream)); + zxx_stream zStream; zStream.avail_in = compressedSize; zStream.next_in = reinterpret_cast<Bytef *>( const_cast<void *>(compressedBuf)); zStream.avail_out = uncompressedSize; zStream.next_out = static_cast<Bytef *>(buf); return zStream; }