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 255664 aac7de995646f3d187d01d7f1e50c19bd00fd738
parent 255663 2e72d754d8d04ddf3e3cf2ed16fa0c5a4b8f0765
child 255665 2fcbd0b82ec60989f6e8035ea88da7c99ba52f9d
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnfroyd
bugs1059797
milestone38.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
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;
 
 /**