Bug 1059797 - Really share the same zlib inflate buffers for SeekableZStream chunks. r=nfroyd
authorMike Hommey <mh+mozilla@glandium.org>
Tue, 10 Feb 2015 16:04:37 +0900
changeset 242215 aac7de995646f3d187d01d7f1e50c19bd00fd738
parent 242214 2e72d754d8d04ddf3e3cf2ed16fa0c5a4b8f0765
child 242216 2fcbd0b82ec60989f6e8035ea88da7c99ba52f9d
push id649
push userwcosta@mozilla.com
push dateWed, 11 Feb 2015 16:57:44 +0000
reviewersnfroyd
bugs1059797
milestone38.0a1
Bug 1059797 - Really share the same zlib inflate buffers for SeekableZStream chunks. r=nfroyd
mozglue/linker/SeekableZStream.cpp
mozglue/linker/SeekableZStream.h
mozglue/linker/Zip.h
--- a/mozglue/linker/SeekableZStream.cpp
+++ b/mozglue/linker/SeekableZStream.cpp
@@ -67,17 +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);
-  zxx_stream zStream;
+  zxx_stream zStream(&allocator);
   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/SeekableZStream.h
+++ b/mozglue/linker/SeekableZStream.h
@@ -134,16 +134,19 @@ private:
   /* Offsets table */
   Array<le_uint32> offsetTable;
 
   /* Filter */
   ZStreamFilter filter;
 
   /* Deflate dictionary */
   Array<unsigned char> dictionary;
+
+  /* Special allocator for inflate to use the same buffers for every chunk */
+  zxx_stream::StaticAllocator allocator;
 };
 
 inline void
 operator++(SeekableZStream::FilterId &other)
 {
   const int orig = static_cast<int>(other);
   other = static_cast<SeekableZStream::FilterId>(orig + 1);
 }
--- a/mozglue/linker/Zip.h
+++ b/mozglue/linker/Zip.h
@@ -7,17 +7,16 @@
 
 #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
@@ -25,87 +24,118 @@
  * 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() {
+  /* Forward declaration */
+  class StaticAllocator;
+
+  explicit zxx_stream(StaticAllocator *allocator_=nullptr)
+  : allocator(allocator_)
+  {
     memset(this, 0, sizeof(z_stream));
     zalloc = Alloc;
     zfree = Free;
     opaque = this;
   }
 
 private:
   static void *Alloc(void *data, uInt items, uInt size)
   {
+    zxx_stream *zStream = reinterpret_cast<zxx_stream *>(data);
+    if (zStream->allocator) {
+      return zStream->allocator->Alloc(items, 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");
-    }
+    return ::operator new(buf_size);
   }
 
   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();
+    if (zStream->allocator) {
+      zStream->allocator->Free(ptr);
     } 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>
   class ZStreamBuf
   {
   public:
-    ZStreamBuf() : buf(new char[Size]), inUse(false) { }
+    ZStreamBuf() : inUse(false) { }
 
     char *get()
     {
       if (!inUse) {
         inUse = true;
-        return buf.get();
+        return buf;
       } else {
         MOZ_CRASH("ZStreamBuf already in use");
       }
     }
 
     void Release()
     {
-      memset(buf.get(), 0, Size);
+      memset(buf, 0, Size);
       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;
 
   private:
-    mozilla::UniquePtr<char[]> buf;
+    char buf[Size];
     bool inUse;
   };
 
-  ZStreamBuf<0x3000> stateBuf; // 0x3000 is an arbitrary size above 10K.
-  ZStreamBuf<1 << MAX_WBITS> windowBuf;
+public:
+  /**
+   * 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;
 };
 
 /**
  * Forward declaration
  */
 class ZipCollection;
 
 /**