Bug 1305360 - Part 1: Add a mechanism to allow users to opt out of protection for small buffers. r=jandem
authorEmanuel Hoogeveen <emanuel.hoogeveen@gmail.com>
Tue, 27 Sep 2016 15:38:00 -0400
changeset 315941 b19e10ea4577c4ecc1cd0db76f76ff3f24b01e17
parent 315940 4a6f6c64ae89d18931c50286076f8a0030c75095
child 315942 8468a31dcb9441bbdd8a1f4f27a982409c677f0a
push id20634
push usercbook@mozilla.com
push dateFri, 30 Sep 2016 10:10:13 +0000
treeherderfx-team@afe79b010d13 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1305360
milestone52.0a1
Bug 1305360 - Part 1: Add a mechanism to allow users to opt out of protection for small buffers. r=jandem
js/src/ds/PageProtectingVector.h
js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h
js/src/jit/x86-shared/BaseAssembler-x86-shared.h
--- a/js/src/ds/PageProtectingVector.h
+++ b/js/src/ds/PageProtectingVector.h
@@ -53,23 +53,32 @@ class PageProtectingVector final
      * the whole page). As a result, if |unprotectedBytes >= pageSize|, we know
      * we can protect at least one more page, and |unprotectedBytes & ~pageMask|
      * is always the number of additional bytes we can protect. Put another way,
      * |offsetToPage + protectedBytes + unprotectedBytes == vector.length()|
      * always holds, and if |protectedBytes != 0| then |unprotectedBytes >= 0|.
      */
     intptr_t unprotectedBytes;
 
+    /*
+     * The size in bytes that a buffer needs to be before its pages will be
+     * protected. This is intended to reduce churn for small vectors while
+     * still offering protection when they grow large enough.
+     */
+    size_t protectionLowerBound;
+
     bool protectionEnabled;
     bool regionUnprotected;
 
     void updateOffsetToPage() {
         unprotectedBytes += offsetToPage;
         offsetToPage = (pageSize - (uintptr_t(vector.begin()) & pageMask)) & pageMask;
         unprotectedBytes -= offsetToPage;
+        protectionEnabled = vector.capacity() >= protectionLowerBound &&
+                            vector.capacity() >= pageSize + offsetToPage;
     }
 
     void protect() {
         MOZ_ASSERT(!regionUnprotected);
         if (protectionEnabled && unprotectedBytes >= intptr_t(pageSize)) {
             size_t toProtect = size_t(unprotectedBytes) & ~pageMask;
             uintptr_t addr = uintptr_t(vector.begin()) + offsetToPage + protectedBytes;
             gc::MakePagesReadOnly(reinterpret_cast<void*>(addr), toProtect);
@@ -89,16 +98,20 @@ class PageProtectingVector final
         }
     }
 
     void protectNewBuffer() {
         updateOffsetToPage();
         protect();
     }
 
+    void unprotectOldBuffer() {
+        unprotect();
+    }
+
     bool anyProtected(size_t first, size_t last) {
         return last >= offsetToPage && first < offsetToPage + protectedBytes;
     }
 
     void setContainingRegion(size_t first, size_t last, uintptr_t* addr, size_t* size) {
         if (first < offsetToPage)
             first = offsetToPage;
         if (last > offsetToPage + protectedBytes - 1)
@@ -120,17 +133,17 @@ class PageProtectingVector final
     {
         PageProtectingVector* vector;
 
       public:
         AutoUnprotect() : vector(nullptr) {};
 
         void emplace(PageProtectingVector* holder) {
             vector = holder;
-            vector->unprotect();
+            vector->unprotectOldBuffer();
         }
 
         explicit AutoUnprotect(PageProtectingVector* holder) {
             emplace(holder);
         }
 
         ~AutoUnprotect() {
             if (vector)
@@ -141,33 +154,32 @@ class PageProtectingVector final
   public:
     explicit PageProtectingVector(AllocPolicy policy = AllocPolicy())
       : vector(policy),
         pageSize(gc::SystemPageSize()),
         pageMask(pageSize - 1),
         offsetToPage(0),
         protectedBytes(0),
         unprotectedBytes(0),
+        protectionLowerBound(0),
         protectionEnabled(false),
-        regionUnprotected(false) { updateOffsetToPage(); }
+        regionUnprotected(false) { protectNewBuffer(); }
 
-    ~PageProtectingVector() { unprotect(); }
+    ~PageProtectingVector() { unprotectOldBuffer(); }
 
-    /* Enable protection for the entire buffer. */
-    void enableProtection() {
-        MOZ_ASSERT(!protectionEnabled);
-        protectionEnabled = true;
-        protectNewBuffer();
-    }
-
-    /* Disable protection for the entire buffer. */
-    void disableProtection() {
-        MOZ_ASSERT(protectionEnabled);
-        unprotect();
-        protectionEnabled = false;
+    /*
+     * Sets the lower bound on the size, in bytes, that this vector's underlying
+     * capacity has to be before its used pages will be protected.
+     */
+    void setLowerBoundForProtection(size_t bytes) {
+        if (protectionLowerBound != bytes) {
+            unprotectOldBuffer();
+            protectionLowerBound = bytes;
+            protectNewBuffer();
+        }
     }
 
     /*
      * Disable protection on the smallest number of pages containing
      * both |firstByteOffset| and |lastByteOffset|.
      */
     void unprotectRegion(size_t firstByteOffset, size_t lastByteOffset) {
         MOZ_ASSERT(!regionUnprotected);
--- a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h
+++ b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h
@@ -82,16 +82,18 @@ namespace jit {
             if (MOZ_UNLIKELY(!m_buffer.append(reinterpret_cast<unsigned char*>(&value), size)))
                 oomDetected();
         }
 
     public:
         AssemblerBuffer()
             : m_oom(false)
         {
+            // Provide memory protection once the buffer starts to get big.
+            m_buffer.setLowerBoundForProtection(32 * 1024);
         }
 
         void ensureSpace(size_t space)
         {
             if (MOZ_UNLIKELY(!m_buffer.reserve(m_buffer.length() + space)))
                 oomDetected();
         }
 
@@ -134,19 +136,16 @@ namespace jit {
             return m_oom;
         }
 
         const unsigned char* buffer() const {
             MOZ_ASSERT(!m_oom);
             return m_buffer.begin();
         }
 
-        void enableBufferProtection() { m_buffer.enableProtection(); }
-        void disableBufferProtection() { m_buffer.disableProtection(); }
-
         void unprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) {
             m_buffer.unprotectRegion(firstByteOffset, lastByteOffset);
         }
         void reprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) {
             m_buffer.reprotectRegion(firstByteOffset, lastByteOffset);
         }
 
     protected:
--- a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h
+++ b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h
@@ -3846,19 +3846,16 @@ threeByteOpImmSimd("vblendps", VEX_PD, O
     {
         memcpy(buffer, m_formatter.buffer(), size());
     }
     MOZ_MUST_USE bool appendBuffer(const BaseAssembler& other)
     {
         return m_formatter.append(other.m_formatter.buffer(), other.size());
     }
 
-    void enableBufferProtection() { m_formatter.enableBufferProtection(); }
-    void disableBufferProtection() { m_formatter.disableBufferProtection(); }
-
     void unprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) {
         m_formatter.unprotectDataRegion(firstByteOffset, lastByteOffset);
     }
     void reprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) {
         m_formatter.reprotectDataRegion(firstByteOffset, lastByteOffset);
     }
 
   protected:
@@ -5127,19 +5124,16 @@ threeByteOpImmSimd("vblendps", VEX_PD, O
         bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
         unsigned char* data() { return m_buffer.data(); }
 
         MOZ_MUST_USE bool append(const unsigned char* values, size_t size)
         {
             return m_buffer.append(values, size);
         }
 
-        void enableBufferProtection() { m_buffer.enableBufferProtection(); }
-        void disableBufferProtection() { m_buffer.disableBufferProtection(); }
-
         void unprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) {
             m_buffer.unprotectDataRegion(firstByteOffset, lastByteOffset);
         }
         void reprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) {
             m_buffer.reprotectDataRegion(firstByteOffset, lastByteOffset);
         }
 
     private: