Bug 1207827 - Switch jit::Pool to a LifoAllocPolicy. r=nbp
☠☠ backed out by d3659c740f48 ☠ ☠
authorJakob Olesen <jolesen@mozilla.com>
Tue, 20 Oct 2015 12:57:39 -0700
changeset 303827 0ea4e13f313d26d34cb1762d1781a53153020800
parent 303826 4e69844a11f63c3af21f471219d9fce622d88d70
child 303828 a77d26defefc0f3dcafff2dc5810d7455262c136
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1207827
milestone44.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 1207827 - Switch jit::Pool to a LifoAllocPolicy. r=nbp This is possible because we no longer PodCopy the pools. Use a more reasonable size for the inline memory in the loadOffsets vector (8 loads instead of 512). This saves stack space when a MacroAssembler is created on the stack. Use a matching inline size of 8 entries for the poolData array itself. Don't drop memory in Pool::reset() by calling placement new - call Vector::clear() instead which hangs on to previously allocated memory for use by the next pool. Delete an unused array of pools in arm64/vixl/MozBaseAssembler-vixl.h.
js/src/jit/arm64/vixl/MozBaseAssembler-vixl.h
js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
--- a/js/src/jit/arm64/vixl/MozBaseAssembler-vixl.h
+++ b/js/src/jit/arm64/vixl/MozBaseAssembler-vixl.h
@@ -183,19 +183,16 @@ class MozBaseAssembler : public js::jit:
  protected:
   // The buffer into which code and relocation info are generated.
   ARMBuffer armbuffer_;
 
   js::jit::CompactBufferWriter jumpRelocations_;
   js::jit::CompactBufferWriter dataRelocations_;
   js::jit::CompactBufferWriter relocations_;
   js::jit::CompactBufferWriter preBarriers_;
-
-  // Literal pools.
-  mozilla::Array<js::jit::Pool, 4> pools_;
 };
 
 
 }  // namespace vixl
 
 
 #endif  // jit_arm64_vixl_MozBaseAssembler_vixl_h
 
--- a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
+++ b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
@@ -70,41 +70,35 @@
 // for simplicity the code below is specialized for fixed 32-bit sized
 // instructions and makes no attempt to support variable length
 // instructions. The base assembler buffer which supports variable width
 // instruction is used by the x86 and x64 backends.
 
 namespace js {
 namespace jit {
 
-typedef Vector<BufferOffset, 512, OldJitAllocPolicy> LoadOffsets;
-
 // The allocation unit size for pools.
 typedef int32_t PoolAllocUnit;
 
-struct Pool : public OldJitAllocPolicy
+struct Pool
 {
   private:
     // The maximum program-counter relative offset below which the instruction
     // set can encode. Different classes of intructions might support different
     // ranges but for simplicity the minimum is used here, and for the ARM this
     // is constrained to 1024 by the float load instructions.
     const size_t maxOffset_;
     // An offset to apply to program-counter relative offsets. The ARM has a
     // bias of 8.
     const unsigned bias_;
 
-    // The number of PoolAllocUnit sized entires used from the poolData vector.
-    unsigned numEntries_;
-    // The available size of the poolData vector, in PoolAllocUnits.
-    unsigned buffSize;
-    // The content of the pool entries.  Invariant: If poolData_ is nullptr then
-    // buffSize will be zero and oom_ will return true.
-    PoolAllocUnit* poolData_;
-    // Flag that tracks OOM conditions.
+    // The content of the pool entries.
+    Vector<PoolAllocUnit, 8, LifoAllocPolicy<Fallible>> poolData_;
+
+    // Flag that tracks OOM conditions. This is set after any append failed.
     bool oom_;
 
     // The limiting instruction and pool-entry pair. The instruction program
     // counter relative offset of this limiting instruction will go out of range
     // first as the pool position moves forward. It is more efficient to track
     // just this limiting pair than to recheck all offsets when testing if the
     // pool needs to be dumped.
     //
@@ -114,72 +108,62 @@ struct Pool : public OldJitAllocPolicy
     // 2. The pool entry index of the limiting pool entry.
     unsigned limitingUsee;
 
   public:
     // A record of the code offset of instructions that reference pool
     // entries. These instructions need to be patched when the actual position
     // of the instructions and pools are known, and for the code below this
     // occurs when each pool is finished, see finishPool().
-    LoadOffsets loadOffsets;
+    Vector<BufferOffset, 8, LifoAllocPolicy<Fallible>> loadOffsets;
 
+    // Create a Pool. Don't allocate anything from lifoAloc, just capture its reference.
     explicit Pool(size_t maxOffset, unsigned bias, LifoAlloc& lifoAlloc)
       : maxOffset_(maxOffset),
         bias_(bias),
-        numEntries_(0),
-        buffSize(8),
-        poolData_(lifoAlloc.newArrayUninitialized<PoolAllocUnit>(buffSize)),
+        poolData_(lifoAlloc),
         oom_(false),
         limitingUser(),
         limitingUsee(INT_MIN),
-        loadOffsets()
+        loadOffsets(lifoAlloc)
     {
-        if (poolData_ == nullptr) {
-            buffSize = 0;
-            oom_ = true;
-        }
     }
 
-    static const unsigned Garbage = 0xa5a5a5a5;
-    Pool()
-      : maxOffset_(Garbage), bias_(Garbage)
-    { }
-
     // If poolData() returns nullptr then oom_ will also be true.
-    PoolAllocUnit* poolData() const {
-        return poolData_;
+    const PoolAllocUnit* poolData() const {
+        return poolData_.begin();
     }
 
     unsigned numEntries() const {
-        return numEntries_;
+        return poolData_.length();
     }
 
     size_t getPoolSize() const {
-        return numEntries_ * sizeof(PoolAllocUnit);
+        return numEntries() * sizeof(PoolAllocUnit);
     }
 
     bool oom() const {
         return oom_;
     }
 
     // Update the instruction/pool-entry pair that limits the position of the
     // pool. The nextInst is the actual offset of the new instruction being
     // allocated.
     //
     // This is comparing the offsets, see checkFull() below for the equation,
     // but common expressions on both sides have been canceled from the ranges
     // being compared. Notably, the poolOffset cancels out, so the limiting pair
     // does not depend on where the pool is placed.
     void updateLimiter(BufferOffset nextInst) {
         ptrdiff_t oldRange = limitingUsee * sizeof(PoolAllocUnit) - limitingUser.getOffset();
-        ptrdiff_t newRange = numEntries_ * sizeof(PoolAllocUnit) - nextInst.getOffset();
+        ptrdiff_t newRange = getPoolSize() - nextInst.getOffset();
         if (!limitingUser.assigned() || newRange > oldRange) {
             // We have a new largest range!
             limitingUser = nextInst;
-            limitingUsee = numEntries_;
+            limitingUsee = numEntries();
         }
     }
 
     // Check if inserting a pool at the actual offset poolOffset would place
     // pool entries out of reach. This is called before inserting instructions
     // to check that doing so would not push pool entries out of reach, and if
     // so then the pool would need to be firstly dumped. The poolOffset is the
     // first word of the pool, after the guard and header and alignment fill.
@@ -192,50 +176,30 @@ struct Pool : public OldJitAllocPolicy
         return offset >= maxOffset_;
     }
 
     static const unsigned OOM_FAIL = unsigned(-1);
 
     unsigned insertEntry(unsigned num, uint8_t* data, BufferOffset off, LifoAlloc& lifoAlloc) {
         if (oom_)
             return OOM_FAIL;
-        if (numEntries_ + num >= buffSize) {
-            // Grow the poolData_ vector.
-            unsigned newSize = buffSize*2;
-            PoolAllocUnit* tmp = lifoAlloc.newArrayUninitialized<PoolAllocUnit>(newSize);
-            if (tmp == nullptr) {
-                oom_ = true;
-                return OOM_FAIL;
-            }
-            mozilla::PodCopy(tmp, poolData_, numEntries_);
-            poolData_ = tmp;
-            buffSize = newSize;
+        unsigned ret = numEntries();
+        if (!poolData_.append((PoolAllocUnit*)data, num) || !loadOffsets.append(off)) {
+            oom_ = true;
+            return OOM_FAIL;
         }
-        mozilla::PodCopy(&poolData_[numEntries_], (PoolAllocUnit*)data, num);
-        loadOffsets.append(off.getOffset());
-        unsigned ret = numEntries_;
-        numEntries_ += num;
         return ret;
     }
 
-    bool reset(LifoAlloc& a) {
-        numEntries_ = 0;
-        buffSize = 8;
-        poolData_ = static_cast<PoolAllocUnit*>(a.alloc(buffSize * sizeof(PoolAllocUnit)));
-        if (poolData_ == nullptr) {
-            oom_ = true;
-            buffSize = 0;
-            return false;
-        }
-
-        new (&loadOffsets) LoadOffsets;
+    void reset() {
+        poolData_.clear();
+        loadOffsets.clear();
 
         limitingUser = BufferOffset();
         limitingUsee = -1;
-        return true;
     }
 };
 
 
 // The InstSize is the sizeof(Inst) but is needed here because the buffer is
 // defined before the Instruction.
 template <size_t SliceSize, size_t InstSize, class Inst, class Asm>
 struct AssemblerBufferWithConstantPools : public AssemblerBuffer<SliceSize, Inst>
@@ -358,19 +322,19 @@ struct AssemblerBufferWithConstantPools 
                                      size_t instBufferAlign, size_t poolMaxOffset,
                                      unsigned pcBias, uint32_t alignFillInst, uint32_t nopFillInst,
                                      unsigned nopFill = 0)
       : poolEntryCount(0),
         guardSize_(guardSize),
         headerSize_(headerSize),
         poolMaxOffset_(poolMaxOffset),
         pcBias_(pcBias),
-        pool_(),
+        pool_(poolMaxOffset, pcBias, this->lifoAlloc_),
         instBufferAlign_(instBufferAlign),
-        poolInfo_(this->lifoAlloc_),  // OK: Vector() doesn't allocate, append() does.
+        poolInfo_(this->lifoAlloc_),
         canNotPlacePool_(false),
 #ifdef DEBUG
         canNotPlacePoolStartOffset_(0),
         canNotPlacePoolMaxInst_(0),
 #endif
         alignFillInst_(alignFillInst),
         nopFillInst_(nopFillInst),
         nopFill_(nopFill),
@@ -379,20 +343,16 @@ struct AssemblerBufferWithConstantPools 
     { }
 
     // We need to wait until an AutoJitContextAlloc is created by the
     // MacroAssembler before allocating any space.
     void initWithAllocator() {
         // We hand out references to lifoAlloc_ in the constructor.
         // Check that no allocations were made then.
         MOZ_ASSERT(this->lifoAlloc_.isEmpty(), "Illegal LIFO allocations before AutoJitContextAlloc");
-
-        new (&pool_) Pool (poolMaxOffset_, pcBias_, this->lifoAlloc_);
-        if (pool_.poolData() == nullptr)
-            this->fail_oom();
     }
 
   private:
     size_t sizeExcludingCurrentPool() const {
         // Return the actual size of the buffer, excluding the current pending
         // pool.
         return this->nextOffset().getOffset();
     }
@@ -588,20 +548,17 @@ struct AssemblerBufferWithConstantPools 
         // Record the pool info.
         unsigned firstEntry = poolEntryCount - pool_.numEntries();
         if (!poolInfo_.append(PoolInfo(firstEntry, data))) {
             this->fail_oom();
             return;
         }
 
         // Reset everything to the state that it was in when we started.
-        if (!pool_.reset(this->lifoAlloc_)) {
-            this->fail_oom();
-            return;
-        }
+        pool_.reset();
     }
 
   public:
     void flushPool() {
         if (this->oom())
             return;
         JitSpew(JitSpew_Pools, "[%d] Requesting a pool flush", id);
         finishPool();