Refactored the interpreter and JIT so they don't dictate closure layout
https://bugs.webkit.org/show_bug.cgi?id=97221

Reviewed by Oliver Hunt.

Source/JavaScriptCore: 

Capture may change the location of an argument for space efficiency. This
patch removes static assumptions about argument location from the interpreter
and JIT.

* bytecode/CodeBlock.h:
(JSC::CodeBlock::argumentIndexAfterCapture):
(JSC::ExecState::argumentAfterCapture): Factored out a helper function
so the compiler could share this logic.

* bytecompiler/NodesCodegen.cpp:
(JSC::BracketAccessorNode::emitBytecode): Don't emit optimized bracket
access on arguments if a parameter has been captured by name. This case is
rare and, where I've seen it in the wild, the optimization mostly failed
anyway due to arguments escape, so I didn't feel like writing and testing
five copies of the code that would handle it in the baseline engines.

The DFG can still synthesize this optimization even if we don't emit the
optimized bytecode for it.

* dfg/DFGArgumentsSimplificationPhase.cpp:
(JSC::DFG::ArgumentsSimplificationPhase::run):
* dfg/DFGAssemblyHelpers.h:
(JSC::DFG::AssemblyHelpers::symbolTableFor):
(AssemblyHelpers): Use the right helper function to account for the fact
that a parameter may have been captured by name and moved.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock): ASSERT that we haven't inlined
a .apply on captured arguments. Once we do start inlining such things,
we'll need to do a little bit of math here to get them right.

* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile): Added support for bracket access on
an arguments object where arguments have also been captured by name. We
load the true index of the argument from a side vector. Arguments elision
is very powerful in the DFG, so I wanted to keep it working, even in this
rare case.

* interpreter/Interpreter.cpp:
(JSC::loadVarargs): Use the right helper function to account for the fact
that a parameter may have been captured by name and moved.

* jit/JITCall.cpp:
(JSC::JIT::compileLoadVarargs):
* jit/JITCall32_64.cpp:
(JSC::JIT::compileLoadVarargs): Don't use the inline copy loop if some
of our arguments have moved, since it would copy stale values. (We still
optimize the actual call, and elide the arguments object.)

LayoutTests: 

* fast/js/dfg-arguments-alias-activation-expected.txt: Added.
* fast/js/dfg-arguments-alias-activation.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@129156 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index ca7100e..bc9bbec 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,61 @@
+2012-09-20  Geoffrey Garen  <ggaren@apple.com>
+
+        Refactored the interpreter and JIT so they don't dictate closure layout
+        https://bugs.webkit.org/show_bug.cgi?id=97221
+
+        Reviewed by Oliver Hunt.
+
+        Capture may change the location of an argument for space efficiency. This
+        patch removes static assumptions about argument location from the interpreter
+        and JIT.
+
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::argumentIndexAfterCapture):
+        (JSC::ExecState::argumentAfterCapture): Factored out a helper function
+        so the compiler could share this logic.
+
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::BracketAccessorNode::emitBytecode): Don't emit optimized bracket
+        access on arguments if a parameter has been captured by name. This case is
+        rare and, where I've seen it in the wild, the optimization mostly failed
+        anyway due to arguments escape, so I didn't feel like writing and testing
+        five copies of the code that would handle it in the baseline engines.
+
+        The DFG can still synthesize this optimization even if we don't emit the
+        optimized bytecode for it.
+
+        * dfg/DFGArgumentsSimplificationPhase.cpp:
+        (JSC::DFG::ArgumentsSimplificationPhase::run):
+        * dfg/DFGAssemblyHelpers.h:
+        (JSC::DFG::AssemblyHelpers::symbolTableFor):
+        (AssemblyHelpers): Use the right helper function to account for the fact
+        that a parameter may have been captured by name and moved.
+
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock): ASSERT that we haven't inlined
+        a .apply on captured arguments. Once we do start inlining such things,
+        we'll need to do a little bit of math here to get them right.
+
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile): Added support for bracket access on
+        an arguments object where arguments have also been captured by name. We
+        load the true index of the argument from a side vector. Arguments elision
+        is very powerful in the DFG, so I wanted to keep it working, even in this
+        rare case.
+
+        * interpreter/Interpreter.cpp:
+        (JSC::loadVarargs): Use the right helper function to account for the fact
+        that a parameter may have been captured by name and moved.
+
+        * jit/JITCall.cpp:
+        (JSC::JIT::compileLoadVarargs):
+        * jit/JITCall32_64.cpp:
+        (JSC::JIT::compileLoadVarargs): Don't use the inline copy loop if some
+        of our arguments have moved, since it would copy stale values. (We still
+        optimize the actual call, and elide the arguments object.)
+
 2012-09-20  Gabor Rapcsanyi  <rgabor@webkit.org>
 
         [Qt] r129045 broke the ARM build
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index d0c969c..40a5b46 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -432,6 +432,8 @@
 
         unsigned instructionCount() { return m_instructions.size(); }
 
+        int argumentIndexAfterCapture(size_t argument);
+
 #if ENABLE(JIT)
         void setJITCode(const JITCode& code, MacroAssemblerCodePtr codeWithArityCheck)
         {
@@ -1520,6 +1522,18 @@
         return baselineCodeBlock;
     }
     
+    inline int CodeBlock::argumentIndexAfterCapture(size_t argument)
+    {
+        if (argument >= static_cast<size_t>(symbolTable()->parameterCount()))
+            return CallFrame::argumentOffset(argument);
+
+        const SlowArgument* slowArguments = symbolTable()->slowArguments();
+        if (!slowArguments || slowArguments[argument].status == SlowArgument::Normal)
+            return CallFrame::argumentOffset(argument);
+
+        ASSERT(slowArguments[argument].status == SlowArgument::Captured);
+        return slowArguments[argument].indexIfCaptured;
+    }
 
     inline Register& ExecState::r(int index)
     {
@@ -1552,15 +1566,7 @@
         if (!codeBlock())
             return this[argumentOffset(argument)].jsValue();
 
-        if (argument >= static_cast<size_t>(codeBlock()->symbolTable()->parameterCount()))
-            return this[argumentOffset(argument)].jsValue();
-
-        const SlowArgument* slowArguments = codeBlock()->symbolTable()->slowArguments();
-        if (!slowArguments || slowArguments[argument].status == SlowArgument::Normal)
-            return this[argumentOffset(argument)].jsValue();
-
-        ASSERT(slowArguments[argument].status == SlowArgument::Captured);
-        return this[slowArguments[argument].indexIfCaptured].jsValue();
+        return this[codeBlock()->argumentIndexAfterCapture(argument)].jsValue();
     }
 
 #if ENABLE(DFG_JIT)
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index e4d3547..afa2151 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -320,7 +320,9 @@
 
 RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    if (m_base->isResolveNode() && generator.willResolveToArguments(static_cast<ResolveNode*>(m_base)->identifier())) {
+    if (m_base->isResolveNode() 
+        && generator.willResolveToArguments(static_cast<ResolveNode*>(m_base)->identifier())
+        && !generator.symbolTable().slowArguments()) {
         RegisterID* property = generator.emitNode(m_subscript);
         generator.emitExpressionInfo(divot(), startOffset(), endOffset());    
         return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property);
diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
index ba66739..5133574 100644
--- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
@@ -584,8 +584,8 @@
                     node.convertToGetLocalUnlinked(
                         static_cast<VirtualRegister>(
                             node.codeOrigin.inlineCallFrame->stackOffset +
-                            argumentToOperand(index + 1)));
-                    
+                            m_graph.baselineCodeBlockFor(node.codeOrigin)->argumentIndexAfterCapture(index)));
+
                     NodeIndex checkNodeIndex = m_graph.size();
                     m_graph.append(check);
                     insertionSet.append(indexInBlock, checkNodeIndex);
diff --git a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
index 57f758c..a2003c5 100644
--- a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
+++ b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
@@ -343,6 +343,25 @@
         return argumentsRegisterFor(codeOrigin.inlineCallFrame);
     }
     
+    SharedSymbolTable* symbolTableFor(const CodeOrigin& codeOrigin)
+    {
+        return baselineCodeBlockFor(codeOrigin)->symbolTable();
+    }
+
+    int offsetOfLocals(const CodeOrigin& codeOrigin)
+    {
+        if (!codeOrigin.inlineCallFrame)
+            return 0;
+        return codeOrigin.inlineCallFrame->stackOffset * sizeof(Register);
+    }
+
+    int offsetOfArgumentsIncludingThis(const CodeOrigin& codeOrigin)
+    {
+        if (!codeOrigin.inlineCallFrame)
+            return CallFrame::argumentOffsetIncludingThis(0) * sizeof(Register);
+        return (codeOrigin.inlineCallFrame->stackOffset + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register);
+    }
+
     Vector<BytecodeAndMachineOffset>& decodedCodeMapFor(CodeBlock*);
     
     static const double twoToThe32;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index fb897ff..1f7da2a 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -2714,6 +2714,7 @@
         case op_call_varargs: {
             ASSERT(m_inlineStackTop->m_inlineCallFrame);
             ASSERT(currentInstruction[3].u.operand == m_inlineStackTop->m_codeBlock->argumentsRegister());
+            ASSERT(!m_inlineStackTop->m_codeBlock->symbolTable()->slowArguments());
             // It would be cool to funnel this into handleCall() so that it can handle
             // inlining. But currently that won't be profitable anyway, since none of the
             // uses of call_varargs will be inlineable. So we set this up manually and
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 2294135..362dcf2 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -4202,23 +4202,50 @@
                     JITCompiler::payloadFor(RegisterFile::ArgumentCount)));
         }
         
+        JITCompiler::JumpList slowArgument;
+        JITCompiler::JumpList slowArgumentOutOfBounds;
+        if (const SlowArgument* slowArguments = m_jit.symbolTableFor(node.codeOrigin)->slowArguments()) {
+            slowArgumentOutOfBounds.append(
+                m_jit.branch32(
+                    JITCompiler::AboveOrEqual, indexGPR,
+                    Imm32(m_jit.symbolTableFor(node.codeOrigin)->parameterCount())));
+
+            COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes);
+            m_jit.move(ImmPtr(slowArguments), resultPayloadGPR);
+            m_jit.load32(
+                JITCompiler::BaseIndex(
+                    resultPayloadGPR, indexGPR, JITCompiler::TimesEight, 
+                    OBJECT_OFFSETOF(SlowArgument, indexIfCaptured)), 
+                resultPayloadGPR);
+
+            m_jit.load32(
+                JITCompiler::BaseIndex(
+                    GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
+                    m_jit.offsetOfLocals(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
+                resultTagGPR);
+            m_jit.load32(
+                JITCompiler::BaseIndex(
+                    GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
+                    m_jit.offsetOfLocals(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
+                resultPayloadGPR);
+            slowArgument.append(m_jit.jump());
+        }
+        slowArgumentOutOfBounds.link(&m_jit);
+
         m_jit.neg32(resultPayloadGPR);
         
-        size_t baseOffset =
-            ((node.codeOrigin.inlineCallFrame
-              ? node.codeOrigin.inlineCallFrame->stackOffset
-              : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register);
         m_jit.load32(
             JITCompiler::BaseIndex(
                 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
-                baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
+                m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
             resultTagGPR);
         m_jit.load32(
             JITCompiler::BaseIndex(
                 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
-                baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
+                m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
             resultPayloadGPR);
             
+        slowArgument.link(&m_jit);
         jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
         break;
     }
@@ -4252,21 +4279,46 @@
                     JITCompiler::payloadFor(RegisterFile::ArgumentCount)));
         }
         
+        JITCompiler::JumpList slowArgument;
+        JITCompiler::JumpList slowArgumentOutOfBounds;
+        if (const SlowArgument* slowArguments = m_jit.symbolTableFor(node.codeOrigin)->slowArguments()) {
+            slowArgumentOutOfBounds.append(
+                m_jit.branch32(
+                    JITCompiler::AboveOrEqual, indexGPR,
+                    Imm32(m_jit.symbolTableFor(node.codeOrigin)->parameterCount())));
+
+            COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes);
+            m_jit.move(ImmPtr(slowArguments), resultPayloadGPR);
+            m_jit.load32(
+                JITCompiler::BaseIndex(
+                    resultPayloadGPR, indexGPR, JITCompiler::TimesEight, 
+                    OBJECT_OFFSETOF(SlowArgument, indexIfCaptured)), 
+                resultPayloadGPR);
+            m_jit.load32(
+                JITCompiler::BaseIndex(
+                    GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
+                    m_jit.offsetOfLocals(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
+                resultTagGPR);
+            m_jit.load32(
+                JITCompiler::BaseIndex(
+                    GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
+                    m_jit.offsetOfLocals(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
+                resultPayloadGPR);
+            slowArgument.append(m_jit.jump());
+        }
+        slowArgumentOutOfBounds.link(&m_jit);
+
         m_jit.neg32(resultPayloadGPR);
         
-        size_t baseOffset =
-            ((node.codeOrigin.inlineCallFrame
-              ? node.codeOrigin.inlineCallFrame->stackOffset
-              : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register);
         m_jit.load32(
             JITCompiler::BaseIndex(
                 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
-                baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
+                m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
             resultTagGPR);
         m_jit.load32(
             JITCompiler::BaseIndex(
                 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
-                baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
+                m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
             resultPayloadGPR);
         
         if (node.codeOrigin.inlineCallFrame) {
@@ -4284,6 +4336,7 @@
                     m_jit.argumentsRegisterFor(node.codeOrigin), indexGPR));
         }
         
+        slowArgument.link(&m_jit);
         jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
         break;
     }
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 87be658..f97d781 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -4122,7 +4122,7 @@
         GPRTemporary result(this);
         GPRReg indexGPR = index.gpr();
         GPRReg resultGPR = result.gpr();
-        
+
         if (!isEmptySpeculation(
                 m_state.variables().operand(
                     m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
@@ -4150,18 +4150,40 @@
                     resultGPR,
                     JITCompiler::payloadFor(RegisterFile::ArgumentCount)));
         }
-            
+
+        JITCompiler::JumpList slowArgument;
+        JITCompiler::JumpList slowArgumentOutOfBounds;
+        if (const SlowArgument* slowArguments = m_jit.symbolTableFor(node.codeOrigin)->slowArguments()) {
+            slowArgumentOutOfBounds.append(
+                m_jit.branch32(
+                    JITCompiler::AboveOrEqual, indexGPR,
+                    Imm32(m_jit.symbolTableFor(node.codeOrigin)->parameterCount())));
+
+            COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes);
+            m_jit.move(ImmPtr(slowArguments), resultGPR);
+            m_jit.load32(
+                JITCompiler::BaseIndex(
+                    resultGPR, indexGPR, JITCompiler::TimesEight, 
+                    OBJECT_OFFSETOF(SlowArgument, indexIfCaptured)), 
+                resultGPR);
+            m_jit.signExtend32ToPtr(resultGPR, resultGPR);
+            m_jit.loadPtr(
+                JITCompiler::BaseIndex(
+                    GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfLocals(node.codeOrigin)),
+                resultGPR);
+            slowArgument.append(m_jit.jump());
+        }
+        slowArgumentOutOfBounds.link(&m_jit);
+
         m_jit.neg32(resultGPR);
         m_jit.signExtend32ToPtr(resultGPR, resultGPR);
             
         m_jit.loadPtr(
             JITCompiler::BaseIndex(
-                GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight,
-                ((node.codeOrigin.inlineCallFrame
-                  ? node.codeOrigin.inlineCallFrame->stackOffset
-                  : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register)),
+                GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin)),
             resultGPR);
 
+        slowArgument.link(&m_jit);
         jsValueResult(resultGPR, m_compileIndex);
         break;
     }
@@ -4194,15 +4216,36 @@
                     JITCompiler::payloadFor(RegisterFile::ArgumentCount)));
         }
         
+        JITCompiler::JumpList slowArgument;
+        JITCompiler::JumpList slowArgumentOutOfBounds;
+        if (const SlowArgument* slowArguments = m_jit.symbolTableFor(node.codeOrigin)->slowArguments()) {
+            slowArgumentOutOfBounds.append(
+                m_jit.branch32(
+                    JITCompiler::AboveOrEqual, indexGPR,
+                    Imm32(m_jit.symbolTableFor(node.codeOrigin)->parameterCount())));
+
+            COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes);
+            m_jit.move(ImmPtr(slowArguments), resultGPR);
+            m_jit.load32(
+                JITCompiler::BaseIndex(
+                    resultGPR, indexGPR, JITCompiler::TimesEight, 
+                    OBJECT_OFFSETOF(SlowArgument, indexIfCaptured)), 
+                resultGPR);
+            m_jit.signExtend32ToPtr(resultGPR, resultGPR);
+            m_jit.loadPtr(
+                JITCompiler::BaseIndex(
+                    GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfLocals(node.codeOrigin)),
+                resultGPR);
+            slowArgument.append(m_jit.jump());
+        }
+        slowArgumentOutOfBounds.link(&m_jit);
+
         m_jit.neg32(resultGPR);
         m_jit.signExtend32ToPtr(resultGPR, resultGPR);
         
         m_jit.loadPtr(
             JITCompiler::BaseIndex(
-                GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight,
-                ((node.codeOrigin.inlineCallFrame
-                  ? node.codeOrigin.inlineCallFrame->stackOffset
-                  : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register)),
+                GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin)),
             resultGPR);
         
         if (node.codeOrigin.inlineCallFrame) {
@@ -4220,6 +4263,7 @@
                     indexGPR));
         }
         
+        slowArgument.link(&m_jit);
         jsValueResult(resultGPR, m_compileIndex);
         break;
     }
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp
index ef6cbd5..799ce79 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp
@@ -202,7 +202,7 @@
         newCallFrame->setArgumentCountIncludingThis(argumentCountIncludingThis);
         newCallFrame->setThisValue(thisValue);
         for (size_t i = 0; i < callFrame->argumentCount(); ++i)
-            newCallFrame->setArgument(i, callFrame->argument(i));
+            newCallFrame->setArgument(i, callFrame->argumentAfterCapture(i));
         return newCallFrame;
     }
 
diff --git a/Source/JavaScriptCore/jit/JITCall.cpp b/Source/JavaScriptCore/jit/JITCall.cpp
index f6ea71e..b5f4f82 100644
--- a/Source/JavaScriptCore/jit/JITCall.cpp
+++ b/Source/JavaScriptCore/jit/JITCall.cpp
@@ -66,7 +66,11 @@
 
     JumpList slowCase;
     JumpList end;
-    if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) {
+    bool canOptimize = m_codeBlock->usesArguments()
+        && arguments == m_codeBlock->argumentsRegister()
+        && !m_codeBlock->symbolTable()->slowArguments();
+
+    if (canOptimize) {
         emitGetVirtualRegister(arguments, regT0);
         slowCase.append(branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue()))));
 
@@ -103,7 +107,7 @@
         end.append(jump());
     }
 
-    if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister())
+    if (canOptimize)
         slowCase.link(this);
 
     JITStubCall stubCall(this, cti_op_load_varargs);
@@ -112,7 +116,7 @@
     stubCall.addArgument(Imm32(firstFreeRegister));
     stubCall.call(regT1);
 
-    if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister())
+    if (canOptimize)
         end.link(this);
 }
 
diff --git a/Source/JavaScriptCore/jit/JITCall32_64.cpp b/Source/JavaScriptCore/jit/JITCall32_64.cpp
index 6195d0b..09727d5 100644
--- a/Source/JavaScriptCore/jit/JITCall32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITCall32_64.cpp
@@ -141,7 +141,11 @@
 
     JumpList slowCase;
     JumpList end;
-    if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) {
+    bool canOptimize = m_codeBlock->usesArguments()
+        && arguments == m_codeBlock->argumentsRegister()
+        && !m_codeBlock->symbolTable()->slowArguments();
+
+    if (canOptimize) {
         emitLoadTag(arguments, regT1);
         slowCase.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::EmptyValueTag)));
 
@@ -180,7 +184,7 @@
         end.append(jump());
     }
 
-    if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister())
+    if (canOptimize)
         slowCase.link(this);
 
     JITStubCall stubCall(this, cti_op_load_varargs);
@@ -189,7 +193,7 @@
     stubCall.addArgument(Imm32(firstFreeRegister));
     stubCall.call(regT3);
 
-    if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister())
+    if (canOptimize)
         end.link(this);
 }