Title: [129156] trunk
Revision
129156
Author
[email protected]
Date
2012-09-20 12:51:58 -0700 (Thu, 20 Sep 2012)

Log Message

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/_javascript_Core: 

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.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (129155 => 129156)


--- trunk/LayoutTests/ChangeLog	2012-09-20 19:49:33 UTC (rev 129155)
+++ trunk/LayoutTests/ChangeLog	2012-09-20 19:51:58 UTC (rev 129156)
@@ -1,3 +1,13 @@
+2012-09-20  Geoffrey Garen  <[email protected]>
+
+        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.
+
+        * fast/js/dfg-arguments-alias-activation-expected.txt: Added.
+        * fast/js/dfg-arguments-alias-activation.html: Added.
+
 2012-09-20  Tony Chang  <[email protected]>
 
         Implement absolutely positioned flex items

Added: trunk/LayoutTests/fast/js/dfg-arguments-alias-activation-expected.txt (0 => 129156)


--- trunk/LayoutTests/fast/js/dfg-arguments-alias-activation-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/js/dfg-arguments-alias-activation-expected.txt	2012-09-20 19:51:58 UTC (rev 129156)
@@ -0,0 +1,403 @@
+This tests verifies access to captured arguments via an optimized-away arguments object.
+
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: f(1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+PASS: g(0, 1) should be 1 and is.
+

Added: trunk/LayoutTests/fast/js/dfg-arguments-alias-activation.html (0 => 129156)


--- trunk/LayoutTests/fast/js/dfg-arguments-alias-activation.html	                        (rev 0)
+++ trunk/LayoutTests/fast/js/dfg-arguments-alias-activation.html	2012-09-20 19:51:58 UTC (rev 129156)
@@ -0,0 +1,39 @@
+<p>This tests verifies access to captured arguments via an optimized-away arguments object.
+</p>
+<pre id="console"></pre>
+
+<script>
+function log(s)
+{
+	document.getElementById("console").appendChild(document.createTextNode(s + "\r\n"));
+}
+
+function shouldBe(a, aDescription, b)
+{
+	if (a == b) {
+		log("PASS: " + aDescription + " should be " + b + " and is.");
+		return;
+	}
+	log("FAIL: " + aDescription + " should be " + b + " but instead is " + a + ".");
+}
+
+if (window.testRunner) {
+	testRunner.dumpAsText();
+}
+
+// In-bounds of declared and passed arguments.
+function f(x) {
+    return arguments[0] || function() { return x; };
+}
+
+// Out-of-bounds of declared arguments, in-bounds of passed arguments.
+function g(x) {
+    return arguments[1] || function() { return x; };
+}
+
+for (var i = 0; i < 200; ++i)
+    shouldBe(f(1), "f(1)", 1);
+
+for (var i = 0; i < 200; ++i)
+    shouldBe(g(0, 1), "g(0, 1)", 1);
+</script>

Modified: trunk/Source/_javascript_Core/ChangeLog (129155 => 129156)


--- trunk/Source/_javascript_Core/ChangeLog	2012-09-20 19:49:33 UTC (rev 129155)
+++ trunk/Source/_javascript_Core/ChangeLog	2012-09-20 19:51:58 UTC (rev 129156)
@@ -1,3 +1,61 @@
+2012-09-20  Geoffrey Garen  <[email protected]>
+
+        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  <[email protected]>
 
         [Qt] r129045 broke the ARM build

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.h (129155 => 129156)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2012-09-20 19:49:33 UTC (rev 129155)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2012-09-20 19:51:58 UTC (rev 129156)
@@ -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,7 +1522,19 @@
         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)
     {
         CodeBlock* codeBlock = this->codeBlock();
@@ -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)

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (129155 => 129156)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2012-09-20 19:49:33 UTC (rev 129155)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2012-09-20 19:51:58 UTC (rev 129156)
@@ -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);

Modified: trunk/Source/_javascript_Core/dfg/DFGArgumentsSimplificationPhase.cpp (129155 => 129156)


--- trunk/Source/_javascript_Core/dfg/DFGArgumentsSimplificationPhase.cpp	2012-09-20 19:49:33 UTC (rev 129155)
+++ trunk/Source/_javascript_Core/dfg/DFGArgumentsSimplificationPhase.cpp	2012-09-20 19:51:58 UTC (rev 129156)
@@ -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);

Modified: trunk/Source/_javascript_Core/dfg/DFGAssemblyHelpers.h (129155 => 129156)


--- trunk/Source/_javascript_Core/dfg/DFGAssemblyHelpers.h	2012-09-20 19:49:33 UTC (rev 129155)
+++ trunk/Source/_javascript_Core/dfg/DFGAssemblyHelpers.h	2012-09-20 19:51:58 UTC (rev 129156)
@@ -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;

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (129155 => 129156)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2012-09-20 19:49:33 UTC (rev 129155)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2012-09-20 19:51:58 UTC (rev 129156)
@@ -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

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (129155 => 129156)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2012-09-20 19:49:33 UTC (rev 129155)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2012-09-20 19:51:58 UTC (rev 129156)
@@ -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;
     }

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (129155 => 129156)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2012-09-20 19:49:33 UTC (rev 129155)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2012-09-20 19:51:58 UTC (rev 129156)
@@ -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;
     }

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (129155 => 129156)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2012-09-20 19:49:33 UTC (rev 129155)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2012-09-20 19:51:58 UTC (rev 129156)
@@ -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;
     }
 

Modified: trunk/Source/_javascript_Core/jit/JITCall.cpp (129155 => 129156)


--- trunk/Source/_javascript_Core/jit/JITCall.cpp	2012-09-20 19:49:33 UTC (rev 129155)
+++ trunk/Source/_javascript_Core/jit/JITCall.cpp	2012-09-20 19:51:58 UTC (rev 129156)
@@ -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);
 }
 

Modified: trunk/Source/_javascript_Core/jit/JITCall32_64.cpp (129155 => 129156)


--- trunk/Source/_javascript_Core/jit/JITCall32_64.cpp	2012-09-20 19:49:33 UTC (rev 129155)
+++ trunk/Source/_javascript_Core/jit/JITCall32_64.cpp	2012-09-20 19:51:58 UTC (rev 129156)
@@ -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);
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to