<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[42337] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/42337">42337</a></dd>
<dt>Author</dt> <dd>oliver@apple.com</dd>
<dt>Date</dt> <dd>2009-04-08 16:08:28 -0700 (Wed, 08 Apr 2009)</dd>
</dl>

<h3>Log Message</h3>
<pre>Improve function.apply performance

Reviewed by Geoff Garen.

Jump through a few hoops to improve performance of function.apply in the general case.

In the case of zero or one arguments, or if there are only two arguments and the
second is an array literal we treat function.apply as function.call.

Otherwise we use the new opcodes op_load_varargs and op_call_varargs to do the .apply call
without re-entering the virtual machine.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJavaScriptCoreChangeLog">trunk/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkJavaScriptCorebytecodeCodeBlockcpp">trunk/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#trunkJavaScriptCorebytecodeOpcodeh">trunk/JavaScriptCore/bytecode/Opcode.h</a></li>
<li><a href="#trunkJavaScriptCorebytecompilerBytecodeGeneratorcpp">trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp</a></li>
<li><a href="#trunkJavaScriptCorebytecompilerBytecodeGeneratorh">trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.h</a></li>
<li><a href="#trunkJavaScriptCoreinterpreterInterpretercpp">trunk/JavaScriptCore/interpreter/Interpreter.cpp</a></li>
<li><a href="#trunkJavaScriptCorejitJITcpp">trunk/JavaScriptCore/jit/JIT.cpp</a></li>
<li><a href="#trunkJavaScriptCorejitJITh">trunk/JavaScriptCore/jit/JIT.h</a></li>
<li><a href="#trunkJavaScriptCorejitJITCallcpp">trunk/JavaScriptCore/jit/JITCall.cpp</a></li>
<li><a href="#trunkJavaScriptCorejitJITStubscpp">trunk/JavaScriptCore/jit/JITStubs.cpp</a></li>
<li><a href="#trunkJavaScriptCorejitJITStubsh">trunk/JavaScriptCore/jit/JITStubs.h</a></li>
<li><a href="#trunkJavaScriptCoreparserGrammary">trunk/JavaScriptCore/parser/Grammar.y</a></li>
<li><a href="#trunkJavaScriptCoreparserNodescpp">trunk/JavaScriptCore/parser/Nodes.cpp</a></li>
<li><a href="#trunkJavaScriptCoreparserNodesh">trunk/JavaScriptCore/parser/Nodes.h</a></li>
<li><a href="#trunkJavaScriptCoreruntimeArgumentscpp">trunk/JavaScriptCore/runtime/Arguments.cpp</a></li>
<li><a href="#trunkJavaScriptCoreruntimeArgumentsh">trunk/JavaScriptCore/runtime/Arguments.h</a></li>
<li><a href="#trunkJavaScriptCoreruntimeFunctionPrototypecpp">trunk/JavaScriptCore/runtime/FunctionPrototype.cpp</a></li>
<li><a href="#trunkJavaScriptCoreruntimeFunctionPrototypeh">trunk/JavaScriptCore/runtime/FunctionPrototype.h</a></li>
<li><a href="#trunkJavaScriptCoreruntimeJSArraycpp">trunk/JavaScriptCore/runtime/JSArray.cpp</a></li>
<li><a href="#trunkJavaScriptCoreruntimeJSArrayh">trunk/JavaScriptCore/runtime/JSArray.h</a></li>
<li><a href="#trunkJavaScriptCoreruntimeJSGlobalObjectcpp">trunk/JavaScriptCore/runtime/JSGlobalObject.cpp</a></li>
<li><a href="#trunkJavaScriptCoreruntimeJSGlobalObjecth">trunk/JavaScriptCore/runtime/JSGlobalObject.h</a></li>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfastprofilerapplyexpectedtxt">trunk/LayoutTests/fast/profiler/apply-expected.txt</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastjsfunctionapplyaliasedexpectedtxt">trunk/LayoutTests/fast/js/function-apply-aliased-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastjsfunctionapplyaliasedhtml">trunk/LayoutTests/fast/js/function-apply-aliased.html</a></li>
<li><a href="#trunkLayoutTestsfastjsresourcesfunctionapplyaliasedjs">trunk/LayoutTests/fast/js/resources/function-apply-aliased.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/ChangeLog (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/ChangeLog        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/ChangeLog        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -1,3 +1,64 @@
</span><ins>+2009-04-07  Oliver Hunt  &lt;oliver@apple.com&gt;
+
+        Reviewed by Geoff Garen.
+
+        Improve function.apply performance
+
+        Jump through a few hoops to improve performance of function.apply in the general case.
+
+        In the case of zero or one arguments, or if there are only two arguments and the
+        second is an array literal we treat function.apply as function.call.
+
+        Otherwise we use the new opcodes op_load_varargs and op_call_varargs to do the .apply call
+        without re-entering the virtual machine.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+        * bytecode/Opcode.h:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitJumpIfNotFunctionApply):
+        (JSC::BytecodeGenerator::emitLoadVarargs):
+        (JSC::BytecodeGenerator::emitCallVarargs):
+        * bytecompiler/BytecodeGenerator.h:
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::privateExecute):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        (JSC::JIT::privateCompileSlowCases):
+        * jit/JIT.h:
+        * jit/JITCall.cpp:
+        (JSC::JIT::compileOpCallSetupArgs):
+        (JSC::JIT::compileOpCallVarargsSetupArgs):
+        (JSC::JIT::compileOpCallVarargs):
+        (JSC::JIT::compileOpCallVarargsSlowCase):
+        * jit/JITStubs.cpp:
+        (JSC::JITStubs::cti_op_load_varargs):
+        * jit/JITStubs.h:
+        * parser/Grammar.y:
+        * parser/Nodes.cpp:
+        (JSC::ArrayNode::isSimpleArray):
+        (JSC::ArrayNode::toArgumentList):
+        (JSC::CallFunctionCallDotNode::emitBytecode):
+        (JSC::ApplyFunctionCallDotNode::emitBytecode):
+        * parser/Nodes.h:
+        (JSC::ExpressionNode::):
+        (JSC::ApplyFunctionCallDotNode::):
+        * runtime/Arguments.cpp:
+        (JSC::Arguments::copyToRegisters):
+        (JSC::Arguments::fillArgList):
+        * runtime/Arguments.h:
+        (JSC::Arguments::numProvidedArguments):
+        * runtime/FunctionPrototype.cpp:
+        (JSC::FunctionPrototype::addFunctionProperties):
+        * runtime/FunctionPrototype.h:
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::copyToRegisters):
+        * runtime/JSArray.h:
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::reset):
+        (JSC::JSGlobalObject::mark):
+        * runtime/JSGlobalObject.h:
+
</ins><span class="cx"> 2009-04-08  Alexey Proskuryakov  &lt;ap@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Reviewed by Darin Adler.
</span></span></pre></div>
<a id="trunkJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/bytecode/CodeBlock.cpp (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/bytecode/CodeBlock.cpp        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/bytecode/CodeBlock.cpp        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -965,6 +965,18 @@
</span><span class="cx">             printf(&quot;[%4d] call_eval\t %s, %s, %d, %d\n&quot;, location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><ins>+        case op_call_varargs: {
+            int dst = (++it)-&gt;u.operand;
+            int func = (++it)-&gt;u.operand;
+            int argCount = (++it)-&gt;u.operand;
+            int registerOffset = (++it)-&gt;u.operand;
+            printf(&quot;[%4d] call_varargs\t %s, %s, %s, %d\n&quot;, location, registerName(dst).c_str(), registerName(func).c_str(), registerName(argCount).c_str(), registerOffset);
+            break;
+        }
+        case op_load_varargs: {
+            printUnaryOp(location, it, &quot;load_varargs&quot;);
+            break;
+        }
</ins><span class="cx">         case op_tear_off_activation: {
</span><span class="cx">             int r0 = (++it)-&gt;u.operand;
</span><span class="cx">             printf(&quot;[%4d] tear_off_activation\t %s\n&quot;, location, registerName(r0).c_str());
</span></span></pre></div>
<a id="trunkJavaScriptCorebytecodeOpcodeh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/bytecode/Opcode.h (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/bytecode/Opcode.h        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/bytecode/Opcode.h        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -140,6 +140,8 @@
</span><span class="cx">         macro(op_new_func_exp, 3) \
</span><span class="cx">         macro(op_call, 5) \
</span><span class="cx">         macro(op_call_eval, 5) \
</span><ins>+        macro(op_call_varargs, 5) \
+        macro(op_load_varargs, 3) \
</ins><span class="cx">         macro(op_tear_off_activation, 2) \
</span><span class="cx">         macro(op_tear_off_arguments, 1) \
</span><span class="cx">         macro(op_ret, 2) \
</span></span></pre></div>
<a id="trunkJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -705,6 +705,15 @@
</span><span class="cx">     return target;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+PassRefPtr&lt;Label&gt; BytecodeGenerator::emitJumpIfNotFunctionApply(RegisterID* cond, Label* target)
+{
+    emitOpcode(op_jneq_ptr);
+    instructions().append(cond-&gt;index());
+    instructions().append(m_scopeChain-&gt;globalObject()-&gt;d()-&gt;applyFunction);
+    instructions().append(target-&gt;offsetFrom(instructions().size()));
+    return target;
+}
+
</ins><span class="cx"> unsigned BytecodeGenerator::addConstant(FuncDeclNode* n)
</span><span class="cx"> {
</span><span class="cx">     // No need to explicitly unique function body nodes -- they're unique already.
</span><span class="lines">@@ -1337,6 +1346,44 @@
</span><span class="cx">     return dst;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+RegisterID* BytecodeGenerator::emitLoadVarargs(RegisterID* argCountDst, RegisterID* arguments)
+{
+    ASSERT(argCountDst-&gt;index() &lt; arguments-&gt;index());
+    emitOpcode(op_load_varargs);
+    instructions().append(argCountDst-&gt;index());
+    instructions().append(arguments-&gt;index());
+    return argCountDst;
+}
+
+RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* argCountRegister, unsigned divot, unsigned startOffset, unsigned endOffset)
+{
+    ASSERT(func-&gt;refCount());
+    ASSERT(thisRegister-&gt;refCount());
+    ASSERT(dst != func);
+    if (m_shouldEmitProfileHooks) {
+        emitOpcode(op_profile_will_call);
+        instructions().append(func-&gt;index());
+        
+#if ENABLE(JIT)
+        m_codeBlock-&gt;addFunctionRegisterInfo(instructions().size(), func-&gt;index());
+#endif
+    }
+    
+    emitExpressionInfo(divot, startOffset, endOffset);
+    
+    // Emit call.
+    emitOpcode(op_call_varargs);
+    instructions().append(dst-&gt;index()); // dst
+    instructions().append(func-&gt;index()); // func
+    instructions().append(argCountRegister-&gt;index()); // arg count
+    instructions().append(thisRegister-&gt;index() + RegisterFile::CallFrameHeaderSize); // initial registerOffset
+    if (m_shouldEmitProfileHooks) {
+        emitOpcode(op_profile_did_call);
+        instructions().append(func-&gt;index());
+    }
+    return dst;
+}
+
</ins><span class="cx"> RegisterID* BytecodeGenerator::emitReturn(RegisterID* src)
</span><span class="cx"> {
</span><span class="cx">     if (m_codeBlock-&gt;needsFullScopeChain()) {
</span></span></pre></div>
<a id="trunkJavaScriptCorebytecompilerBytecodeGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.h (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -288,6 +288,8 @@
</span><span class="cx"> 
</span><span class="cx">         RegisterID* emitCall(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
</span><span class="cx">         RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
</span><ins>+        RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* argCount, unsigned divot, unsigned startOffset, unsigned endOffset);
+        RegisterID* emitLoadVarargs(RegisterID* argCountDst, RegisterID* args);
</ins><span class="cx"> 
</span><span class="cx">         RegisterID* emitReturn(RegisterID* src);
</span><span class="cx">         RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); }
</span><span class="lines">@@ -299,6 +301,7 @@
</span><span class="cx">         PassRefPtr&lt;Label&gt; emitJumpIfTrue(RegisterID* cond, Label* target);
</span><span class="cx">         PassRefPtr&lt;Label&gt; emitJumpIfFalse(RegisterID* cond, Label* target);
</span><span class="cx">         PassRefPtr&lt;Label&gt; emitJumpIfNotFunctionCall(RegisterID* cond, Label* target);
</span><ins>+        PassRefPtr&lt;Label&gt; emitJumpIfNotFunctionApply(RegisterID* cond, Label* target);
</ins><span class="cx">         PassRefPtr&lt;Label&gt; emitJumpScopes(Label* target, int targetScopeDepth);
</span><span class="cx"> 
</span><span class="cx">         PassRefPtr&lt;Label&gt; emitJumpSubroutine(RegisterID* retAddrDst, Label*);
</span><span class="lines">@@ -365,7 +368,7 @@
</span><span class="cx">         typedef HashMap&lt;RefPtr&lt;UString::Rep&gt;, int, IdentifierRepHash, HashTraits&lt;RefPtr&lt;UString::Rep&gt; &gt;, IdentifierMapIndexHashTraits&gt; IdentifierMap;
</span><span class="cx">         typedef HashMap&lt;double, JSValuePtr&gt; NumberMap;
</span><span class="cx">         typedef HashMap&lt;UString::Rep*, JSString*, IdentifierRepHash&gt; IdentifierStringMap;
</span><del>-
</del><ins>+        
</ins><span class="cx">         RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
</span><span class="cx">         
</span><span class="cx">         RegisterID* newRegister();
</span></span></pre></div>
<a id="trunkJavaScriptCoreinterpreterInterpretercpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/interpreter/Interpreter.cpp (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/interpreter/Interpreter.cpp        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/interpreter/Interpreter.cpp        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -2972,6 +2972,141 @@
</span><span class="cx">         exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame-&gt;codeBlock()-&gt;instructions().begin(), callFrame-&gt;codeBlock());
</span><span class="cx">         goto vm_throw;
</span><span class="cx">     }
</span><ins>+    DEFINE_OPCODE(op_load_varargs) {
+        int argCountDst = (++vPC)-&gt;u.operand;
+        int argsOffset = (++vPC)-&gt;u.operand;
+        
+        JSValuePtr arguments = callFrame[argsOffset].jsValue(callFrame);
+        uint32_t argCount = 0;
+        if (!arguments.isUndefinedOrNull()) {
+            if (!arguments.isObject()) {
+                exceptionValue = createInvalidParamError(callFrame, &quot;Function.prototype.apply&quot;, arguments, vPC - callFrame-&gt;codeBlock()-&gt;instructions().begin(), callFrame-&gt;codeBlock());
+                goto vm_throw;
+            }
+            if (asObject(arguments)-&gt;classInfo() == &amp;Arguments::info) {
+                Arguments* args = asArguments(arguments);
+                argCount = args-&gt;numProvidedArguments(callFrame);
+                int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
+                Register* newEnd = callFrame-&gt;registers() + sizeDelta;
+                if (!registerFile-&gt;grow(newEnd) || ((newEnd - callFrame-&gt;registers()) != sizeDelta)) {
+                    exceptionValue = createStackOverflowError(callFrame);
+                    goto vm_throw;
+                }
+                args-&gt;copyToRegisters(callFrame, callFrame-&gt;registers() + argsOffset, argCount);
+            } else if (isJSArray(&amp;callFrame-&gt;globalData(), arguments)) {
+                JSArray* array = asArray(arguments);
+                argCount = array-&gt;length();
+                int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
+                Register* newEnd = callFrame-&gt;registers() + sizeDelta;
+                if (!registerFile-&gt;grow(newEnd) || ((newEnd - callFrame-&gt;registers()) != sizeDelta)) {
+                    exceptionValue = createStackOverflowError(callFrame);
+                    goto vm_throw;
+                }
+                array-&gt;copyToRegisters(callFrame, callFrame-&gt;registers() + argsOffset, argCount);
+            } else if (asObject(arguments)-&gt;inherits(&amp;JSArray::info)) {
+                JSObject* argObject = asObject(arguments);
+                argCount = argObject-&gt;get(callFrame, callFrame-&gt;propertyNames().length).toUInt32(callFrame);
+                int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
+                Register* newEnd = callFrame-&gt;registers() + sizeDelta;
+                if (!registerFile-&gt;grow(newEnd) || ((newEnd - callFrame-&gt;registers()) != sizeDelta)) {
+                    exceptionValue = createStackOverflowError(callFrame);
+                    goto vm_throw;
+                }
+                Register* argsBuffer = callFrame-&gt;registers() + argsOffset;
+                for (unsigned i = 0; i &lt; argCount; ++i) {
+                    argsBuffer[i] = asObject(arguments)-&gt;get(callFrame, i);
+                    CHECK_FOR_EXCEPTION();
+                }
+            } else {
+                if (!arguments.isObject()) {
+                    exceptionValue = createInvalidParamError(callFrame, &quot;Function.prototype.apply&quot;, arguments, vPC - callFrame-&gt;codeBlock()-&gt;instructions().begin(), callFrame-&gt;codeBlock());
+                    goto vm_throw;
+                }
+            }
+        }
+        CHECK_FOR_EXCEPTION();
+        callFrame[argCountDst] = argCount + 1;
+        ++vPC;
+        NEXT_INSTRUCTION();
+    }
+    DEFINE_OPCODE(op_call_varargs) {
+        /* call_varargs dst(r) func(r) argCountReg(r) baseRegisterOffset(n)
+         
+         Perform a function call with a dynamic set of arguments.
+         
+         registerOffset is the distance the callFrame pointer should move
+         before the VM initializes the new call frame's header, excluding
+         space for arguments.
+         
+         dst is where op_ret should store its result.
+         */
+        
+        int dst = vPC[1].u.operand;
+        int func = vPC[2].u.operand;
+        int argCountReg = vPC[3].u.operand;
+        int registerOffset = vPC[4].u.operand;
+        
+        JSValuePtr v = callFrame[func].jsValue(callFrame);
+        int argCount = callFrame[argCountReg].i();
+        registerOffset += argCount;
+        CallData callData;
+        CallType callType = v.getCallData(callData);
+        
+        if (callType == CallTypeJS) {
+            ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
+            FunctionBodyNode* functionBodyNode = callData.js.functionBody;
+            CodeBlock* newCodeBlock = &amp;functionBodyNode-&gt;bytecode(callDataScopeChain);
+            
+            CallFrame* previousCallFrame = callFrame;
+            
+            callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
+            if (UNLIKELY(!callFrame)) {
+                callFrame = previousCallFrame;
+                exceptionValue = createStackOverflowError(callFrame);
+                goto vm_throw;
+            }
+            
+            callFrame-&gt;init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
+            vPC = newCodeBlock-&gt;instructions().begin();
+            
+#if ENABLE(OPCODE_STATS)
+            OpcodeStats::resetLastInstruction();
+#endif
+            
+            NEXT_INSTRUCTION();
+        }
+        
+        if (callType == CallTypeHost) {
+            ScopeChainNode* scopeChain = callFrame-&gt;scopeChain();
+            CallFrame* newCallFrame = CallFrame::create(callFrame-&gt;registers() + registerOffset);
+            newCallFrame-&gt;init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0);
+            
+            Register* thisRegister = newCallFrame-&gt;registers() - RegisterFile::CallFrameHeaderSize - argCount;
+            ArgList args(thisRegister + 1, argCount - 1);
+            
+            // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
+            JSValuePtr thisValue = thisRegister-&gt;jsValue(callFrame);
+            if (thisValue == jsNull())
+                thisValue = callFrame-&gt;globalThisValue();
+            
+            JSValuePtr returnValue;
+            {
+                SamplingTool::HostCallRecord callRecord(m_sampler);
+                returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
+            }
+            CHECK_FOR_EXCEPTION();
+            
+            callFrame[dst] = JSValuePtr(returnValue);
+            
+            vPC += 5;
+            NEXT_INSTRUCTION();
+        }
+        
+        ASSERT(callType == CallTypeNone);
+        
+        exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame-&gt;codeBlock()-&gt;instructions().begin(), callFrame-&gt;codeBlock());
+        goto vm_throw;
+    }
</ins><span class="cx">     DEFINE_OPCODE(op_tear_off_activation) {
</span><span class="cx">         /* tear_off_activation activation(r)
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkJavaScriptCorejitJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/jit/JIT.cpp (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/jit/JIT.cpp        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/jit/JIT.cpp        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -496,6 +496,16 @@
</span><span class="cx">             compileOpCall(opcodeID, currentInstruction, callLinkInfoIndex++);
</span><span class="cx">             NEXT_OPCODE(op_call_eval);
</span><span class="cx">         }
</span><ins>+        case op_load_varargs: {
+            emitPutJITStubArgConstant(currentInstruction[2].u.operand, 1);
+            emitCTICall(JITStubs::cti_op_load_varargs);
+            emitPutVirtualRegister(currentInstruction[1].u.operand);
+            NEXT_OPCODE(op_load_varargs);
+        }
+        case op_call_varargs: {
+            compileOpCallVarargs(currentInstruction);
+            NEXT_OPCODE(op_call_varargs);
+        }
</ins><span class="cx">         case op_construct: {
</span><span class="cx">             compileOpCall(opcodeID, currentInstruction, callLinkInfoIndex++);
</span><span class="cx">             NEXT_OPCODE(op_construct);
</span><span class="lines">@@ -1596,6 +1606,10 @@
</span><span class="cx">             compileOpCallSlowCase(currentInstruction, iter, callLinkInfoIndex++, opcodeID);
</span><span class="cx">             NEXT_OPCODE(op_call_eval);
</span><span class="cx">         }
</span><ins>+        case op_call_varargs: {
+            compileOpCallVarargsSlowCase(currentInstruction, iter);
+            NEXT_OPCODE(op_call_varargs);
+        }
</ins><span class="cx">         case op_construct: {
</span><span class="cx">             compileOpCallSlowCase(currentInstruction, iter, callLinkInfoIndex++, opcodeID);
</span><span class="cx">             NEXT_OPCODE(op_construct);
</span></span></pre></div>
<a id="trunkJavaScriptCorejitJITh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/jit/JIT.h (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/jit/JIT.h        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/jit/JIT.h        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -412,10 +412,13 @@
</span><span class="cx">         void compilePutByIdHotPath(int baseVReg, Identifier* ident, int valueVReg, unsigned propertyAccessInstructionIndex);
</span><span class="cx">         void compilePutByIdSlowCase(int baseVReg, Identifier* ident, int valueVReg, Vector&lt;SlowCaseEntry&gt;::iterator&amp; iter, unsigned propertyAccessInstructionIndex);
</span><span class="cx">         void compileOpCall(OpcodeID, Instruction* instruction, unsigned callLinkInfoIndex);
</span><ins>+        void compileOpCallVarargs(Instruction* instruction);
</ins><span class="cx">         void compileOpCallInitializeCallFrame();
</span><span class="cx">         void compileOpCallSetupArgs(Instruction*);
</span><ins>+        void compileOpCallVarargsSetupArgs(Instruction*);
</ins><span class="cx">         void compileOpCallEvalSetupArgs(Instruction*);
</span><span class="cx">         void compileOpCallSlowCase(Instruction* instruction, Vector&lt;SlowCaseEntry&gt;::iterator&amp; iter, unsigned callLinkInfoIndex, OpcodeID opcodeID);
</span><ins>+        void compileOpCallVarargsSlowCase(Instruction* instruction, Vector&lt;SlowCaseEntry&gt;::iterator&amp; iter);
</ins><span class="cx">         void compileOpConstructSetupArgs(Instruction*);
</span><span class="cx">         enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq };
</span><span class="cx">         void compileOpStrictEq(Instruction* instruction, CompileOpStrictEqType type);
</span></span></pre></div>
<a id="trunkJavaScriptCorejitJITCallcpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/jit/JITCall.cpp (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/jit/JITCall.cpp        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/jit/JITCall.cpp        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -87,9 +87,20 @@
</span><span class="cx"> 
</span><span class="cx">     // ecx holds func
</span><span class="cx">     emitPutJITStubArg(regT2, 1);
</span><ins>+    emitPutJITStubArgConstant(argCount, 3);
</ins><span class="cx">     emitPutJITStubArgConstant(registerOffset, 2);
</span><del>-    emitPutJITStubArgConstant(argCount, 3);
</del><span class="cx"> }
</span><ins>+          
+void JIT::compileOpCallVarargsSetupArgs(Instruction* instruction)
+{
+    int registerOffset = instruction[4].u.operand;
+    
+    // ecx holds func
+    emitPutJITStubArg(regT2, 1);
+    emitPutJITStubArg(regT1, 3);
+    addPtr(Imm32(registerOffset), regT1, regT0);
+    emitPutJITStubArg(regT0, 2);
+}
</ins><span class="cx"> 
</span><span class="cx"> void JIT::compileOpCallEvalSetupArgs(Instruction* instruction)
</span><span class="cx"> {
</span><span class="lines">@@ -334,6 +345,50 @@
</span><span class="cx"> 
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+void JIT::compileOpCallVarargs(Instruction* instruction)
+{
+    int dst = instruction[1].u.operand;
+    int callee = instruction[2].u.operand;
+    int argCountRegister = instruction[3].u.operand;
+
+    emitGetVirtualRegister(argCountRegister, regT1);
+    emitGetVirtualRegister(callee, regT2);
+    compileOpCallVarargsSetupArgs(instruction);
+
+    // Check for JSFunctions.
+    emitJumpSlowCaseIfNotJSCell(regT2);
+    addSlowCase(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData-&gt;jsFunctionVPtr)));
+    
+    // Speculatively roll the callframe, assuming argCount will match the arity.
+    mul32(Imm32(sizeof(Register)), regT0, regT0);
+    intptr_t offset = (intptr_t)sizeof(Register) * (intptr_t)RegisterFile::CallerFrame;
+    addPtr(Imm32((int32_t)offset), regT0, regT3);
+    addPtr(callFrameRegister, regT3);
+    storePtr(callFrameRegister, regT3);
+    addPtr(regT0, callFrameRegister);
+    emitNakedCall(m_globalData-&gt;jitStubs.ctiVirtualCall());
+
+    // Put the return value in dst. In the interpreter, op_ret does this.
+    emitPutVirtualRegister(dst);
+    
+    sampleCodeBlock(m_codeBlock);
+}
+
+void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector&lt;SlowCaseEntry&gt;::iterator&amp; iter)
+{
+    int dst = instruction[1].u.operand;
+    
+    linkSlowCase(iter);
+    linkSlowCase(iter);
+    
+    // This handles host functions
+    emitCTICall(JITStubs::cti_op_call_NotJSFunction);
+    // Put the return value in dst. In the interpreter, op_ret does this.
+    emitPutVirtualRegister(dst);
+    
+    sampleCodeBlock(m_codeBlock);
+}
+    
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(JIT)
</span></span></pre></div>
<a id="trunkJavaScriptCorejitJITStubscpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/jit/JITStubs.cpp (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/jit/JITStubs.cpp        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/jit/JITStubs.cpp        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -1374,6 +1374,66 @@
</span><span class="cx">     CHECK_FOR_EXCEPTION_AT_END();
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><ins>+    
+int JITStubs::cti_op_load_varargs(STUB_ARGS)
+{
+    BEGIN_STUB_FUNCTION();
+    CallFrame* callFrame = ARG_callFrame;
+    RegisterFile* registerFile = ARG_registerFile;
+    int argsOffset = ARG_int1;
+    JSValuePtr arguments = callFrame[argsOffset].jsValue(callFrame);
+    uint32_t argCount = 0;
+    if (!arguments.isUndefinedOrNull()) {
+        if (!arguments.isObject()) {
+            CodeBlock* codeBlock = callFrame-&gt;codeBlock();
+            unsigned vPCIndex = codeBlock-&gt;getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
+            ARG_globalData-&gt;exception = createInvalidParamError(callFrame, &quot;Function.prototype.apply&quot;, arguments, vPCIndex, codeBlock);
+            VM_THROW_EXCEPTION();
+        }
+        if (asObject(arguments)-&gt;classInfo() == &amp;Arguments::info) {
+            Arguments* argsObject = asArguments(arguments);
+            argCount = argsObject-&gt;numProvidedArguments(callFrame);
+            int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
+            Register* newEnd = callFrame-&gt;registers() + sizeDelta;
+            if (!registerFile-&gt;grow(newEnd) || ((newEnd - callFrame-&gt;registers()) != sizeDelta)) {
+                ARG_globalData-&gt;exception = createStackOverflowError(callFrame);
+                VM_THROW_EXCEPTION();
+            }
+            argsObject-&gt;copyToRegisters(callFrame, callFrame-&gt;registers() + argsOffset, argCount);
+        } else if (isJSArray(&amp;callFrame-&gt;globalData(), arguments)) {
+            JSArray* array = asArray(arguments);
+            argCount = array-&gt;length();
+            int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
+            Register* newEnd = callFrame-&gt;registers() + sizeDelta;
+            if (!registerFile-&gt;grow(newEnd) || ((newEnd - callFrame-&gt;registers()) != sizeDelta)) {
+                ARG_globalData-&gt;exception = createStackOverflowError(callFrame);
+                VM_THROW_EXCEPTION();
+            }
+            array-&gt;copyToRegisters(callFrame, callFrame-&gt;registers() + argsOffset, argCount);
+        } else if (asObject(arguments)-&gt;inherits(&amp;JSArray::info)) {
+            JSObject* argObject = asObject(arguments);
+            argCount = argObject-&gt;get(callFrame, callFrame-&gt;propertyNames().length).toUInt32(callFrame);
+            int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
+            Register* newEnd = callFrame-&gt;registers() + sizeDelta;
+            if (!registerFile-&gt;grow(newEnd) || ((newEnd - callFrame-&gt;registers()) != sizeDelta)) {
+                ARG_globalData-&gt;exception = createStackOverflowError(callFrame);
+                VM_THROW_EXCEPTION();
+            }
+            Register* argsBuffer = callFrame-&gt;registers() + argsOffset;
+            for (unsigned i = 0; i &lt; argCount; ++i) {
+                argsBuffer[i] = asObject(arguments)-&gt;get(callFrame, i);
+                CHECK_FOR_EXCEPTION();
+            }
+        } else {
+            CodeBlock* codeBlock = callFrame-&gt;codeBlock();
+            unsigned vPCIndex = codeBlock-&gt;getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
+            ARG_globalData-&gt;exception = createInvalidParamError(callFrame, &quot;Function.prototype.apply&quot;, arguments, vPCIndex, codeBlock);
+            VM_THROW_EXCEPTION();
+        }
+    }
+    CHECK_FOR_EXCEPTION_AT_END();
+    return argCount + 1;
+}
</ins><span class="cx"> 
</span><span class="cx"> JSValueEncodedAsPointer* JITStubs::cti_op_negate(STUB_ARGS)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkJavaScriptCorejitJITStubsh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/jit/JITStubs.h (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/jit/JITStubs.h        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/jit/JITStubs.h        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -170,6 +170,7 @@
</span><span class="cx">         static int JIT_STUB cti_op_loop_if_less(STUB_ARGS);
</span><span class="cx">         static int JIT_STUB cti_op_loop_if_lesseq(STUB_ARGS);
</span><span class="cx">         static int JIT_STUB cti_op_loop_if_true(STUB_ARGS);
</span><ins>+        static int JIT_STUB cti_op_load_varargs(STUB_ARGS);
</ins><span class="cx">         static int JIT_STUB cti_timeout_check(STUB_ARGS);
</span><span class="cx">         static void JIT_STUB cti_op_create_arguments(STUB_ARGS);
</span><span class="cx">         static void JIT_STUB cti_op_create_arguments_no_params(STUB_ARGS);
</span></span></pre></div>
<a id="trunkJavaScriptCoreparserGrammary"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/parser/Grammar.y (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/parser/Grammar.y        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/parser/Grammar.y        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -1928,6 +1928,8 @@
</span><span class="cx">     FunctionCallDotNode* node;
</span><span class="cx">     if (dot-&gt;identifier() == GLOBAL_DATA-&gt;propertyNames-&gt;call)
</span><span class="cx">         node = new CallFunctionCallDotNode(GLOBAL_DATA, dot-&gt;base(), dot-&gt;identifier(), args.m_node, divot, divot - start, end - divot);
</span><ins>+    else if (dot-&gt;identifier() == GLOBAL_DATA-&gt;propertyNames-&gt;apply)
+        node = new ApplyFunctionCallDotNode(GLOBAL_DATA, dot-&gt;base(), dot-&gt;identifier(), args.m_node, divot, divot - start, end - divot);
</ins><span class="cx">     else
</span><span class="cx">         node = new FunctionCallDotNode(GLOBAL_DATA, dot-&gt;base(), dot-&gt;identifier(), args.m_node, divot, divot - start, end - divot);
</span><span class="cx">     node-&gt;setSubexpressionInfo(dot-&gt;divot(), dot-&gt;endOffset());
</span></span></pre></div>
<a id="trunkJavaScriptCoreparserNodescpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/parser/Nodes.cpp (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/parser/Nodes.cpp        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/parser/Nodes.cpp        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -404,6 +404,34 @@
</span><span class="cx">     return generator.moveToDestinationIfNeeded(dst, array.get());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool ArrayNode::isSimpleArray() const
+{
+    if (m_elision || m_optional)
+        return false;
+    for (ElementNode* ptr = m_element.get(); ptr; ptr = ptr-&gt;next()) {
+        if (ptr-&gt;elision())
+            return false;
+    }
+    return true;
+}
+
+PassRefPtr&lt;ArgumentListNode&gt; ArrayNode::toArgumentList(JSGlobalData* globalData) const
+{
+    ASSERT(!m_elision &amp;&amp; !m_optional);
+    RefPtr&lt;ArgumentListNode&gt; head;
+    ElementNode* ptr = m_element.get();
+    if (!ptr)
+        return head;
+    head = new ArgumentListNode(globalData, ptr-&gt;value());
+    ArgumentListNode* tail = head.get();
+    ptr = ptr-&gt;next();
+    for (; ptr; ptr = ptr-&gt;next()) {
+        ASSERT(!ptr-&gt;elision());
+        tail = new ArgumentListNode(globalData, tail, ptr-&gt;value());
+    }
+    return head.release();
+}
+
</ins><span class="cx"> // ------------------------------ PropertyNode ----------------------------
</span><span class="cx"> 
</span><span class="cx"> PropertyNode::~PropertyNode()
</span><span class="lines">@@ -710,9 +738,9 @@
</span><span class="cx">         if (m_args-&gt;m_listNode &amp;&amp; m_args-&gt;m_listNode-&gt;m_expr) {
</span><span class="cx">             generator.emitNode(thisRegister.get(), m_args-&gt;m_listNode-&gt;m_expr.get());
</span><span class="cx">             m_args-&gt;m_listNode = m_args-&gt;m_listNode-&gt;m_next;
</span><del>-        } else {
</del><ins>+        } else
</ins><span class="cx">             generator.emitLoad(thisRegister.get(), jsNull());
</span><del>-        }
</del><ins>+
</ins><span class="cx">         generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset());
</span><span class="cx">         generator.emitJump(end.get());
</span><span class="cx">         m_args-&gt;m_listNode = oldList;
</span><span class="lines">@@ -725,7 +753,70 @@
</span><span class="cx">     generator.emitLabel(end.get());
</span><span class="cx">     return finalDestination.get();
</span><span class="cx"> }
</span><ins>+    
+static bool areTrivialApplyArguments(ArgumentsNode* args)
+{
+    return !args-&gt;m_listNode || !args-&gt;m_listNode-&gt;m_expr || !args-&gt;m_listNode-&gt;m_next
+        || (!args-&gt;m_listNode-&gt;m_next-&gt;m_next &amp;&amp; args-&gt;m_listNode-&gt;m_next-&gt;m_expr-&gt;isSimpleArray());
+}
</ins><span class="cx"> 
</span><ins>+RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator&amp; generator, RegisterID* dst)
+{
+    // A few simple cases can be trivially handled as ordinary functions calls
+    // function.apply(), function.apply(arg) -&gt; identical to function.call
+    // function.apply(thisArg, [arg0, arg1, ...]) -&gt; can be trivially coerced into function.call(thisArg, arg0, arg1, ...) and saves object allocation
+    bool mayBeCall = areTrivialApplyArguments(m_args.get());
+
+    RefPtr&lt;Label&gt; realCall = generator.newLabel();
+    RefPtr&lt;Label&gt; end = generator.newLabel();
+    RefPtr&lt;RegisterID&gt; base = generator.emitNode(m_base.get());
+    generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset);
+    RefPtr&lt;RegisterID&gt; function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
+    RefPtr&lt;RegisterID&gt; finalDestination = generator.finalDestination(dst, function.get());
+    generator.emitJumpIfNotFunctionApply(function.get(), realCall.get());
+    {
+        if (mayBeCall) {
+            RefPtr&lt;RegisterID&gt; realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
+            RefPtr&lt;RegisterID&gt; thisRegister = generator.newTemporary();
+            RefPtr&lt;ArgumentListNode&gt; oldList = m_args-&gt;m_listNode;
+            if (m_args-&gt;m_listNode &amp;&amp; m_args-&gt;m_listNode-&gt;m_expr) {
+                generator.emitNode(thisRegister.get(), m_args-&gt;m_listNode-&gt;m_expr.get());
+                m_args-&gt;m_listNode = m_args-&gt;m_listNode-&gt;m_next;
+                if (m_args-&gt;m_listNode) {
+                    ASSERT(m_args-&gt;m_listNode-&gt;m_expr-&gt;isSimpleArray());
+                    ASSERT(!m_args-&gt;m_listNode-&gt;m_next);
+                    m_args-&gt;m_listNode = static_cast&lt;ArrayNode*&gt;(m_args-&gt;m_listNode-&gt;m_expr.get())-&gt;toArgumentList(generator.globalData());
+                }
+            } else
+                generator.emitLoad(thisRegister.get(), jsNull());
+            generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset());
+            m_args-&gt;m_listNode = oldList;
+        } else {
+            ASSERT(m_args-&gt;m_listNode &amp;&amp; m_args-&gt;m_listNode-&gt;m_next);
+            RefPtr&lt;RegisterID&gt; realFunction = generator.emitMove(generator.newTemporary(), base.get());
+            RefPtr&lt;RegisterID&gt; argsCountRegister = generator.newTemporary();
+            RefPtr&lt;RegisterID&gt; thisRegister = generator.newTemporary();
+            RefPtr&lt;RegisterID&gt; argsRegister = generator.newTemporary();
+            generator.emitNode(thisRegister.get(), m_args-&gt;m_listNode-&gt;m_expr.get());
+            ArgumentListNode* args = m_args-&gt;m_listNode-&gt;m_next.get();
+            generator.emitNode(argsRegister.get(), args-&gt;m_expr.get());
+            while ((args = args-&gt;m_next.get()))
+                generator.emitNode(generator.newTemporary(), args-&gt;m_expr.get());
+
+            generator.emitLoadVarargs(argsCountRegister.get(), argsRegister.get());
+            generator.emitCallVarargs(finalDestination.get(), realFunction.get(), thisRegister.get(), argsCountRegister.get(), divot(), startOffset(), endOffset());
+        }
+        generator.emitJump(end.get());
+    }
+    generator.emitLabel(realCall.get());
+    {
+        RefPtr&lt;RegisterID&gt; thisRegister = generator.emitMove(generator.newTemporary(), base.get());
+        generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset());
+    }
+    generator.emitLabel(end.get());
+    return finalDestination.get();
+}
+
</ins><span class="cx"> // ------------------------------ PostfixResolveNode ----------------------------------
</span><span class="cx"> 
</span><span class="cx"> static RegisterID* emitPreIncOrDec(BytecodeGenerator&amp; generator, RegisterID* srcDst, Operator oper)
</span></span></pre></div>
<a id="trunkJavaScriptCoreparserNodesh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/parser/Nodes.h (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/parser/Nodes.h        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/parser/Nodes.h        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -43,6 +43,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+    class ArgumentListNode;
</ins><span class="cx">     class CodeBlock;
</span><span class="cx">     class BytecodeGenerator;
</span><span class="cx">     class FuncDeclNode;
</span><span class="lines">@@ -171,6 +172,7 @@
</span><span class="cx">         virtual bool isBracketAccessorNode() const JSC_FAST_CALL { return false; }
</span><span class="cx">         virtual bool isDotAccessorNode() const JSC_FAST_CALL { return false; }
</span><span class="cx">         virtual bool isFuncExprNode() const JSC_FAST_CALL { return false; } 
</span><ins>+        virtual bool isSimpleArray() const JSC_FAST_CALL { return false; }
</ins><span class="cx"> 
</span><span class="cx">         virtual ExpressionNode* stripUnaryPlus() { return this; }
</span><span class="cx"> 
</span><span class="lines">@@ -470,6 +472,8 @@
</span><span class="cx"> 
</span><span class="cx">         virtual RegisterID* emitBytecode(BytecodeGenerator&amp;, RegisterID* = 0) JSC_FAST_CALL;
</span><span class="cx"> 
</span><ins>+        virtual bool isSimpleArray() const JSC_FAST_CALL;
+        PassRefPtr&lt;ArgumentListNode&gt; toArgumentList(JSGlobalData*) const;
</ins><span class="cx">     private:
</span><span class="cx">         RefPtr&lt;ElementNode&gt; m_element;
</span><span class="cx">         int m_elision;
</span><span class="lines">@@ -777,6 +781,15 @@
</span><span class="cx">         }
</span><span class="cx">         virtual RegisterID* emitBytecode(BytecodeGenerator&amp;, RegisterID* = 0) JSC_FAST_CALL;
</span><span class="cx">     };
</span><ins>+    
+    class ApplyFunctionCallDotNode : public FunctionCallDotNode {
+    public:
+        ApplyFunctionCallDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier&amp; ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+        : FunctionCallDotNode(globalData, base, ident, args, divot, startOffset, endOffset)
+        {
+        }
+        virtual RegisterID* emitBytecode(BytecodeGenerator&amp;, RegisterID* = 0) JSC_FAST_CALL;
+    };
</ins><span class="cx"> 
</span><span class="cx">     class PrePostResolveNode : public ExpressionNode, public ThrowableExpressionData {
</span><span class="cx">     public:
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeArgumentscpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/Arguments.cpp (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/Arguments.cpp        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/runtime/Arguments.cpp        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -69,6 +69,41 @@
</span><span class="cx">         d-&gt;activation-&gt;mark();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Arguments::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize)
+{
+    if (UNLIKELY(d-&gt;overrodeLength)) {
+        unsigned length = min(get(exec, exec-&gt;propertyNames().length).toUInt32(exec), maxSize);
+        for (unsigned i = 0; i &lt; length; i++)
+            buffer[i] = get(exec, i);
+        return;
+    }
+
+    if (LIKELY(!d-&gt;deletedArguments)) {
+        unsigned parametersLength = min(min(d-&gt;numParameters, d-&gt;numArguments), maxSize);
+        unsigned i = 0;
+        for (; i &lt; parametersLength; ++i)
+            buffer[i] = d-&gt;registers[d-&gt;firstParameterIndex + i].jsValue(exec);
+        for (; i &lt; d-&gt;numArguments; ++i)
+            buffer[i] = d-&gt;extraArguments[i - d-&gt;numParameters].jsValue(exec);
+        return;
+    }
+    
+    unsigned parametersLength = min(min(d-&gt;numParameters, d-&gt;numArguments), maxSize);
+    unsigned i = 0;
+    for (; i &lt; parametersLength; ++i) {
+        if (!d-&gt;deletedArguments[i])
+            buffer[i] = d-&gt;registers[d-&gt;firstParameterIndex + i].jsValue(exec);
+        else
+            buffer[i] = get(exec, i);
+    }
+    for (; i &lt; d-&gt;numArguments; ++i) {
+        if (!d-&gt;deletedArguments[i])
+            buffer[i] = d-&gt;extraArguments[i - d-&gt;numParameters].jsValue(exec);
+        else
+            buffer[i] = get(exec, i);
+    }
+}
+
</ins><span class="cx"> void Arguments::fillArgList(ExecState* exec, ArgList&amp; args)
</span><span class="cx"> {
</span><span class="cx">     if (UNLIKELY(d-&gt;overrodeLength)) {
</span><span class="lines">@@ -76,7 +111,7 @@
</span><span class="cx">         for (unsigned i = 0; i &lt; length; i++) 
</span><span class="cx">             args.append(get(exec, i)); 
</span><span class="cx">         return;
</span><del>-   }
</del><ins>+    }
</ins><span class="cx"> 
</span><span class="cx">     if (LIKELY(!d-&gt;deletedArguments)) {
</span><span class="cx">         if (LIKELY(!d-&gt;numParameters)) {
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeArgumentsh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/Arguments.h (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/Arguments.h        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/runtime/Arguments.h        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -65,6 +65,14 @@
</span><span class="cx"> 
</span><span class="cx">         void fillArgList(ExecState*, ArgList&amp;);
</span><span class="cx"> 
</span><ins>+        uint32_t numProvidedArguments(ExecState* exec) const 
+        {
+            if (UNLIKELY(d-&gt;overrodeLength))
+                return get(exec, exec-&gt;propertyNames().length).toUInt32(exec);
+            return d-&gt;numArguments; 
+        }
+        
+        void copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize);
</ins><span class="cx">         void copyRegisters();
</span><span class="cx">         bool isTornOff() const { return d-&gt;registerArray; }
</span><span class="cx">         void setActivation(JSActivation* activation)
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeFunctionPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/FunctionPrototype.cpp (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/FunctionPrototype.cpp        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/runtime/FunctionPrototype.cpp        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -43,10 +43,11 @@
</span><span class="cx">     putDirectWithoutTransition(exec-&gt;propertyNames().length, jsNumber(exec, 0), DontDelete | ReadOnly | DontEnum);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void FunctionPrototype::addFunctionProperties(ExecState* exec, Structure* prototypeFunctionStructure, PrototypeFunction** callFunction)
</del><ins>+void FunctionPrototype::addFunctionProperties(ExecState* exec, Structure* prototypeFunctionStructure, PrototypeFunction** callFunction, PrototypeFunction** applyFunction)
</ins><span class="cx"> {
</span><span class="cx">     putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec-&gt;propertyNames().toString, functionProtoFuncToString), DontEnum);
</span><del>-    putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 2, exec-&gt;propertyNames().apply, functionProtoFuncApply), DontEnum);
</del><ins>+    *applyFunction = new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 2, exec-&gt;propertyNames().apply, functionProtoFuncApply);
+    putDirectFunctionWithoutTransition(exec, *applyFunction, DontEnum);
</ins><span class="cx">     *callFunction = new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 1, exec-&gt;propertyNames().call, functionProtoFuncCall);
</span><span class="cx">     putDirectFunctionWithoutTransition(exec, *callFunction, DontEnum);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeFunctionPrototypeh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/FunctionPrototype.h (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/FunctionPrototype.h        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/runtime/FunctionPrototype.h        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -30,7 +30,7 @@
</span><span class="cx">     class FunctionPrototype : public InternalFunction {
</span><span class="cx">     public:
</span><span class="cx">         FunctionPrototype(ExecState*, PassRefPtr&lt;Structure&gt;);
</span><del>-        void addFunctionProperties(ExecState*, Structure* prototypeFunctionStructure, PrototypeFunction** callFunction);
</del><ins>+        void addFunctionProperties(ExecState*, Structure* prototypeFunctionStructure, PrototypeFunction** callFunction, PrototypeFunction** applyFunction);
</ins><span class="cx"> 
</span><span class="cx">         static PassRefPtr&lt;Structure&gt; createStructure(JSValuePtr proto)
</span><span class="cx">         {
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeJSArraycpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/JSArray.cpp (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/JSArray.cpp        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/runtime/JSArray.cpp        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -910,6 +910,19 @@
</span><span class="cx">         args.append(get(exec, i));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void JSArray::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize)
+{
+    ASSERT(m_storage-&gt;m_length == maxSize);
+    UNUSED_PARAM(maxSize);
+    unsigned fastAccessLength = min(m_storage-&gt;m_length, m_fastAccessCutoff);
+    unsigned i = 0;
+    for (; i &lt; fastAccessLength; ++i)
+        buffer[i] = getIndex(i);
+    uint32_t size = m_storage-&gt;m_length;
+    for (; i &lt; size; ++i)
+        buffer[i] = get(exec, i);
+}
+
</ins><span class="cx"> unsigned JSArray::compactForSorting()
</span><span class="cx"> {
</span><span class="cx">     checkConsistency();
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeJSArrayh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/JSArray.h (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/JSArray.h        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/runtime/JSArray.h        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -76,6 +76,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         void fillArgList(ExecState*, ArgList&amp;);
</span><ins>+        void copyToRegisters(ExecState*, Register*, uint32_t);
</ins><span class="cx"> 
</span><span class="cx">         static PassRefPtr&lt;Structure&gt; createStructure(JSValuePtr prototype)
</span><span class="cx">         {
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeJSGlobalObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/JSGlobalObject.cpp (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/JSGlobalObject.cpp        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/runtime/JSGlobalObject.cpp        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -204,8 +204,10 @@
</span><span class="cx">     d()-&gt;functionPrototype = new (exec) FunctionPrototype(exec, FunctionPrototype::createStructure(jsNull())); // The real prototype will be set once ObjectPrototype is created.
</span><span class="cx">     d()-&gt;prototypeFunctionStructure = PrototypeFunction::createStructure(d()-&gt;functionPrototype);
</span><span class="cx">     PrototypeFunction* callFunction = 0;
</span><del>-    d()-&gt;functionPrototype-&gt;addFunctionProperties(exec, d()-&gt;prototypeFunctionStructure.get(), &amp;callFunction);
</del><ins>+    PrototypeFunction* applyFunction = 0;
+    d()-&gt;functionPrototype-&gt;addFunctionProperties(exec, d()-&gt;prototypeFunctionStructure.get(), &amp;callFunction, &amp;applyFunction);
</ins><span class="cx">     d()-&gt;callFunction = callFunction;
</span><ins>+    d()-&gt;applyFunction = applyFunction;
</ins><span class="cx">     d()-&gt;objectPrototype = new (exec) ObjectPrototype(exec, ObjectPrototype::createStructure(jsNull()), d()-&gt;prototypeFunctionStructure.get());
</span><span class="cx">     d()-&gt;functionPrototype-&gt;structure()-&gt;setPrototypeWithoutTransition(d()-&gt;objectPrototype);
</span><span class="cx"> 
</span><span class="lines">@@ -373,6 +375,7 @@
</span><span class="cx"> 
</span><span class="cx">     markIfNeeded(d()-&gt;evalFunction);
</span><span class="cx">     markIfNeeded(d()-&gt;callFunction);
</span><ins>+    markIfNeeded(d()-&gt;applyFunction);
</ins><span class="cx"> 
</span><span class="cx">     markIfNeeded(d()-&gt;objectPrototype);
</span><span class="cx">     markIfNeeded(d()-&gt;functionPrototype);
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeJSGlobalObjecth"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/JSGlobalObject.h (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/JSGlobalObject.h        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/JavaScriptCore/runtime/JSGlobalObject.h        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -69,6 +69,7 @@
</span><span class="cx">                 , URIErrorConstructor(0)
</span><span class="cx">                 , evalFunction(0)
</span><span class="cx">                 , callFunction(0)
</span><ins>+                , applyFunction(0)
</ins><span class="cx">                 , objectPrototype(0)
</span><span class="cx">                 , functionPrototype(0)
</span><span class="cx">                 , arrayPrototype(0)
</span><span class="lines">@@ -107,6 +108,7 @@
</span><span class="cx"> 
</span><span class="cx">             GlobalEvalFunction* evalFunction;
</span><span class="cx">             PrototypeFunction* callFunction;
</span><ins>+            PrototypeFunction* applyFunction;
</ins><span class="cx"> 
</span><span class="cx">             ObjectPrototype* objectPrototype;
</span><span class="cx">             FunctionPrototype* functionPrototype;
</span></span></pre></div>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/LayoutTests/ChangeLog        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2009-04-07  Oliver Hunt  &lt;oliver@apple.com&gt;
+
+        Reviewed by Geoff Garen.
+
+        Add a bunch of tests for function.apply
+
+        * fast/js/function-apply-aliased-expected.txt: Added.
+        * fast/js/function-apply-aliased.html: Added.
+        * fast/js/resources/function-apply-aliased.js: Added.
+        * fast/profiler/apply-expected.txt:
+
</ins><span class="cx"> 2009-04-08  Adam Roben  &lt;aroben@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Skip fast/cookies/local-file-can-set-cookies.html on Windows
</span></span></pre></div>
<a id="trunkLayoutTestsfastjsfunctionapplyaliasedexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/js/function-apply-aliased-expected.txt (0 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/js/function-apply-aliased-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/js/function-apply-aliased-expected.txt        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+This tests that we can correctly call Function.prototype.apply
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS myObject.apply() is [myObject, &quot;myObject.apply&quot;]
+PASS forwarder(myObject) is [myObject, &quot;myObject.apply&quot;]
+PASS myFunction('arg1') is [this, &quot;myFunction&quot;, &quot;arg1&quot;]
+PASS forwarder(myFunction, null, ['arg1']) is [this, &quot;myFunction&quot;, &quot;arg1&quot;]
+PASS myFunction.apply(myObject, ['arg1']) is [myObject, &quot;myFunction&quot;, &quot;arg1&quot;]
+PASS myFunction.apply(myObject, arg1Array) is [myObject, &quot;myFunction&quot;, &quot;arg1&quot;]
+PASS forwarder(myFunction, myObject, arg1Array) is [myObject, &quot;myFunction&quot;, &quot;arg1&quot;]
+PASS myFunction.apply() is [this, &quot;myFunction&quot;, undefined]
+PASS myFunction.apply(null) is [this, &quot;myFunction&quot;, undefined]
+PASS myFunction.apply(undefined) is [this, &quot;myFunction&quot;, undefined]
+PASS myFunction.aliasedApply(myObject, ['arg1']) is [myObject, &quot;myFunction&quot;, &quot;arg1&quot;]
+PASS myFunction.aliasedApply() is [this, &quot;myFunction&quot;, undefined]
+PASS myFunction.aliasedApply(null) is [this, &quot;myFunction&quot;, undefined]
+PASS myFunction.aliasedApply(undefined) is [this, &quot;myFunction&quot;, undefined]
+PASS myFunctionWithApply.apply(myObject, ['arg1']) is [myFunctionWithApply, &quot;myFunctionWithApply.apply&quot;, myObject]
+PASS myFunctionWithApply.aliasedApply(myObject, ['arg1']) is [myObject, &quot;myFunctionWithApply&quot;, &quot;arg1&quot;]
+PASS myFunctionWithApply.apply(myObject, arg1Array) is [myFunctionWithApply, &quot;myFunctionWithApply.apply&quot;, myObject]
+PASS forwarder(myFunctionWithApply, myObject, arg1Array) is [myFunctionWithApply, &quot;myFunctionWithApply.apply&quot;, myObject]
+PASS myFunctionWithApply.aliasedApply(myObject, arg1Array) is [myObject, &quot;myFunctionWithApply&quot;, &quot;arg1&quot;]
+PASS myFunction.apply(null, new Array(5000000)) threw exception RangeError: Maximum call stack size exceeded..
+PASS myFunction.apply(null, new Array(1 &lt;&lt; 30)) threw exception RangeError: Maximum call stack size exceeded..
+PASS recurseArguments.apply(null, new Array(50000)) threw exception RangeError: Maximum call stack size exceeded..
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastjsfunctionapplyaliasedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/js/function-apply-aliased.html (0 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/js/function-apply-aliased.html                                (rev 0)
+++ trunk/LayoutTests/fast/js/function-apply-aliased.html        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;link rel=&quot;stylesheet&quot; href=&quot;resources/js-test-style.css&quot;&gt;
+&lt;script src=&quot;resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;p id=&quot;description&quot;&gt;&lt;/p&gt;
+&lt;div id=&quot;console&quot;&gt;&lt;/div&gt;
+&lt;script src=&quot;resources/function-apply-aliased.js&quot; type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastjsresourcesfunctionapplyaliasedjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/js/resources/function-apply-aliased.js (0 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/js/resources/function-apply-aliased.js                                (rev 0)
+++ trunk/LayoutTests/fast/js/resources/function-apply-aliased.js        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -0,0 +1,54 @@
</span><ins>+description(
+&quot;This tests that we can correctly call Function.prototype.apply&quot;
+);
+
+var myObject = { apply: function() { return [myObject, &quot;myObject.apply&quot;] } };
+var myFunction = function (arg1) {
+    return [this, &quot;myFunction&quot;, arg1];
+};
+var myFunctionWithApply = function (arg1) { 
+    return [this, &quot;myFunctionWithApply&quot;, arg1];
+};
+
+function forwarder(f, thisValue, args) {
+    function g() {
+        return f.apply(thisValue, arguments);
+    }
+    return g.apply(null, args);
+}
+function recurseArguments() {
+    recurseArguments.apply(null, arguments);
+}
+
+myFunctionWithApply.apply = function (arg1) { return [this, &quot;myFunctionWithApply.apply&quot;, arg1] };
+Function.prototype.aliasedApply = Function.prototype.apply;
+var arg1Array = ['arg1'];
+
+shouldBe(&quot;myObject.apply()&quot;, '[myObject, &quot;myObject.apply&quot;]');
+shouldBe(&quot;forwarder(myObject)&quot;, '[myObject, &quot;myObject.apply&quot;]');
+shouldBe(&quot;myFunction('arg1')&quot;, '[this, &quot;myFunction&quot;, &quot;arg1&quot;]');
+shouldBe(&quot;forwarder(myFunction, null, ['arg1'])&quot;, '[this, &quot;myFunction&quot;, &quot;arg1&quot;]');
+shouldBe(&quot;myFunction.apply(myObject, ['arg1'])&quot;, '[myObject, &quot;myFunction&quot;, &quot;arg1&quot;]');
+shouldBe(&quot;myFunction.apply(myObject, arg1Array)&quot;, '[myObject, &quot;myFunction&quot;, &quot;arg1&quot;]');
+shouldBe(&quot;forwarder(myFunction, myObject, arg1Array)&quot;, '[myObject, &quot;myFunction&quot;, &quot;arg1&quot;]');
+shouldBe(&quot;myFunction.apply()&quot;, '[this, &quot;myFunction&quot;, undefined]');
+shouldBe(&quot;myFunction.apply(null)&quot;, '[this, &quot;myFunction&quot;, undefined]');
+shouldBe(&quot;myFunction.apply(undefined)&quot;, '[this, &quot;myFunction&quot;, undefined]');
+shouldBe(&quot;myFunction.aliasedApply(myObject, ['arg1'])&quot;, '[myObject, &quot;myFunction&quot;, &quot;arg1&quot;]');
+shouldBe(&quot;myFunction.aliasedApply()&quot;, '[this, &quot;myFunction&quot;, undefined]');
+shouldBe(&quot;myFunction.aliasedApply(null)&quot;, '[this, &quot;myFunction&quot;, undefined]');
+shouldBe(&quot;myFunction.aliasedApply(undefined)&quot;, '[this, &quot;myFunction&quot;, undefined]');
+shouldBe(&quot;myFunctionWithApply.apply(myObject, ['arg1'])&quot;, '[myFunctionWithApply, &quot;myFunctionWithApply.apply&quot;, myObject]');
+shouldBe(&quot;myFunctionWithApply.aliasedApply(myObject, ['arg1'])&quot;, '[myObject, &quot;myFunctionWithApply&quot;, &quot;arg1&quot;]');
+shouldBe(&quot;myFunctionWithApply.apply(myObject, arg1Array)&quot;, '[myFunctionWithApply, &quot;myFunctionWithApply.apply&quot;, myObject]');
+shouldBe(&quot;forwarder(myFunctionWithApply, myObject, arg1Array)&quot;, '[myFunctionWithApply, &quot;myFunctionWithApply.apply&quot;, myObject]');
+shouldBe(&quot;myFunctionWithApply.aliasedApply(myObject, arg1Array)&quot;, '[myObject, &quot;myFunctionWithApply&quot;, &quot;arg1&quot;]');
+
+// Blow the stack with a sparse array
+shouldThrow(&quot;myFunction.apply(null, new Array(5000000))&quot;);
+// Blow the stack with a sparse array that is sufficiently large to cause int overflow
+shouldThrow(&quot;myFunction.apply(null, new Array(1 &lt;&lt; 30))&quot;);
+// Blow the stack recursing with arguments
+shouldThrow(&quot;recurseArguments.apply(null, new Array(50000))&quot;);
+
+var successfullyParsed = true;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastprofilerapplyexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/profiler/apply-expected.txt (42336 => 42337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/profiler/apply-expected.txt        2009-04-08 23:06:52 UTC (rev 42336)
+++ trunk/LayoutTests/fast/profiler/apply-expected.txt        2009-04-08 23:08:28 UTC (rev 42337)
</span><span class="lines">@@ -6,8 +6,7 @@
</span><span class="cx"> Thread_1 (no file) (line 0)
</span><span class="cx">    startTest apply.html (line 11)
</span><span class="cx">       fakeObject apply.html (line 18)
</span><del>-         apply (no file) (line 0)
-            fakeInteriorFunction apply.html (line 24)
</del><ins>+         fakeInteriorFunction apply.html (line 24)
</ins><span class="cx">       endTest profiler-test-JS-resources.js (line 1)
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>