Bug 848773 - Add x86 BCJ filter for szip. r=nfroyd,r=ted
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 08 Mar 2013 09:32:56 +0100
changeset 124215 b7dfaca2b3cce1c27298325aa29ab5917285ff1f
parent 124214 b87aedbe45c76a7d3603a3dc0c381c6bc0a07409
child 124216 65c8f4a189924998be8b1b5137a201c4c841eea1
push id24412
push userryanvm@gmail.com
push dateSun, 10 Mar 2013 00:01:53 +0000
treeherdermozilla-central@9e6232e86000 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnfroyd, ted
bugs848773
milestone22.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 848773 - Add x86 BCJ filter for szip. r=nfroyd,r=ted
mozglue/linker/Makefile.in
mozglue/linker/SeekableZStream.cpp
mozglue/linker/SeekableZStream.h
mozglue/linker/szip.cpp
--- a/mozglue/linker/Makefile.in
+++ b/mozglue/linker/Makefile.in
@@ -38,8 +38,11 @@ include $(topsrcdir)/config/rules.mk
 
 ifeq (arm,$(TARGET_CPU))
 ifdef MOZ_THUMB2
 HOST_CXXFLAGS += -DTARGET_THUMB
 else
 HOST_CXXFLAGS += -DTARGET_ARM
 endif
 endif
+ifeq (x86,$(CPU_ARCH))
+HOST_CXXFLAGS += -DTARGET_X86
+endif
--- a/mozglue/linker/SeekableZStream.cpp
+++ b/mozglue/linker/SeekableZStream.cpp
@@ -165,22 +165,106 @@ BCJ_ARM_filter(off_t offset, SeekableZSt
       dest >>= 2;
       buf[i] = dest;
       buf[i + 1] = dest >> 8;
       buf[i + 2] = dest >> 16;
     }
   }
 }
 
+/* Branch/Call/Jump conversion filter for x86, derived from xz-utils
+ * by Igor Pavlov and Lasse Collin, published in the public domain */
+
+#define Test86MSByte(b) ((b) == 0 || (b) == 0xff)
+
+static void
+BCJ_X86_filter(off_t offset, SeekableZStream::FilterDirection dir,
+               unsigned char *buf, size_t size)
+{
+  static const bool MASK_TO_ALLOWED_STATUS[8] =
+    { true, true, true, false, true, false, false, false };
+
+  static const uint32_t MASK_TO_BIT_NUMBER[8] =
+    { 0, 1, 2, 2, 3, 3, 3, 3 };
+
+  uint32_t prev_mask = 0;
+  uint32_t prev_pos = 0;
+
+  for (size_t i = 0; i <= size - 5;) {
+    uint8_t b = buf[i];
+    if (b != 0xe8 && b != 0xe9) {
+      ++i;
+      continue;
+    }
+
+    const uint32_t off = offset + (uint32_t)(i) - prev_pos;
+    prev_pos = offset + (uint32_t)(i);
+
+    if (off > 5) {
+      prev_mask = 0;
+    } else {
+      for (uint32_t i = 0; i < off; ++i) {
+        prev_mask &= 0x77;
+        prev_mask <<= 1;
+      }
+    }
+
+    b = buf[i + 4];
+
+    if (Test86MSByte(b) && MASK_TO_ALLOWED_STATUS[(prev_mask >> 1) & 0x7]
+        && (prev_mask >> 1) < 0x10) {
+
+      uint32_t src = ((uint32_t)(b) << 24)
+                     | ((uint32_t)(buf[i + 3]) << 16)
+                     | ((uint32_t)(buf[i + 2]) << 8)
+                     | (buf[i + 1]);
+
+      uint32_t dest;
+      while (true) {
+        if (dir == SeekableZStream::FILTER)
+          dest = src + (offset + (uint32_t)(i) + 5);
+        else
+          dest = src - (offset + (uint32_t)(i) + 5);
+
+        if (prev_mask == 0)
+          break;
+
+        const uint32_t i = MASK_TO_BIT_NUMBER[prev_mask >> 1];
+
+        b = (uint8_t)(dest >> (24 - i * 8));
+
+        if (!Test86MSByte(b))
+          break;
+
+        src = dest ^ ((1 << (32 - i * 8)) - 1);
+      }
+
+      buf[i + 4] = (uint8_t)(~(((dest >> 24) & 1) - 1));
+      buf[i + 3] = (uint8_t)(dest >> 16);
+      buf[i + 2] = (uint8_t)(dest >> 8);
+      buf[i + 1] = (uint8_t)(dest);
+      i += 5;
+      prev_mask = 0;
+
+    } else {
+      ++i;
+      prev_mask |= 1;
+      if (Test86MSByte(b))
+        prev_mask |= 0x10;
+    }
+  }
+}
 
 SeekableZStream::ZStreamFilter
 SeekableZStream::GetFilter(SeekableZStream::FilterId id)
 {
   switch (id) {
   case BCJ_THUMB:
     return BCJ_Thumb_filter;
   case BCJ_ARM:
     return BCJ_ARM_filter;
+  case BCJ_X86:
+    return BCJ_X86_filter;
   default:
     return NULL;
   }
   return NULL;
 }
--- a/mozglue/linker/SeekableZStream.h
+++ b/mozglue/linker/SeekableZStream.h
@@ -101,16 +101,17 @@ public:
   };
   typedef void (*ZStreamFilter)(off_t, FilterDirection,
                                   unsigned char *, size_t);
 
   enum FilterId {
     NONE,
     BCJ_THUMB,
     BCJ_ARM,
+    BCJ_X86,
     FILTER_MAX
   };
   static ZStreamFilter GetFilter(FilterId id);
 
   static ZStreamFilter GetFilter(uint16_t id) {
     return GetFilter(static_cast<FilterId>(id));
   }
 
--- a/mozglue/linker/szip.cpp
+++ b/mozglue/linker/szip.cpp
@@ -139,16 +139,18 @@ public:
 
 private:
 
   const static SeekableZStream::FilterId DEFAULT_FILTER =
 #if defined(TARGET_THUMB)
     SeekableZStream::BCJ_THUMB;
 #elif defined(TARGET_ARM)
     SeekableZStream::BCJ_ARM;
+#elif defined(TARGET_X86)
+    SeekableZStream::BCJ_X86;
 #else
     SeekableZStream::NONE;
 #endif
 
   size_t chunkSize;
   SeekableZStream::FilterId filter;
   size_t dictSize;
 };
@@ -347,16 +349,18 @@ int main(int argc, char* argv[])
       firstArg++;
       argc--;
       if (!firstArg[0])
         break;
       if (strcmp(firstArg[0], "arm") == 0)
         filter = SeekableZStream::BCJ_ARM;
       else if (strcmp(firstArg[0], "thumb") == 0)
         filter = SeekableZStream::BCJ_THUMB;
+      else if (strcmp(firstArg[0], "x86") == 0)
+        filter = SeekableZStream::BCJ_X86;
       else {
         log("Invalid filter");
         return 1;
       }
     } else if (strcmp(firstArg[0], "-D") == 0) {
       firstArg++;
       argc--;
       if (!firstArg[0])