Bug 1250964: SharedStubs - Don't add invalid stubs, r=jandem
authorHannes Verschore <hv1989@gmail.com>
Tue, 15 Mar 2016 12:21:18 -0400
changeset 288791 a4ddac87ea0ce807686a6f18d74f25cb7a3edae8
parent 288790 2f9b5a3b2a90689a25ac91515803a0d17272583d
child 288792 447ab351338571338f840028f4bc1efe035635f8
push id30089
push userkwierso@gmail.com
push dateWed, 16 Mar 2016 00:26:08 +0000
treeherdermozilla-central@7773387a9a2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1250964
milestone48.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 1250964: SharedStubs - Don't add invalid stubs, r=jandem
js/src/jit/BaselineDebugModeOSR.h
js/src/jit/Ion.cpp
js/src/jit/SharedIC.cpp
js/src/jit/SharedIC.h
--- a/js/src/jit/BaselineDebugModeOSR.h
+++ b/js/src/jit/BaselineDebugModeOSR.h
@@ -59,17 +59,17 @@ class DebugModeOSRVolatileStub
       : engine_(ICStubCompiler::Engine::Baseline),
         stub_(static_cast<T>(stub)),
         frame_(frame),
         pcOffset_(stub->icEntry()->pcOffset())
     { }
 
     bool invalid() const {
         if (engine_ == ICStubCompiler::Engine::IonMonkey)
-            return false;
+            return stub_->invalid();
         MOZ_ASSERT(!frame_->isHandlingException());
         ICEntry& entry = frame_->script()->baselineScript()->icEntryFromPCOffset(pcOffset_);
         return stub_ != entry.fallbackStub();
     }
 
     operator const T&() const { MOZ_ASSERT(!invalid()); return stub_; }
     T operator->() const { MOZ_ASSERT(!invalid()); return stub_; }
     T* address() { MOZ_ASSERT(!invalid()); return &stub_; }
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1223,25 +1223,29 @@ IonScript::purgeOptimizedStubs(Zone* zon
                     stub = stub->next();
                     continue;
                 }
 
                 prev = stub;
                 stub = stub->next();
             }
 
+            lastStub->toFallbackStub()->setInvalid();
+
             if (lastStub->isMonitoredFallback()) {
                 // Monitor stubs can't make calls, so are always in the
                 // optimized stub space.
                 ICTypeMonitor_Fallback* lastMonStub =
                     lastStub->toMonitoredFallbackStub()->fallbackMonitorStub();
                 lastMonStub->resetMonitorStubChain(zone);
+                lastMonStub->setInvalid();
             }
         } else if (lastStub->isTypeMonitor_Fallback()) {
             lastStub->toTypeMonitor_Fallback()->resetMonitorStubChain(zone);
+            lastStub->toTypeMonitor_Fallback()->setInvalid();
         } else {
             MOZ_ASSERT(lastStub->isTableSwitch());
         }
     }
 
 #ifdef DEBUG
     // All remaining stubs must be allocated in the fallback space.
     for (size_t i = 0; i < numSharedStubs(); i++) {
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -926,16 +926,17 @@ SharedStubInfo::outerScript(JSContext* c
 {
     if (!outerScript_) {
         js::jit::JitActivationIterator iter(cx->runtime());
         JitFrameIterator it(iter);
         MOZ_ASSERT(it.isExitFrame());
         ++it;
         MOZ_ASSERT(it.isIonJS());
         outerScript_ = it.script();
+        MOZ_ASSERT(!it.ionScript()->invalidated());
     }
     return outerScript_;
 }
 
 //
 // BinaryArith_Fallback
 //
 
@@ -3051,31 +3052,32 @@ DoGetPropFallback(JSContext* cx, void* p
     // end up attaching a stub for the exact same access later.
     bool isTemporarilyUnoptimizable = false;
 
     RootedPropertyName name(cx, script->getName(pc));
 
     // After the Genericstub was added, we should never reach the Fallbackstub again.
     MOZ_ASSERT(!stub->hasStub(ICStub::GetProp_Generic));
 
-    if (stub->numOptimizedStubs() >= ICGetProp_Fallback::MAX_OPTIMIZED_STUBS) {
+    if (stub->numOptimizedStubs() >= ICGetProp_Fallback::MAX_OPTIMIZED_STUBS && !stub.invalid()) {
         // Discard all stubs in this IC and replace with generic getprop stub.
         for (ICStubIterator iter = stub->beginChain(); !iter.atEnd(); iter++)
             iter.unlink(cx);
         ICGetProp_Generic::Compiler compiler(cx, engine,
                                              stub->fallbackMonitorStub()->firstMonitorStub());
         ICStub* newStub = compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));
         if (!newStub)
             return false;
         stub->addNewStub(newStub);
         attached = true;
     }
 
-    if (!attached && !TryAttachNativeGetAccessorPropStub(cx, &info, stub, name, val, res, &attached,
-                                                         &isTemporarilyUnoptimizable))
+    if (!attached && !stub.invalid() &&
+        !TryAttachNativeGetAccessorPropStub(cx, &info, stub, name, val, res, &attached,
+                                            &isTemporarilyUnoptimizable))
     {
         return false;
     }
 
 
     if (!ComputeGetPropResult(cx, info.maybeFrame(), op, name, val, res))
         return false;
 
@@ -4165,16 +4167,17 @@ ICGetProp_Generic::Clone(JSContext* cx, 
 }
 
 static bool
 DoGetPropGeneric(JSContext* cx, void* payload, ICGetProp_Generic* stub,
                  MutableHandleValue val, MutableHandleValue res)
 {
     ICFallbackStub* fallback = stub->getChainFallback();
     SharedStubInfo info(cx, payload, fallback->icEntry());
+    MOZ_ASSERT(info.outerScript(cx));
     HandleScript script = info.innerScript();
     jsbytecode* pc = info.pc();
     JSOp op = JSOp(*pc);
     RootedPropertyName name(cx, script->getName(pc));
     return ComputeGetPropResult(cx, info.maybeFrame(), op, name, val, res);
 }
 
 typedef bool (*DoGetPropGenericFn)(JSContext*, void*, ICGetProp_Generic*, MutableHandleValue, MutableHandleValue);
@@ -4772,17 +4775,17 @@ DoTypeMonitorFallback(JSContext* cx, voi
         TypeScript::SetArgument(cx, script, argument, value);
     } else {
         if (value.isMagic(JS_UNINITIALIZED_LEXICAL))
             TypeScript::Monitor(cx, script, pc, TypeSet::UnknownType());
         else
             TypeScript::Monitor(cx, script, pc, value);
     }
 
-    if (!stub->addMonitorStubForValue(cx, &info, value))
+    if (!stub->invalid() && !stub->addMonitorStubForValue(cx, &info, value))
         return false;
 
     // Copy input value to res.
     res.set(value);
     return true;
 }
 
 typedef bool (*DoTypeMonitorFallbackFn)(JSContext*, void*, ICTypeMonitor_Fallback*,
--- a/js/src/jit/SharedIC.h
+++ b/js/src/jit/SharedIC.h
@@ -754,63 +754,75 @@ class ICFallbackStub : public ICStub
   protected:
     // Fallback stubs need these fields to easily add new stubs to
     // the linked list of stubs for an IC.
 
     // The IC entry for this linked list of stubs.
     ICEntry* icEntry_;
 
     // The number of stubs kept in the IC entry.
-    uint32_t numOptimizedStubs_;
+    uint32_t numOptimizedStubs_ : 31;
+    uint32_t invalid_ : 1;
 
     // A pointer to the location stub pointer that needs to be
     // changed to add a new "last" stub immediately before the fallback
     // stub.  This'll start out pointing to the icEntry's "firstStub_"
     // field, and as new stubs are added, it'll point to the current
     // last stub's "next_" field.
     ICStub** lastStubPtrAddr_;
 
     ICFallbackStub(Kind kind, JitCode* stubCode)
       : ICStub(kind, ICStub::Fallback, stubCode),
         icEntry_(nullptr),
         numOptimizedStubs_(0),
+        invalid_(false),
         lastStubPtrAddr_(nullptr) {}
 
     ICFallbackStub(Kind kind, Trait trait, JitCode* stubCode)
       : ICStub(kind, trait, stubCode),
         icEntry_(nullptr),
         numOptimizedStubs_(0),
+        invalid_(false),
         lastStubPtrAddr_(nullptr)
     {
         MOZ_ASSERT(trait == ICStub::Fallback ||
                    trait == ICStub::MonitoredFallback);
     }
 
   public:
     inline ICEntry* icEntry() const {
         return icEntry_;
     }
 
     inline size_t numOptimizedStubs() const {
         return (size_t) numOptimizedStubs_;
     }
 
+    void setInvalid() {
+        invalid_ = 1;
+    }
+
+    bool invalid() const {
+        return invalid_;
+    }
+
     // The icEntry and lastStubPtrAddr_ fields can't be initialized when the stub is
     // created since the stub is created at compile time, and we won't know the IC entry
     // address until after compile when the JitScript is created.  This method
     // allows these fields to be fixed up at that point.
     void fixupICEntry(ICEntry* icEntry) {
         MOZ_ASSERT(icEntry_ == nullptr);
         MOZ_ASSERT(lastStubPtrAddr_ == nullptr);
         icEntry_ = icEntry;
         lastStubPtrAddr_ = icEntry_->addressOfFirstStub();
     }
 
     // Add a new stub to the IC chain terminated by this fallback stub.
     void addNewStub(ICStub* stub) {
+        MOZ_ASSERT(!invalid());
         MOZ_ASSERT(*lastStubPtrAddr_ == this);
         MOZ_ASSERT(stub->next() == nullptr);
         stub->setNext(this);
         *lastStubPtrAddr_ = stub;
         lastStubPtrAddr_ = stub->addressOfNext();
         numOptimizedStubs_++;
     }
 
@@ -1267,17 +1279,19 @@ class ICTypeMonitor_Fallback : public IC
     ICStub* firstMonitorStub_;
 
     // Address of the last monitor stub's field pointing to this
     // fallback monitor stub.  This will get updated when new
     // monitor stubs are created and added.
     ICStub** lastMonitorStubPtrAddr_;
 
     // Count of optimized type monitor stubs in this chain.
-    uint32_t numOptimizedMonitorStubs_ : 8;
+    uint32_t numOptimizedMonitorStubs_ : 7;
+
+    uint32_t invalid_ : 1;
 
     // Whether this has a fallback stub referring to the IC entry.
     bool hasFallbackStub_ : 1;
 
     // Index of 'this' or argument which is being monitored, or BYTECODE_INDEX
     // if this is monitoring the types of values pushed at some bytecode.
     uint32_t argumentIndex_ : 23;
 
@@ -1285,25 +1299,27 @@ class ICTypeMonitor_Fallback : public IC
 
     ICTypeMonitor_Fallback(JitCode* stubCode, ICMonitoredFallbackStub* mainFallbackStub,
                            uint32_t argumentIndex)
       : ICStub(ICStub::TypeMonitor_Fallback, stubCode),
         mainFallbackStub_(mainFallbackStub),
         firstMonitorStub_(thisFromCtor()),
         lastMonitorStubPtrAddr_(nullptr),
         numOptimizedMonitorStubs_(0),
+        invalid_(false),
         hasFallbackStub_(mainFallbackStub != nullptr),
         argumentIndex_(argumentIndex)
     { }
 
     ICTypeMonitor_Fallback* thisFromCtor() {
         return this;
     }
 
     void addOptimizedMonitorStub(ICStub* stub) {
+        MOZ_ASSERT(!invalid());
         stub->setNext(this);
 
         MOZ_ASSERT((lastMonitorStubPtrAddr_ != nullptr) ==
                    (numOptimizedMonitorStubs_ || !hasFallbackStub_));
 
         if (lastMonitorStubPtrAddr_)
             *lastMonitorStubPtrAddr_ = stub;
 
@@ -1347,16 +1363,24 @@ class ICTypeMonitor_Fallback : public IC
     static inline size_t offsetOfFirstMonitorStub() {
         return offsetof(ICTypeMonitor_Fallback, firstMonitorStub_);
     }
 
     inline uint32_t numOptimizedMonitorStubs() const {
         return numOptimizedMonitorStubs_;
     }
 
+    void setInvalid() {
+        invalid_ = 1;
+    }
+
+    bool invalid() const {
+        return invalid_;
+    }
+
     inline bool monitorsThis() const {
         return argumentIndex_ == 0;
     }
 
     inline bool monitorsArgument(uint32_t* pargument) const {
         if (argumentIndex_ > 0 && argumentIndex_ < BYTECODE_INDEX) {
             *pargument = argumentIndex_ - 1;
             return true;