Bug 976536 - Don't relazify inlined functions. r=jandem, a=sledru
authorTill Schneidereit <till@tillschneidereit.net>
Sat, 05 Apr 2014 05:01:10 +0200
changeset 192626 2b4260425a87f4f4a11337a2b2f8d961a55e54f4
parent 192625 24669347a557654c7054f8a4d0df522570f4e52d
child 192627 61944f992c2397df552bdbf142d30840fcd7cb37
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem, sledru
bugs976536
milestone30.0a2
Bug 976536 - Don't relazify inlined functions. r=jandem, a=sledru
js/src/jit/IonBuilder.cpp
js/src/jsfun.cpp
js/src/jsscript.h
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -4104,16 +4104,20 @@ IonBuilder::makeInliningDecision(JSFunct
             return DontInline(targetScript, "Vetoed: callee is insufficiently hot.");
         }
     }
 
     // TI calls ObjectStateChange to trigger invalidation of the caller.
     types::TypeObjectKey *targetType = types::TypeObjectKey::get(target);
     targetType->watchStateChangeForInlinedCall(constraints());
 
+    // We mustn't relazify functions that have been inlined, because there's
+    // no way to tell if it safe to do so.
+    script()->setHasBeenInlined();
+
     return InliningDecision_Inline;
 }
 
 bool
 IonBuilder::selectInliningTargets(ObjectVector &targets, CallInfo &callInfo, BoolVector &choiceSet,
                                   uint32_t *numInlineable)
 {
     *numInlineable = 0;
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -565,16 +565,17 @@ JSFunction::trace(JSTracer *trc)
         // for self-hosted code.
         if (hasScript() && u.i.s.script_) {
             // Functions can be relazified under the following conditions:
             // - their compartment isn't currently executing scripts or being
             //   debugged
             // - they are not in the self-hosting compartment
             // - they aren't generators
             // - they don't have JIT code attached
+            // - they haven't ever been inlined
             // - they don't have child functions
             // - they have information for un-lazifying them again later
             // This information can either be a LazyScript, or the name of a
             // self-hosted function which can be cloned over again. The latter
             // is stored in the first extended slot.
             if (IS_GC_MARKING_TRACER(trc) && !compartment()->hasBeenEntered() &&
                 !compartment()->debugMode() && !compartment()->isSelfHosting &&
                 u.i.s.script_->isRelazifiable() && (!isSelfHostedBuiltin() || isExtended()))
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -834,16 +834,19 @@ class JSScript : public js::gc::Barriere
     bool treatAsRunOnce_:1;
 
     // If treatAsRunOnce, whether script has executed.
     bool hasRunOnce_:1;
 
     // Script has been reused for a clone.
     bool hasBeenCloned_:1;
 
+    // Script has been inlined at least once, and can't be relazified.
+    bool hasBeenInlined_:1;
+
     // Script came from eval(), and is still active.
     bool isActiveEval_:1;
 
     // Script came from eval(), and is in eval cache.
     bool isCachedEval_:1;
 
     // Set for functions defined at the top level within an 'eval' script.
     bool directlyInsideEval_:1;
@@ -1023,20 +1026,22 @@ class JSScript : public js::gc::Barriere
     }
 
     bool hasSingletons() const { return hasSingletons_; }
     bool treatAsRunOnce() const {
         return treatAsRunOnce_;
     }
     bool hasRunOnce() const { return hasRunOnce_; }
     bool hasBeenCloned() const { return hasBeenCloned_; }
+    bool hasBeenInlined() const { return hasBeenInlined_; }
 
     void setTreatAsRunOnce() { treatAsRunOnce_ = true; }
     void setHasRunOnce() { hasRunOnce_ = true; }
     void setHasBeenCloned() { hasBeenCloned_ = true; }
+    void setHasBeenInlined() { hasBeenInlined_ = true; }
 
     bool isActiveEval() const { return isActiveEval_; }
     bool isCachedEval() const { return isCachedEval_; }
     bool directlyInsideEval() const { return directlyInsideEval_; }
 
     void cacheForEval() {
         JS_ASSERT(isActiveEval() && !isCachedEval());
         isActiveEval_ = false;
@@ -1241,17 +1246,17 @@ class JSScript : public js::gc::Barriere
         return offsetof(JSScript, baselineOrIonRaw);
     }
     static size_t offsetOfBaselineOrIonSkipArgCheck() {
         return offsetof(JSScript, baselineOrIonSkipArgCheck);
     }
 
     bool isRelazifiable() const {
         return (selfHosted() || lazyScript) &&
-               !isGenerator() && !hasBaselineScript() && !hasAnyIonScript();
+               !isGenerator() && !hasBaselineScript() && !hasAnyIonScript() && !hasBeenInlined();
     }
     void setLazyScript(js::LazyScript *lazy) {
         lazyScript = lazy;
     }
     js::LazyScript *maybeLazyScript() {
         return lazyScript;
     }