Bug 976536 - Don't relazify inlined functions. r=jandem, a=sledru
authorTill Schneidereit <till@tillschneidereit.net>
Thu, 27 Mar 2014 23:50:46 -0400
changeset 183669 ee6aea5824b7
parent 183668 c8bcfc32f855
child 183670 7ccc27d5c8f4
push id3441
push userryanvm@gmail.com
push date2014-04-08 16:59 +0000
treeherdermozilla-beta@30c45853f8cb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem, sledru
bugs976536
milestone29.0
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
@@ -4031,16 +4031,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
@@ -529,16 +529,17 @@ JSFunction::trace(JSTracer *trc)
         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
             // - their 'arguments' object can't escape
             // - 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
@@ -741,16 +741,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;
@@ -923,20 +926,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;
@@ -1142,17 +1147,17 @@ class JSScript : public js::gc::Barriere
     }
     static size_t offsetOfBaselineOrIonSkipArgCheck() {
         return offsetof(JSScript, baselineOrIonSkipArgCheck);
     }
 
     bool isRelazifiable() const {
         return (selfHosted() || lazyScript) &&
                !(analyzedArgsUsage() && needsArgsObj()) &&
-               !isGenerator() && !hasBaselineScript() && !hasAnyIonScript();
+               !isGenerator() && !hasBaselineScript() && !hasAnyIonScript() && !hasBeenInlined();
     }
     void setLazyScript(js::LazyScript *lazy) {
         lazyScript = lazy;
     }
     js::LazyScript *maybeLazyScript() {
         return lazyScript;
     }