Various arguments optimisations in codegen fail to account for arguments being in lexical record
https://bugs.webkit.org/show_bug.cgi?id=137617

Reviewed by Michael Saboff.

Rework the way we track |arguments| references so that we don't try
to use the |arguments| reference on the stack if it's not safe.

To do this without nuking performance it was necessary to update
the parser to track modification of the |arguments| reference
itself.

* bytecode/CodeBlock.cpp:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::willResolveToArguments):
(JSC::BytecodeGenerator::uncheckedLocalArgumentsRegister):
(JSC::BytecodeGenerator::emitCall):
(JSC::BytecodeGenerator::emitConstruct):
(JSC::BytecodeGenerator::emitEnumeration):
(JSC::BytecodeGenerator::uncheckedRegisterForArguments): Deleted.
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::hasSafeLocalArgumentsRegister):
* bytecompiler/NodesCodegen.cpp:
(JSC::BracketAccessorNode::emitBytecode):
(JSC::DotAccessorNode::emitBytecode):
(JSC::getArgumentByVal):
(JSC::CallFunctionCallDotNode::emitBytecode):
(JSC::ApplyFunctionCallDotNode::emitBytecode):
(JSC::ArrayPatternNode::emitDirectBinding):
* interpreter/StackVisitor.cpp:
(JSC::StackVisitor::Frame::existingArguments):
* parser/Nodes.h:
(JSC::ScopeNode::modifiesArguments):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseInner):
* parser/Parser.h:
(JSC::Scope::getCapturedVariables):
* parser/ParserModes.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@174821 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index f569cdb..327b5d8 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -167,6 +167,7 @@
     , m_lexicalEnvironmentRegister(0)
     , m_emptyValueRegister(0)
     , m_globalObjectRegister(0)
+    , m_localArgumentsRegister(0)
     , m_finallyDepth(0)
     , m_localScopeDepth(0)
     , m_codeType(GlobalCode)
@@ -211,6 +212,7 @@
     , m_lexicalEnvironmentRegister(0)
     , m_emptyValueRegister(0)
     , m_globalObjectRegister(0)
+    , m_localArgumentsRegister(0)
     , m_finallyDepth(0)
     , m_localScopeDepth(0)
     , m_codeType(FunctionCode)
@@ -250,6 +252,7 @@
         emitOpcode(op_create_lexical_environment);
         instructions().append(m_lexicalEnvironmentRegister->index());
     }
+    RegisterID* localArgumentsRegister = nullptr;
     RegisterID* scratch = addVar();
     m_symbolTable->setCaptureStart(virtualRegisterForLocal(m_codeBlock->m_numVars).offset());
 
@@ -257,6 +260,8 @@
         RegisterID* unmodifiedArgumentsRegister = addVar(); // Anonymous, so it can't be modified by user code.
         RegisterID* argumentsRegister = addVar(propertyNames().arguments, IsVariable, NotWatchable); // Can be changed by assigning to 'arguments'.
 
+        localArgumentsRegister = argumentsRegister;
+
         // We can save a little space by hard-coding the knowledge that the two
         // 'arguments' values are stored in consecutive registers, and storing
         // only the index of the assignable one.
@@ -274,6 +279,15 @@
                 initializeCapturedVariable(argumentsRegister, propertyNames().arguments, argumentsRegister);
                 RegisterID* uncheckedArgumentsRegister = &registerFor(JSC::unmodifiedArgumentsRegister(m_codeBlock->argumentsRegister()).offset());
                 initializeCapturedVariable(uncheckedArgumentsRegister, propertyNames().arguments, uncheckedArgumentsRegister);
+                if (functionBody->modifiesArguments()) {
+                    emitOpcode(op_mov);
+                    instructions().append(argumentsRegister->index());
+                    instructions().append(addConstantValue(jsUndefined())->index());
+                    emitOpcode(op_mov);
+                    instructions().append(uncheckedArgumentsRegister->index());
+                    instructions().append(addConstantValue(jsUndefined())->index());
+                    localArgumentsRegister = nullptr;
+                }
             }
         }
     }
@@ -386,6 +400,7 @@
     int nextParameterIndex = CallFrame::thisArgumentOffset();
     m_thisRegister.setIndex(nextParameterIndex++);
     m_codeBlock->addParameter();
+
     for (size_t i = 0; i < parameters.size(); ++i, ++nextParameterIndex) {
         int index = nextParameterIndex;
         auto pattern = parameters.at(i);
@@ -419,6 +434,7 @@
         instructions().append(0);
         instructions().append(0);
     }
+    m_localArgumentsRegister = localArgumentsRegister;
 }
 
 BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
@@ -431,6 +447,7 @@
     , m_lexicalEnvironmentRegister(0)
     , m_emptyValueRegister(0)
     , m_globalObjectRegister(0)
+    , m_localArgumentsRegister(0)
     , m_finallyDepth(0)
     , m_localScopeDepth(0)
     , m_codeType(EvalCode)
@@ -545,19 +562,17 @@
     if (entry.isNull())
         return false;
 
-    if (m_codeBlock->usesArguments() && m_codeType == FunctionCode)
+    if (m_codeBlock->usesArguments() && m_codeType == FunctionCode && m_localArgumentsRegister)
         return true;
     
     return false;
 }
 
-RegisterID* BytecodeGenerator::uncheckedRegisterForArguments()
+RegisterID* BytecodeGenerator::uncheckedLocalArgumentsRegister()
 {
     ASSERT(willResolveToArguments(propertyNames().arguments));
-
-    SymbolTableEntry entry = symbolTable().get(propertyNames().arguments.impl());
-    ASSERT(!entry.isNull());
-    return &registerFor(entry.getIndex());
+    ASSERT(m_localArgumentsRegister);
+    return m_localArgumentsRegister;
 }
 
 RegisterID* BytecodeGenerator::createLazyRegisterIfNecessary(RegisterID* reg)
@@ -1828,7 +1843,7 @@
             auto expression = static_cast<SpreadExpressionNode*>(n->m_expr)->expression();
             RefPtr<RegisterID> argumentRegister;
             if (expression->isResolveNode() && willResolveToArguments(static_cast<ResolveNode*>(expression)->identifier()) && !symbolTable().slowArguments())
-                argumentRegister = uncheckedRegisterForArguments();
+                argumentRegister = uncheckedLocalArgumentsRegister();
             else
                 argumentRegister = expression->emitBytecode(*this, callArguments.argumentRegister(0));
             RefPtr<RegisterID> thisRegister = emitMove(newTemporary(), callArguments.thisRegister());
@@ -1970,7 +1985,7 @@
             auto expression = static_cast<SpreadExpressionNode*>(n->m_expr)->expression();
             RefPtr<RegisterID> argumentRegister;
             if (expression->isResolveNode() && willResolveToArguments(static_cast<ResolveNode*>(expression)->identifier()) && !symbolTable().slowArguments())
-                argumentRegister = uncheckedRegisterForArguments();
+                argumentRegister = uncheckedLocalArgumentsRegister();
             else
                 argumentRegister = expression->emitBytecode(*this, callArguments.argumentRegister(0));
             return emitConstructVarargs(dst, func, argumentRegister.get(), newTemporary(), 0, callArguments.profileHookRegister(), divot, divotStart, divotEnd);
@@ -2538,13 +2553,13 @@
         emitJump(loopCondition.get());
         emitLabel(loopStart.get());
         emitLoopHint();
-        emitGetArgumentByVal(value.get(), uncheckedRegisterForArguments(), index.get());
+        emitGetArgumentByVal(value.get(), uncheckedLocalArgumentsRegister(), index.get());
         callBack(*this, value.get());
     
         emitLabel(scope->continueTarget());
         emitInc(index.get());
         emitLabel(loopCondition.get());
-        RefPtr<RegisterID> length = emitGetArgumentsLength(newTemporary(), uncheckedRegisterForArguments());
+        RefPtr<RegisterID> length = emitGetArgumentsLength(newTemporary(), uncheckedLocalArgumentsRegister());
         emitJumpIfTrue(emitEqualityOp(op_less, newTemporary(), index.get(), length.get()), loopStart.get());
         emitLabel(scope->breakTarget());
         return;
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index f7b1481..46d590d 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -277,7 +277,9 @@
         void setIsNumericCompareFunction(bool isNumericCompareFunction);
 
         bool willResolveToArguments(const Identifier&);
-        RegisterID* uncheckedRegisterForArguments();
+
+        bool hasSafeLocalArgumentsRegister() { return m_localArgumentsRegister; }
+        RegisterID* uncheckedLocalArgumentsRegister();
 
         bool isCaptured(int operand);
         CaptureMode captureMode(int operand) { return isCaptured(operand) ? IsCaptured : NotCaptured; }
@@ -752,6 +754,8 @@
         RegisterID* m_lexicalEnvironmentRegister;
         RegisterID* m_emptyValueRegister;
         RegisterID* m_globalObjectRegister;
+        RegisterID* m_localArgumentsRegister;
+
         Vector<Identifier, 16> m_watchableVariables;
         SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
         SegmentedVector<RegisterID, 32> m_calleeRegisters;
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 4b4e5a7..b992bc62 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -386,7 +386,7 @@
         && !generator.symbolTable().slowArguments()) {
         RegisterID* property = generator.emitNode(m_subscript);
         generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-        return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property);
+        return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedLocalArgumentsRegister(), property);
     }
 
     RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator));
@@ -412,7 +412,7 @@
         if (!generator.willResolveToArguments(resolveNode->identifier()))
             goto nonArgumentsPath;
         generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-        return generator.emitGetArgumentsLength(generator.finalDestination(dst), generator.uncheckedRegisterForArguments());
+        return generator.emitGetArgumentsLength(generator.finalDestination(dst), generator.uncheckedLocalArgumentsRegister());
     }
 
 nonArgumentsPath:
@@ -593,7 +593,7 @@
         && generator.willResolveToArguments(static_cast<ResolveNode*>(base)->identifier())
         && !generator.symbolTable().slowArguments()) {
         generator.emitExpressionInfo(divot, divotStart, divotEnd);
-        return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property);
+        return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedLocalArgumentsRegister(), property);
     }
     return nullptr;
 }
@@ -621,7 +621,7 @@
             RefPtr<RegisterID> thisRegister = getArgumentByVal(generator, subject, generator.emitLoad(0, jsNumber(0)), 0, spread->divot(), spread->divotStart(), spread->divotEnd());
             RefPtr<RegisterID> argumentsRegister;
             if (thisRegister)
-                argumentsRegister = generator.uncheckedRegisterForArguments();
+                argumentsRegister = generator.uncheckedLocalArgumentsRegister();
             else {
                 argumentsRegister = generator.emitNode(subject);
                 generator.emitExpressionInfo(spread->divot(), spread->divotStart(), spread->divotEnd());
@@ -749,7 +749,7 @@
         RefPtr<RegisterID> argsRegister;
         ArgumentListNode* args = m_args->m_listNode->m_next;
         if (args->m_expr->isResolveNode() && generator.willResolveToArguments(static_cast<ResolveNode*>(args->m_expr)->identifier()) && !generator.symbolTable().slowArguments())
-            argsRegister = generator.uncheckedRegisterForArguments();
+            argsRegister = generator.uncheckedLocalArgumentsRegister();
         else
             argsRegister = generator.emitNode(args->m_expr);
 
@@ -2721,7 +2721,7 @@
 {
     if (rhs->isResolveNode()
         && generator.willResolveToArguments(static_cast<ResolveNode*>(rhs)->identifier())
-        && !generator.symbolTable().slowArguments()) {
+        && generator.hasSafeLocalArgumentsRegister()&& !generator.symbolTable().slowArguments()) {
         for (size_t i = 0; i < m_targetPatterns.size(); i++) {
             auto target = m_targetPatterns[i];
             if (!target)
@@ -2729,7 +2729,7 @@
             
             RefPtr<RegisterID> temp = generator.newTemporary();
             generator.emitLoad(temp.get(), jsNumber(i));
-            generator.emitGetArgumentByVal(temp.get(), generator.uncheckedRegisterForArguments(), temp.get());
+            generator.emitGetArgumentByVal(temp.get(), generator.uncheckedLocalArgumentsRegister(), temp.get());
             target->bindValue(generator, temp.get());
         }
         if (dst == generator.ignoredResult() || !dst)