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 358784 b19e10ea4577c4ecc1cd0db76f76ff3f24b01e17
parent 358783 4a6f6c64ae89d18931c50286076f8a0030c75095
child 358785 8468a31dcb9441bbdd8a1f4f27a982409c677f0a
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-beta@76101b503191 [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: