Copied from: https://hg.mozilla.org/releases/mozilla-esr38/rev/f31d643afd41
Security advisory: https://www.mozilla.org/en-US/security/advisories/mfsa2016-01/
Mozilla Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1233925

# HG changeset patch
# User Jan de Mooij <jdemooij@mozilla.com>
# Date 1452110721 -3600
# Node ID f31d643afd4159b5422ae5aebcbbea0a088e018e
# Parent  4444e94a99cb9b00c0351cc8bf5459739cc036a5
Bug 1233925 - Treat functions with rest more like functions with lazy arguments. r=nbp a=ritu

diff --git a/js/src/jit/BacktrackingAllocator.cpp b/js/src/jit/BacktrackingAllocator.cpp
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -201,20 +201,19 @@ BacktrackingAllocator::tryGroupRegisters
     // 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->argumentsAliasesFormals()) {
+        if (graph.mir().entryBlock()->info().mayReadFrameArgsDirectly()) {
             if (*reg0->def()->output() != *reg1->def()->output())
                 return true;
         }
     }
 
     VirtualRegisterGroup* group0 = reg0->group(), *group1 = reg1->group();
 
     if (!group0 && group1)
diff --git a/js/src/jit/CompileInfo.h b/js/src/jit/CompileInfo.h
--- a/js/src/jit/CompileInfo.h
+++ b/js/src/jit/CompileInfo.h
@@ -194,16 +194,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!
@@ -222,17 +223,17 @@ class CompileInfo
         fixedLexicalBegin_ = script->fixedLexicalBegin();
         nstack_ = script->nslots() - script->nfixed();
         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;
@@ -539,16 +540,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_;
@@ -559,15 +564,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 */
diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1002,17 +1002,17 @@ MarkThisAndArguments(JSTracer* trc, JitF
     // formal arguments is taken care of by the frame's safepoint/snapshot,
     // except when the script's lazy arguments object aliases those formals,
     // in which case we mark them as well.
 
     size_t nargs = layout->numActualArgs();
     size_t nformals = 0;
     if (CalleeTokenIsFunction(layout->calleeToken())) {
         JSFunction* fun = CalleeTokenToFunction(layout->calleeToken());
-        nformals = fun->nonLazyScript()->argumentsAliasesFormals() ? 0 : fun->nargs();
+        nformals = fun->nonLazyScript()->mayReadFrameArgsDirectly() ? 0 : fun->nargs();
     }
 
     Value* argv = layout->argv();
 
     // Trace |this|.
     gc::MarkValueRoot(trc, argv, "ion-thisv");
 
     // Trace actual arguments beyond the formals. Note + 1 for thisv.
diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3894,16 +3894,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;
diff --git a/js/src/jsscript.h b/js/src/jsscript.h
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1397,16 +1397,20 @@ class JSScript : public js::gc::TenuredC
     }
     inline void setFunction(JSFunction* fun);
     /*
      * De-lazifies the canonical function. Must be called before entering code
      * that expects the function to be non-lazy.
      */
     inline void ensureNonLazyCanonicalFunction(JSContext* cx);
 
+    // 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_;
     }

