Bug 1250964: SharedStubs - Don't add invalid stubs, r=jandem, a=ritu
authorHannes Verschore <hv1989@gmail.com>
Tue, 15 Mar 2016 12:21:18 -0400
changeset 323547 20bc3ca96c291494b9cf128fa8680bc84d9a9d53
parent 323546 dcc8b840bd8fe08b527a48fbfc4815eaa534fc88
child 323548 ba8aa7ee36795c4a58a23e14287fa1cb637c5ed1
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem, ritu
bugs1250964
milestone47.0a2
Bug 1250964: SharedStubs - Don't add invalid stubs, r=jandem, a=ritu
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
@@ -1296,25 +1296,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
@@ -927,16 +927,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
 //
 
@@ -3052,31 +3053,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;
 
@@ -4166,16 +4168,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);
@@ -4773,17 +4776,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;