Bug 1481556 - Compute the appropriate stub field index instead of assuming it based on execution order r=jandem
authorMatthew Gaudet <mgaudet@mozilla.com>
Tue, 07 Aug 2018 13:50:18 -0400
changeset 486358 cd69094e843a3fec0e963b62a107c5c1519d9385
parent 486357 2f962180068b5d353f3cb1d1b084382535067cd1
child 486359 42473b857282739b3878fd6e75cf13f14a54bce6
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1481556
milestone63.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 1481556 - Compute the appropriate stub field index instead of assuming it based on execution order r=jandem
js/src/jit/CacheIR.cpp
js/src/jit/CacheIR.h
js/src/jit/CacheIRCompiler.h
js/src/jit/IonCacheIRCompiler.cpp
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -32,16 +32,43 @@ const char* js::jit::CacheKindNames[] = 
 #undef DEFINE_KIND
 };
 
 void
 CacheIRWriter::assertSameCompartment(JSObject* obj) {
     assertSameCompartmentDebugOnly(cx_, obj);
 }
 
+StubField
+CacheIRWriter::readStubFieldForIon(uint32_t offset, StubField::Type type) const
+{
+    size_t index = 0;
+    size_t currentOffset = 0;
+
+    // If we've seen an offset earlier than this before, we know we can start the search
+    // there at least, otherwise, we start the search from the beginning.
+    if (lastOffset_ < offset) {
+        currentOffset = lastOffset_;
+        index = lastIndex_;
+    }
+
+    while (currentOffset != offset) {
+        currentOffset += StubField::sizeInBytes(stubFields_[index].type());
+        index++;
+        MOZ_ASSERT(index < stubFields_.length());
+    }
+
+    MOZ_ASSERT(stubFields_[index].type() == type);
+
+    lastOffset_ = currentOffset;
+    lastIndex_ = index;
+
+    return stubFields_[index];
+}
+
 IRGenerator::IRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, CacheKind cacheKind,
                          ICState::Mode mode)
   : writer(cx),
     cx_(cx),
     script_(script),
     pc_(pc),
     cacheKind_(cacheKind),
     mode_(mode)
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -439,16 +439,20 @@ class MOZ_RAII CacheIRWriter : public JS
     Vector<uint32_t, 8, SystemAllocPolicy> operandLastUsed_;
 
     // OperandId and stub offsets are stored in a single byte, so make sure
     // this doesn't overflow. We use a very conservative limit for now.
     static const size_t MaxOperandIds = 20;
     static const size_t MaxStubDataSizeInBytes = 20 * sizeof(uintptr_t);
     bool tooLarge_;
 
+    // Basic caching to avoid quadatic lookup behaviour in readStubFieldForIon.
+    mutable uint32_t lastOffset_;
+    mutable uint32_t lastIndex_;
+
     void assertSameCompartment(JSObject*);
 
     void writeOp(CacheOp op) {
         MOZ_ASSERT(uint32_t(op) <= UINT8_MAX);
         buffer_.writeByte(uint32_t(op));
         nextInstructionId_++;
     }
 
@@ -502,17 +506,19 @@ class MOZ_RAII CacheIRWriter : public JS
   public:
     explicit CacheIRWriter(JSContext* cx)
       : CustomAutoRooter(cx),
         cx_(cx),
         nextOperandId_(0),
         nextInstructionId_(0),
         numInputOperands_(0),
         stubDataSize_(0),
-        tooLarge_(false)
+        tooLarge_(false),
+        lastOffset_(0),
+        lastIndex_(0)
     {}
 
     bool failed() const { return buffer_.oom() || tooLarge_; }
 
     uint32_t numInputOperands() const { return numInputOperands_; }
     uint32_t numOperandIds() const { return nextOperandId_; }
     uint32_t numInstructions() const { return nextInstructionId_; }
 
@@ -552,20 +558,17 @@ class MOZ_RAII CacheIRWriter : public JS
     }
     uint32_t codeLength() const {
         MOZ_ASSERT(!failed());
         return buffer_.length();
     }
 
     // This should not be used when compiling Baseline code, as Baseline code
     // shouldn't bake in stub values.
-    StubField readStubFieldForIon(size_t i, StubField::Type type) const {
-        MOZ_ASSERT(stubFields_[i].type() == type);
-        return stubFields_[i];
-    }
+    StubField readStubFieldForIon(uint32_t offset, StubField::Type type) const;
 
     ObjOperandId guardIsObject(ValOperandId val) {
         writeOpWithOperandId(CacheOp::GuardIsObject, val);
         return ObjOperandId(val.id());
     }
     Int32OperandId guardIsBoolean(ValOperandId val) {
         Int32OperandId res(nextOperandId_++);
         writeOpWithOperandId(CacheOp::GuardIsBoolean, val);
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -637,34 +637,31 @@ class MOZ_RAII CacheIRCompiler
 
     // Whether this IC may read double values from uint32 arrays.
     mozilla::Maybe<bool> allowDoubleResult_;
 
     // Distance from the IC to the stub data; mostly will be
     // sizeof(stubType)
     uint32_t stubDataOffset_;
 
-    uint32_t nextStubField_;
-
     enum class StubFieldPolicy {
         Address,
         Constant
     };
 
     StubFieldPolicy stubFieldPolicy_;
 
     CacheIRCompiler(JSContext* cx, const CacheIRWriter& writer, uint32_t stubDataOffset, Mode mode, StubFieldPolicy policy)
       : cx_(cx),
         reader(writer),
         writer_(writer),
         allocator(writer_),
         liveFloatRegs_(FloatRegisterSet::All()),
         mode_(mode),
         stubDataOffset_(stubDataOffset),
-        nextStubField_(0),
         stubFieldPolicy_(policy)
     {
         MOZ_ASSERT(!writer.failed());
     }
 
     MOZ_MUST_USE bool addFailurePath(FailurePath** failure);
     MOZ_MUST_USE bool emitFailurePath(size_t i);
 
@@ -719,25 +716,22 @@ class MOZ_RAII CacheIRCompiler
 #undef DEFINE_SHARED_OP
 
     void emitLoadStubField(StubFieldOffset val, Register dest);
     void emitLoadStubFieldConstant(StubFieldOffset val, Register dest);
 
     uintptr_t readStubWord(uint32_t offset, StubField::Type type) {
         MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
         MOZ_ASSERT((offset % sizeof(uintptr_t)) == 0);
-        // We use nextStubField_ to access the data as it's stored in an as-of-yet
-        // unpacked vector, and so using the offset can be incorrect where the index
-        // would change as a result of packing.
-        return writer_.readStubFieldForIon(nextStubField_++, type).asWord();
+        return writer_.readStubFieldForIon(offset, type).asWord();
     }
     uint64_t readStubInt64(uint32_t offset, StubField::Type type) {
         MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
         MOZ_ASSERT((offset % sizeof(uintptr_t)) == 0);
-        return writer_.readStubFieldForIon(nextStubField_++, type).asInt64();
+        return writer_.readStubFieldForIon(offset, type).asInt64();
     }
     int32_t int32StubField(uint32_t offset) {
         MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
         return readStubWord(offset, StubField::Type::RawWord);
     }
     Shape* shapeStubField(uint32_t offset) {
         MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
         return (Shape*)readStubWord(offset, StubField::Type::Shape);
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -587,18 +587,16 @@ IonCacheIRCompiler::compile()
 
           default:
             MOZ_CRASH("Invalid op");
         }
 
         allocator.nextOp();
     } while (reader.more());
 
-    MOZ_RELEASE_ASSERT(nextStubField_ == writer_.numStubFields());
-
     masm.assumeUnreachable("Should have returned from IC");
 
     // Done emitting the main IC code. Now emit the failure paths.
     for (size_t i = 0; i < failurePaths.length(); i++) {
         if (!emitFailurePath(i))
             return nullptr;
         Register scratch = ic_->scratchRegisterForEntryJump();
         CodeOffset offset = masm.movWithPatch(ImmWord(-1), scratch);