Bug 1503582: Implement LifoAlloc::allocEnsureUnused r=nbp,tcampbell
authorIain Ireland <iireland@mozilla.com>
Fri, 09 Nov 2018 10:58:37 +0000
changeset 445423 a668206f59fb119af6b6c02cc2e64aa250d8a088
parent 445422 f63693feadd5bb35a11558d31a5dec4ec62db23e
child 445424 2df61d7610d6d819b666e118dd019bbeffb1410f
push id72687
push usertcampbell@mozilla.com
push dateFri, 09 Nov 2018 13:09:01 +0000
treeherderautoland@a668206f59fb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp, tcampbell
bugs1503582
milestone65.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 1503582: Implement LifoAlloc::allocEnsureUnused r=nbp,tcampbell Differential Revision: https://phabricator.services.mozilla.com/D11324
js/src/ds/LifoAlloc.h
js/src/jit/JitAllocPolicy.h
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -659,16 +659,35 @@ class LifoAlloc
         // infallible allocator.
         if (fallibleScope_) {
             JS_OOM_POSSIBLY_FAIL();
         }
 #endif
         return allocImpl(n);
     }
 
+    // Allocates |n| bytes if we can guarantee that we will have
+    // |needed| unused bytes remaining. Returns nullptr if we can't.
+    // This is useful for maintaining our ballast invariants while
+    // attempting fallible allocations.
+    MOZ_ALWAYS_INLINE
+    void* allocEnsureUnused(size_t n, size_t needed) {
+        JS_OOM_POSSIBLY_FAIL();
+        MOZ_ASSERT(fallibleScope_);
+
+        detail::BumpChunk::Mark m = mark();
+        void *result = allocImpl(n);
+        if (!ensureUnusedApproximate(needed)) {
+            release(m);
+            return nullptr;
+        }
+        cancelMark(m);
+        return result;
+    }
+
     template<typename T, typename... Args>
     MOZ_ALWAYS_INLINE T*
     allocInSize(size_t n, Args&&... args)
     {
         MOZ_ASSERT(n >= sizeof(T), "must request enough space to store a T");
         static_assert(alignof(T) <= detail::LIFO_ALLOC_ALIGN,
                       "LifoAlloc must provide enough alignment to store T");
         void* ptr = alloc(n);
@@ -797,16 +816,22 @@ class LifoAlloc
         unused_.appendAll(std::move(released));
 
         // Release everything which follows the mark in the last chunk.
         if (!chunks_.empty()) {
             chunks_.last()->release(mark);
         }
     }
 
+  private:
+    void cancelMark(Mark mark) {
+        markCount--;
+    }
+
+  public:
     void releaseAll() {
         MOZ_ASSERT(!markCount);
         for (detail::BumpChunk& bc : chunks_) {
             bc.release();
         }
         unused_.appendAll(std::move(chunks_));
     }
 
--- a/js/src/jit/JitAllocPolicy.h
+++ b/js/src/jit/JitAllocPolicy.h
@@ -43,46 +43,28 @@ class TempAllocator
     void* allocateInfallible(size_t bytes)
     {
         return lifoScope_.alloc().allocInfallible(bytes);
     }
 
     MOZ_MUST_USE void* allocate(size_t bytes)
     {
         LifoAlloc::AutoFallibleScope fallibleAllocator(lifoAlloc());
-        void* p = lifoScope_.alloc().alloc(bytes);
-
-        // The above allocation will allocate memory out of the
-        // lifo alloc's ballast, so we call ensureBallast to
-        // replenish it. If we fail to replenish the ballast, then
-        // future "infallible" allocations could fail.  (Returning
-        // nullptr is insufficient because of cases like
-        // CompilerConstraintList::add, where we delay the OOM
-        // failure until later.)
-        AutoEnterOOMUnsafeRegion oomUnsafe;
-        if (!ensureBallast()) {
-            oomUnsafe.crash("Failed to replenish ballast in TempAllocator::allocate");
-        }
-        return p;
+        return lifoScope_.alloc().allocEnsureUnused(bytes, BallastSize);
     }
 
     template <typename T>
     MOZ_MUST_USE T* allocateArray(size_t n)
     {
         LifoAlloc::AutoFallibleScope fallibleAllocator(lifoAlloc());
         size_t bytes;
         if (MOZ_UNLIKELY(!CalculateAllocSize<T>(n, &bytes))) {
             return nullptr;
         }
-        T* p = static_cast<T*>(lifoScope_.alloc().alloc(bytes));
-        AutoEnterOOMUnsafeRegion oomUnsafe;
-        if (!ensureBallast()) {
-            oomUnsafe.crash("Failed to replenish ballast in TempAllocator::allocateArray");
-        }
-        return p;
+        return static_cast<T*>(lifoScope_.alloc().allocEnsureUnused(bytes, BallastSize));
     }
 
     // View this allocator as a fallible allocator.
     struct Fallible { TempAllocator& alloc; };
     Fallible fallible() { return { *this }; }
 
     LifoAlloc* lifoAlloc() {
         return &lifoScope_.alloc();