Bug 1207827 - Use a Vector for poolInfo_. r=nbp
authorJakob Olesen <jolesen@mozilla.com>
Mon, 26 Oct 2015 17:06:09 -0700
changeset 304814 a205783978a08750991298a31e089271f78141e0
parent 304813 e7e10092994ca6a858c4c7dd1068436681baa973
child 304815 a6667610d4ba14c1a1505c5bb672f95b87f948a2
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 - Use a Vector for poolInfo_. r=nbp Use a Vector with 8 preallocated slots and a LifoAllocPolicy allocating from the parent AssemblerBuffer's lifoAlloc_. We'll rarely need more than 8 constant pools in a single assembler. We can't actually allocate memory from this->lifoAlloc_ in the constructor, but it is OK to capture allocator references like the Vector constructor does. Add an assertion to initWithAllocator() to verify that we didn't allocate anything from lifoAlloc_ before the MacroAssembler constructor had a chance to install an AutoJitContextAlloc.
js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
--- a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
+++ b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
@@ -302,23 +302,19 @@ struct AssemblerBufferWithConstantPools 
         BufferOffset offset;
 
         explicit PoolInfo(unsigned index, BufferOffset data)
           : firstEntryIndex(index)
           , offset(data)
         {
         }
     };
-    // The number of times we've dumped a pool, and the number of Pool Info
-    // elements used in the poolInfo vector below.
-    unsigned numDumps_;
-    // The number of PoolInfo elements available in the poolInfo vector.
-    size_t poolInfoSize_;
-    // Pointer to a vector of PoolInfo structures. Grown as needed.
-    PoolInfo* poolInfo_;
+
+    // Info for each pool that has already been dumped. This does not include any entries in pool_.
+    Vector<PoolInfo, 8, LifoAllocPolicy<Fallible>> poolInfo_;
 
     // When true dumping pools is inhibited.
     bool canNotPlacePool_;
 
 #ifdef DEBUG
     // State for validating the 'maxInst' argument to enterNoPool().
     // The buffer offset when entering the no-pool region.
     size_t canNotPlacePoolStartOffset_;
@@ -350,68 +346,56 @@ struct AssemblerBufferWithConstantPools 
     Slice* getHead() const {
         return this->head;
     }
     Slice* getTail() const {
         return this->tail;
     }
 
   public:
+    // Create an assembler buffer.
+    // Note that this constructor is not allowed to actually allocate memory from this->lifoAlloc_
+    // because the MacroAssembler constructor has not yet created an AutoJitContextAlloc.
     AssemblerBufferWithConstantPools(unsigned guardSize, unsigned headerSize,
                                      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_(),
         instBufferAlign_(instBufferAlign),
-        numDumps_(0),
-        poolInfoSize_(8),
-        poolInfo_(nullptr),
+        poolInfo_(this->lifoAlloc_),  // OK: Vector() doesn't allocate, append() does.
         canNotPlacePool_(false),
 #ifdef DEBUG
         canNotPlacePoolStartOffset_(0),
         canNotPlacePoolMaxInst_(0),
 #endif
         alignFillInst_(alignFillInst),
         nopFillInst_(nopFillInst),
         nopFill_(nopFill),
         inhibitNops_(false),
         id(-1)
     { }
 
     // We need to wait until an AutoJitContextAlloc is created by the
     // MacroAssembler before allocating any space.
     void initWithAllocator() {
-        poolInfo_ = this->lifoAlloc_.template newArrayUninitialized<PoolInfo>(poolInfoSize_);
-        if (!poolInfo_) {
-            this->fail_oom();
-            return;
-        }
+        // 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:
-    const PoolInfo& getLastPoolInfo() const {
-        // Return the PoolInfo for the last pool dumped, or a zero PoolInfo
-        // structure if none have been dumped.
-        static const PoolInfo nil = {0, 0, 0, nullptr};
-
-        if (numDumps_ > 0)
-            return poolInfo_[numDumps_ - 1];
-
-        return nil;
-    }
-
     size_t sizeExcludingCurrentPool() const {
         // Return the actual size of the buffer, excluding the current pending
         // pool.
         return this->nextOffset().getOffset();
     }
 
   public:
     size_t size() const {
@@ -545,17 +529,17 @@ struct AssemblerBufferWithConstantPools 
 
     BufferOffset putInt(uint32_t value, bool markAsBranch = false) {
         return allocEntry(1, 0, (uint8_t*)&value, nullptr, nullptr, markAsBranch);
     }
 
   private:
     void finishPool() {
         JitSpew(JitSpew_Pools, "[%d] Attempting to finish pool %d with %d entries.", id,
-                numDumps_, pool_.numEntries());
+                poolInfo_.length(), pool_.numEntries());
 
         if (pool_.numEntries() == 0) {
             // If there is no data in the pool being dumped, don't dump anything.
             JitSpew(JitSpew_Pools, "[%d] Aborting because the pool is empty", id);
             return;
         }
 
         // Should not be placing a pool in a no-pool region, check.
@@ -597,31 +581,21 @@ struct AssemblerBufferWithConstantPools 
             // the pool entry that is being loaded.  We need to do a non-trivial
             // amount of math here, since the pool that we've made does not
             // actually reside there in memory.
             JitSpew(JitSpew_Pools, "[%d] Fixing entry %d offset to %u", id, idx, codeOffset);
             Asm::PatchConstantPoolLoad(inst, (uint8_t*)inst + codeOffset);
         }
 
         // Record the pool info.
-        if (numDumps_ >= poolInfoSize_) {
-            // Grow the poolInfo vector.
-            poolInfoSize_ *= 2;
-            PoolInfo* tmp = this->lifoAlloc_.template newArrayUninitialized<PoolInfo>(poolInfoSize_);
-            if (tmp == nullptr) {
-                this->fail_oom();
-                return;
-            }
-            mozilla::PodCopy(tmp, poolInfo_, numDumps_);
-            poolInfo_ = tmp;
+        unsigned firstEntry = poolEntryCount - pool_.numEntries();
+        if (!poolInfo_.append(PoolInfo(firstEntry, data))) {
+            this->fail_oom();
+            return;
         }
-        unsigned firstEntry = poolEntryCount - pool_.numEntries();
-        MOZ_ASSERT(numDumps_ < poolInfoSize_);
-        poolInfo_[numDumps_] = PoolInfo(firstEntry, data);
-        numDumps_++;
 
         // Reset everything to the state that it was in when we started.
         if (!pool_.reset(this->lifoAlloc_)) {
             this->fail_oom();
             return;
         }
     }
 
@@ -715,17 +689,17 @@ struct AssemblerBufferWithConstantPools 
     }
 
   public:
     size_t poolEntryOffset(PoolEntry pe) const {
         MOZ_ASSERT(pe.index() < poolEntryCount - pool_.numEntries(),
                    "Invalid pool entry, or not flushed yet.");
         // Find the pool containing pe.index().
         // The array is sorted, so we can use a binary search.
-        auto b = poolInfo_, e = poolInfo_ + numDumps_;
+        auto b = poolInfo_.begin(), e = poolInfo_.end();
         // A note on asymmetric types in the upper_bound comparator:
         // http://permalink.gmane.org/gmane.comp.compilers.clang.devel/10101
         auto i = std::upper_bound(b, e, pe.index(), [](size_t value, const PoolInfo& entry) {
             return value < entry.firstEntryIndex;
         });
         // Since upper_bound finds the first pool greater than pe,
         // we want the previous one which is the last one less than or equal.
         MOZ_ASSERT(i != b, "PoolInfo not sorted or empty?");