Bug 1233925 - Treat functions with rest more like functions with lazy arguments. r=nbp a=ritu
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 06 Jan 2016 21:05:21 +0100
changeset 304220 51f069f6fe91
parent 304219 4791761ef641
child 304221 906fc0cacd8d
push id5475
push userjandemooij@gmail.com
push date2016-01-11 14:01 +0000
treeherdermozilla-beta@51f069f6fe91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp, ritu
bugs1233925
milestone44.0
Bug 1233925 - Treat functions with rest more like functions with lazy arguments. r=nbp a=ritu
js/src/jit/BacktrackingAllocator.cpp
js/src/jit/CompileInfo.h
js/src/jit/JitFrames.cpp
js/src/jsscript.cpp
js/src/jsscript.h
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -887,20 +887,19 @@ BacktrackingAllocator::tryMergeBundles(L
     // constructor calling convention.
     if (IsThisSlotDefinition(reg0.def()) || IsThisSlotDefinition(reg1.def())) {
         if (*reg0.def()->output() != *reg1.def()->output())
             return true;
     }
 
     // Registers which might spill to the frame's argument slots can only be
     // grouped with other such registers if the frame might access those
-    // arguments through a lazy arguments object.
+    // arguments through a lazy arguments object or rest parameter.
     if (IsArgumentSlotDefinition(reg0.def()) || IsArgumentSlotDefinition(reg1.def())) {
-        JSScript* script = graph.mir().entryBlock()->info().script();
-        if (script && script->argumentsHasVarBinding()) {
+        if (graph.mir().entryBlock()->info().mayReadFrameArgsDirectly()) {
             if (*reg0.def()->output() != *reg1.def()->output())
                 return true;
         }
     }
 
     // Limit the number of times we compare ranges if there are many ranges in
     // one of the bundles, to avoid quadratic behavior.
     static const size_t MAX_RANGES = 200;
--- a/js/src/jit/CompileInfo.h
+++ b/js/src/jit/CompileInfo.h
@@ -195,16 +195,17 @@ enum AnalysisMode {
 class CompileInfo
 {
   public:
     CompileInfo(JSScript* script, JSFunction* fun, jsbytecode* osrPc, bool constructing,
                 AnalysisMode analysisMode, bool scriptNeedsArgsObj,
                 InlineScriptTree* inlineScriptTree)
       : script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing),
         analysisMode_(analysisMode), scriptNeedsArgsObj_(scriptNeedsArgsObj),
+        mayReadFrameArgsDirectly_(script->mayReadFrameArgsDirectly()),
         inlineScriptTree_(inlineScriptTree)
     {
         MOZ_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY);
 
         // The function here can flow in from anywhere so look up the canonical
         // function to ensure that we do not try to embed a nursery pointer in
         // jit-code. Precisely because it can flow in from anywhere, it's not
         // guaranteed to be non-lazy. Hence, don't access its script!
@@ -223,17 +224,17 @@ class CompileInfo
         fixedLexicalBegin_ = script->fixedLexicalBegin();
         nstack_ = Max<unsigned>(script->nslots() - script->nfixed(), MinJITStackSize);
         nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_;
     }
 
     explicit CompileInfo(unsigned nlocals)
       : script_(nullptr), fun_(nullptr), osrPc_(nullptr), osrStaticScope_(nullptr),
         constructing_(false), analysisMode_(Analysis_None), scriptNeedsArgsObj_(false),
-        inlineScriptTree_(nullptr)
+        mayReadFrameArgsDirectly_(false), inlineScriptTree_(nullptr)
     {
         nimplicit_ = 0;
         nargs_ = 0;
         nbodyfixed_ = 0;
         nlocals_ = nlocals;
         nstack_ = 1;  /* For FunctionCompiler::pushPhiInput/popPhiOutput */
         nslots_ = nlocals_ + nstack_;
         fixedLexicalBegin_ = nlocals;
@@ -543,16 +544,20 @@ class CompileInfo
             return false;
 
         if (needsArgsObj() && isObservableArgumentSlot(slot))
             return false;
 
         return true;
     }
 
+    bool mayReadFrameArgsDirectly() const {
+        return mayReadFrameArgsDirectly_;
+    }
+
   private:
     unsigned nimplicit_;
     unsigned nargs_;
     unsigned nbodyfixed_;
     unsigned nlocals_;
     unsigned nstack_;
     unsigned nslots_;
     unsigned fixedLexicalBegin_;
@@ -563,15 +568,17 @@ class CompileInfo
     bool constructing_;
     AnalysisMode analysisMode_;
 
     // Whether a script needs an arguments object is unstable over compilation
     // since the arguments optimization could be marked as failed on the main
     // thread, so cache a value here and use it throughout for consistency.
     bool scriptNeedsArgsObj_;
 
+    bool mayReadFrameArgsDirectly_;
+
     InlineScriptTree* inlineScriptTree_;
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_CompileInfo_h */
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1056,17 +1056,17 @@ MarkThisAndArguments(JSTracer* trc, cons
                              : frame.jsFrame();
 
     size_t nargs = layout->numActualArgs();
     size_t nformals = 0;
     size_t newTargetOffset = 0;
     if (CalleeTokenIsFunction(layout->calleeToken())) {
         JSFunction* fun = CalleeTokenToFunction(layout->calleeToken());
         if (!frame.isExitFrameLayout<LazyLinkExitFrameLayout>() &&
-            !fun->nonLazyScript()->argumentsHasVarBinding())
+            !fun->nonLazyScript()->mayReadFrameArgsDirectly())
         {
             nformals = fun->nargs();
         }
         newTargetOffset = Max(nargs, fun->nargs());
     }
 
     Value* argv = layout->argv();
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -4281,16 +4281,22 @@ JSScript::hasLoops()
     JSTryNote* tnlimit = tn + trynotes()->length;
     for (; tn < tnlimit; tn++) {
         if (tn->kind == JSTRY_FOR_IN || tn->kind == JSTRY_LOOP)
             return true;
     }
     return false;
 }
 
+bool
+JSScript::mayReadFrameArgsDirectly()
+{
+    return argumentsHasVarBinding() || (function_ && function_->hasRest());
+}
+
 static inline void
 LazyScriptHash(uint32_t lineno, uint32_t column, uint32_t begin, uint32_t end,
                HashNumber hashes[3])
 {
     HashNumber hash = lineno;
     hash = RotateLeft(hash, 4) ^ column;
     hash = RotateLeft(hash, 4) ^ begin;
     hash = RotateLeft(hash, 4) ^ end;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1595,16 +1595,20 @@ class JSScript : public js::gc::TenuredC
      */
     inline void ensureNonLazyCanonicalFunction(JSContext* cx);
 
     js::ModuleObject* module() const {
         return module_;
     }
     inline void setModule(js::ModuleObject* module);
 
+    // Returns true if the script may read formal arguments on the stack
+    // directly, via lazy arguments or a rest parameter.
+    bool mayReadFrameArgsDirectly();
+
     JSFlatString* sourceData(JSContext* cx);
 
     static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked);
 
     void setSourceObject(JSObject* object);
     JSObject* sourceObject() const {
         return sourceObject_;
     }