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 id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersnfroyd, ted
bugs848773
milestone22.0a1
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])