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 # 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_; }