Bug 1305360 - Part 1: Add a mechanism to allow users to opt out of protection for small buffers. r=jandem
☠☠ backed out by 282b5fdbd98b ☠ ☠
authorEmanuel Hoogeveen <emanuel.hoogeveen@gmail.com>
Tue, 27 Sep 2016 15:38:00 +0200
changeset 315746 eab2157634632da5e39a037c5b62d7bfa6123c7e
parent 315745 fbfe71842bb7a17bed00854803f59f67e58c0afd
child 315747 a70dda2a48b40683107eacf133e4ba27cf86dba1
push id82255
push usercbook@mozilla.com
push dateThu, 29 Sep 2016 13:51:21 +0000
treeherdermozilla-inbound@66a5416f87a2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1305360
milestone52.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 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: