<!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>[38322] 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/38322">38322</a></dd>
<dt>Author</dt> <dd>ggaren@apple.com</dd>
<dt>Date</dt> <dd>2008-11-11 16:32:38 -0800 (Tue, 11 Nov 2008)</dd>
</dl>

<h3>Log Message</h3>
<pre>2008-11-11  Geoffrey Garen  &lt;ggaren@apple.com&gt;

        Reviewed by Darin Adler.
        
        Fixed https://bugs.webkit.org/show_bug.cgi?id=22174
        Simplified op_call by nixing its responsibility for moving the value of
        &quot;this&quot; into the first argument slot.

        Instead, the caller emits an explicit load or mov instruction, or relies
        on implicit knowledge that &quot;this&quot; is already in the first argument slot.
        As a result, two operands to op_call are gone: firstArg and thisVal.
        
        SunSpider and v8 tests show no change in bytecode or CTI.

        * VM/CTI.cpp:
        (JSC::CTI::compileOpCallSetupArgs):
        (JSC::CTI::compileOpCallEvalSetupArgs):
        (JSC::CTI::compileOpConstructSetupArgs): Split apart these three versions
        of setting up arguments to op_call, because they're more different than
        they are the same -- even more so with this patch.

        (JSC::CTI::compileOpCall): Updated for the fact that op_construct doesn't
        match op_call anymore.

        (JSC::CTI::privateCompileMainPass):
        (JSC::CTI::privateCompileSlowCases): Merged a few call cases. Updated
        for changes mentioned above.

        * VM/CTI.h:

        * VM/CodeBlock.cpp:
        (JSC::CodeBlock::dump): Updated for new bytecode format of call / construct.

        * VM/Machine.cpp:
        (JSC::Machine::callEval): Updated for new bytecode format of call / construct.

        (JSC::Machine::dumpCallFrame):
        (JSC::Machine::dumpRegisters): Simplified these debugging functions, 
        taking advantage of the new call frame layout.

        (JSC::Machine::execute): Fixed up the eval version of execute to be
        friendlier to calls in the new format.

        (JSC::Machine::privateExecute): Implemented the new call format in
        bytecode.

        (JSC::Machine::cti_op_call_NotJSFunction):
        (JSC::Machine::cti_op_construct_JSConstruct):
        (JSC::Machine::cti_op_construct_NotJSConstruct):
        (JSC::Machine::cti_op_call_eval): Updated CTI helpers to match the new
        call format.
        
        Fixed a latent bug in stack overflow checking that is now hit because
        the register layout has changed a bit -- namely: when throwing a stack
        overflow exception inside an op_call helper, we need to account for the
        fact that the current call frame is only half-constructed, and use the
        parent call frame instead.

        * VM/Machine.h:

        * bytecompiler/CodeGenerator.cpp:
        (JSC::CodeGenerator::emitCall):
        (JSC::CodeGenerator::emitCallEval):
        (JSC::CodeGenerator::emitConstruct):
        * bytecompiler/CodeGenerator.h: Updated codegen to match the new call
        format.

        * parser/Nodes.cpp:
        (JSC::EvalFunctionCallNode::emitCode):
        (JSC::FunctionCallValueNode::emitCode):
        (JSC::FunctionCallResolveNode::emitCode):
        (JSC::FunctionCallBracketNode::emitCode):
        (JSC::FunctionCallDotNode::emitCode):
        * parser/Nodes.h:
        (JSC::ScopeNode::neededConstants): ditto

2008-11-10  Geoffrey Garen  &lt;ggaren@apple.com&gt;

        Reviewed by Darin Adler.
        
        Updated a test after fixing https://bugs.webkit.org/show_bug.cgi?id=22174
        Simplified op_call by nixing its responsibility for moving the value of
        &quot;this&quot; into the first argument slot.

        * fast/js/global-recursion-on-full-stack-expected.txt: This test passes
        a little differently now, because the register layout has changed.
        Specifically, the stack overflow now happens in the call to f() instead
        of the initiation of the &lt;script&gt; tag, so it is caught, and it does not
        log an exception to the console.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJavaScriptCoreChangeLog">trunk/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkJavaScriptCoreVMCTIcpp">trunk/JavaScriptCore/VM/CTI.cpp</a></li>
<li><a href="#trunkJavaScriptCoreVMCTIh">trunk/JavaScriptCore/VM/CTI.h</a></li>
<li><a href="#trunkJavaScriptCoreVMCodeBlockcpp">trunk/JavaScriptCore/VM/CodeBlock.cpp</a></li>
<li><a href="#trunkJavaScriptCoreVMMachinecpp">trunk/JavaScriptCore/VM/Machine.cpp</a></li>
<li><a href="#trunkJavaScriptCoreVMMachineh">trunk/JavaScriptCore/VM/Machine.h</a></li>
<li><a href="#trunkJavaScriptCorebytecompilerCodeGeneratorcpp">trunk/JavaScriptCore/bytecompiler/CodeGenerator.cpp</a></li>
<li><a href="#trunkJavaScriptCorebytecompilerCodeGeneratorh">trunk/JavaScriptCore/bytecompiler/CodeGenerator.h</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="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfastjsglobalrecursiononfullstackexpectedtxt">trunk/LayoutTests/fast/js/global-recursion-on-full-stack-expected.txt</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/ChangeLog (38321 => 38322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/ChangeLog        2008-11-12 00:28:57 UTC (rev 38321)
+++ trunk/JavaScriptCore/ChangeLog        2008-11-12 00:32:38 UTC (rev 38322)
</span><span class="lines">@@ -1,3 +1,79 @@
</span><ins>+2008-11-11  Geoffrey Garen  &lt;ggaren@apple.com&gt;
+
+        Reviewed by Darin Adler.
+        
+        Fixed https://bugs.webkit.org/show_bug.cgi?id=22174
+        Simplified op_call by nixing its responsibility for moving the value of
+        &quot;this&quot; into the first argument slot.
+
+        Instead, the caller emits an explicit load or mov instruction, or relies
+        on implicit knowledge that &quot;this&quot; is already in the first argument slot.
+        As a result, two operands to op_call are gone: firstArg and thisVal.
+        
+        SunSpider and v8 tests show no change in bytecode or CTI.
+
+        * VM/CTI.cpp:
+        (JSC::CTI::compileOpCallSetupArgs):
+        (JSC::CTI::compileOpCallEvalSetupArgs):
+        (JSC::CTI::compileOpConstructSetupArgs): Split apart these three versions
+        of setting up arguments to op_call, because they're more different than
+        they are the same -- even more so with this patch.
+
+        (JSC::CTI::compileOpCall): Updated for the fact that op_construct doesn't
+        match op_call anymore.
+
+        (JSC::CTI::privateCompileMainPass):
+        (JSC::CTI::privateCompileSlowCases): Merged a few call cases. Updated
+        for changes mentioned above.
+
+        * VM/CTI.h:
+
+        * VM/CodeBlock.cpp:
+        (JSC::CodeBlock::dump): Updated for new bytecode format of call / construct.
+
+        * VM/Machine.cpp:
+        (JSC::Machine::callEval): Updated for new bytecode format of call / construct.
+
+        (JSC::Machine::dumpCallFrame):
+        (JSC::Machine::dumpRegisters): Simplified these debugging functions, 
+        taking advantage of the new call frame layout.
+
+        (JSC::Machine::execute): Fixed up the eval version of execute to be
+        friendlier to calls in the new format.
+
+        (JSC::Machine::privateExecute): Implemented the new call format in
+        bytecode.
+
+        (JSC::Machine::cti_op_call_NotJSFunction):
+        (JSC::Machine::cti_op_construct_JSConstruct):
+        (JSC::Machine::cti_op_construct_NotJSConstruct):
+        (JSC::Machine::cti_op_call_eval): Updated CTI helpers to match the new
+        call format.
+        
+        Fixed a latent bug in stack overflow checking that is now hit because
+        the register layout has changed a bit -- namely: when throwing a stack
+        overflow exception inside an op_call helper, we need to account for the
+        fact that the current call frame is only half-constructed, and use the
+        parent call frame instead.
+
+        * VM/Machine.h:
+
+        * bytecompiler/CodeGenerator.cpp:
+        (JSC::CodeGenerator::emitCall):
+        (JSC::CodeGenerator::emitCallEval):
+        (JSC::CodeGenerator::emitConstruct):
+        * bytecompiler/CodeGenerator.h: Updated codegen to match the new call
+        format.
+
+        * parser/Nodes.cpp:
+        (JSC::EvalFunctionCallNode::emitCode):
+        (JSC::FunctionCallValueNode::emitCode):
+        (JSC::FunctionCallResolveNode::emitCode):
+        (JSC::FunctionCallBracketNode::emitCode):
+        (JSC::FunctionCallDotNode::emitCode):
+        * parser/Nodes.h:
+        (JSC::ScopeNode::neededConstants): ditto
+
</ins><span class="cx"> 2008-11-11  Cameron Zwarich  &lt;zwarich@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Reviewed by Geoff Garen.
</span></span></pre></div>
<a id="trunkJavaScriptCoreVMCTIcpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/VM/CTI.cpp (38321 => 38322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/VM/CTI.cpp        2008-11-12 00:28:57 UTC (rev 38321)
+++ trunk/JavaScriptCore/VM/CTI.cpp        2008-11-12 00:32:38 UTC (rev 38322)
</span><span class="lines">@@ -587,47 +587,58 @@
</span><span class="cx">     m_jit.movl_rm(X86::ebx, RegisterFile::ScopeChain * static_cast&lt;int&gt;(sizeof(Register)), X86::edi);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void CTI::compileOpCallSetupArgs(Instruction* instruction, bool isConstruct, bool isEval)
</del><ins>+void CTI::compileOpCallSetupArgs(Instruction* instruction)
</ins><span class="cx"> {
</span><del>-    int firstArg = instruction[4].u.operand;
-    int argCount = instruction[5].u.operand;
-    int registerOffset = instruction[6].u.operand;
</del><ins>+    int argCount = instruction[3].u.operand;
+    int registerOffset = instruction[4].u.operand;
</ins><span class="cx"> 
</span><ins>+    // ecx holds func
</ins><span class="cx">     emitPutArg(X86::ecx, 0);
</span><span class="cx">     emitPutArgConstant(registerOffset, 4);
</span><span class="cx">     emitPutArgConstant(argCount, 8);
</span><span class="cx">     emitPutArgConstant(reinterpret_cast&lt;unsigned&gt;(instruction), 12);
</span><del>-    if (isConstruct) {
-        emitGetPutArg(instruction[3].u.operand, 16, X86::eax);
-        emitPutArgConstant(firstArg, 20);
-    } else if (isEval)
-        emitGetPutArg(instruction[3].u.operand, 16, X86::eax);
</del><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void CTI::compileOpCallEvalSetupArgs(Instruction* instruction)
+{
+    int argCount = instruction[3].u.operand;
+    int registerOffset = instruction[4].u.operand;
+
+    // ecx holds func
+    emitPutArg(X86::ecx, 0);
+    emitPutArgConstant(registerOffset, 4);
+    emitPutArgConstant(argCount, 8);
+    emitPutArgConstant(reinterpret_cast&lt;unsigned&gt;(instruction), 12);
+}
+
+void CTI::compileOpConstructSetupArgs(Instruction* instruction)
+{
+    int argCount = instruction[3].u.operand;
+    int registerOffset = instruction[4].u.operand;
+    int proto = instruction[5].u.operand;
+    int thisRegister = instruction[6].u.operand;
+
+    // ecx holds func
+    emitPutArg(X86::ecx, 0);
+    emitPutArgConstant(registerOffset, 4);
+    emitPutArgConstant(argCount, 8);
+    emitGetPutArg(proto, 12, X86::eax);
+    emitPutArgConstant(thisRegister, 16);
+    emitPutArgConstant(reinterpret_cast&lt;unsigned&gt;(instruction), 20);
+}
+
</ins><span class="cx"> void CTI::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned i, unsigned callLinkInfoIndex)
</span><span class="cx"> {
</span><span class="cx">     int dst = instruction[1].u.operand;
</span><span class="cx">     int callee = instruction[2].u.operand;
</span><del>-    int firstArg = instruction[4].u.operand;
-    int argCount = instruction[5].u.operand;
-    int registerOffset = instruction[6].u.operand;
</del><ins>+    int argCount = instruction[3].u.operand;
+    int registerOffset = instruction[4].u.operand;
</ins><span class="cx"> 
</span><del>-    // Setup this value as the first argument (does not apply to constructors)
-    if (opcodeID != op_construct) {
-        int thisVal = instruction[3].u.operand;
-        if (thisVal == missingThisObjectMarker())
-            m_jit.movl_i32m(asInteger(jsNull()), firstArg * sizeof(Register), X86::edi);
-        else {
-            emitGetArg(thisVal, X86::eax);
-            emitPutResult(firstArg);
-        }
-    }
-
</del><span class="cx">     // Handle eval
</span><span class="cx">     X86Assembler::JmpSrc wasEval;
</span><span class="cx">     if (opcodeID == op_call_eval) {
</span><span class="cx">         emitGetArg(callee, X86::ecx);
</span><del>-        compileOpCallSetupArgs(instruction, false, true);
</del><ins>+        compileOpCallEvalSetupArgs(instruction);
</ins><span class="cx"> 
</span><span class="cx">         emitCTICall(instruction, i, Machine::cti_op_call_eval);
</span><span class="cx">         m_jit.cmpl_i32r(asInteger(JSImmediate::impossibleValue()), X86::eax);
</span><span class="lines">@@ -647,10 +658,13 @@
</span><span class="cx"> 
</span><span class="cx">     // In the case of OpConstruct, call out to a cti_ function to create the new object.
</span><span class="cx">     if (opcodeID == op_construct) {
</span><ins>+        int proto = instruction[5].u.operand;
+        int thisRegister = instruction[6].u.operand;
+
</ins><span class="cx">         emitPutArg(X86::ecx, 0);
</span><del>-        emitGetPutArg(instruction[3].u.operand, 16, X86::eax);
</del><ins>+        emitGetPutArg(proto, 12, X86::eax);
</ins><span class="cx">         emitCTICall(instruction, i, Machine::cti_op_construct_JSConstruct);
</span><del>-        emitPutResult(firstArg);
</del><ins>+        emitPutResult(thisRegister);
</ins><span class="cx">         emitGetArg(callee, X86::ecx);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1285,9 +1299,11 @@
</span><span class="cx">             i += 3;
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-        case op_call: {
</del><ins>+        case op_call:
+        case op_call_eval:
+        case op_construct: {
</ins><span class="cx">             compileOpCall(opcodeID, instruction + i, i, callLinkInfoIndex++);
</span><del>-            i += 7;
</del><ins>+            i += (opcodeID == op_construct ? 7 : 5);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_get_global_var: {
</span><span class="lines">@@ -1381,11 +1397,6 @@
</span><span class="cx">             i += 3;
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-        case op_construct: {
-            compileOpCall(opcodeID, instruction + i, i, callLinkInfoIndex++);
-            i += 7;
-            break;
-        }
</del><span class="cx">         case op_construct_verify: {
</span><span class="cx">             emitGetArg(instruction[i + 1].u.operand, X86::eax);
</span><span class="cx">             
</span><span class="lines">@@ -1913,11 +1924,6 @@
</span><span class="cx">             i += 5;
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-        case op_call_eval: {
-            compileOpCall(opcodeID, instruction + i, i, callLinkInfoIndex++);
-            i += 7;
-            break;
-        }
</del><span class="cx">         case op_throw: {
</span><span class="cx">             emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
</span><span class="cx">             emitCTICall(instruction + i, i, Machine::cti_op_throw);
</span><span class="lines">@@ -2767,15 +2773,16 @@
</span><span class="cx">         case op_construct: {
</span><span class="cx">             int dst = instruction[i + 1].u.operand;
</span><span class="cx">             int callee = instruction[i + 2].u.operand;
</span><del>-            int firstArg = instruction[i + 4].u.operand;
-            int argCount = instruction[i + 5].u.operand;
-            int registerOffset = instruction[i + 6].u.operand;
</del><ins>+            int argCount = instruction[i + 3].u.operand;
+            int registerOffset = instruction[i + 4].u.operand;
</ins><span class="cx"> 
</span><span class="cx">             m_jit.link(iter-&gt;from, m_jit.label());
</span><span class="cx"> 
</span><span class="cx">             // The arguments have been set up on the hot path for op_call_eval
</span><del>-            if (opcodeID != op_call_eval)
-                compileOpCallSetupArgs(instruction + i, (opcodeID == op_construct), false);
</del><ins>+            if (opcodeID == op_call)
+                compileOpCallSetupArgs(instruction + i);
+            else if (opcodeID == op_construct)
+                compileOpConstructSetupArgs(instruction + i);
</ins><span class="cx"> 
</span><span class="cx">             // Fast check for JS function.
</span><span class="cx">             m_jit.testl_i32r(JSImmediate::TagMask, X86::ecx);
</span><span class="lines">@@ -2783,10 +2790,10 @@
</span><span class="cx">             m_jit.cmpl_i32m(reinterpret_cast&lt;unsigned&gt;(m_machine-&gt;m_jsFunctionVptr), X86::ecx);
</span><span class="cx">             X86Assembler::JmpSrc callLinkFailNotJSFunction = m_jit.emitUnlinkedJne();
</span><span class="cx"> 
</span><del>-            // First, in the cale of a construct, allocate the new object.
</del><ins>+            // First, in the case of a construct, allocate the new object.
</ins><span class="cx">             if (opcodeID == op_construct) {
</span><span class="cx">                 emitCTICall(instruction, i, Machine::cti_op_construct_JSConstruct);
</span><del>-                emitPutResult(firstArg);
</del><ins>+                emitPutResult(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
</ins><span class="cx">                 emitGetArg(callee, X86::ecx);
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="lines">@@ -2827,8 +2834,10 @@
</span><span class="cx">             m_callStructureStubCompilationInfo[callLinkInfoIndex].coldPathOther = m_jit.label();
</span><span class="cx"> 
</span><span class="cx">             // The arguments have been set up on the hot path for op_call_eval
</span><del>-            if (opcodeID != op_call_eval)
-                compileOpCallSetupArgs(instruction + i, (opcodeID == op_construct), false);
</del><ins>+            if (opcodeID == op_call)
+                compileOpCallSetupArgs(instruction + i);
+            else if (opcodeID == op_construct)
+                compileOpConstructSetupArgs(instruction + i);
</ins><span class="cx"> 
</span><span class="cx">             // Check for JSFunctions.
</span><span class="cx">             m_jit.testl_i32r(JSImmediate::TagMask, X86::ecx);
</span><span class="lines">@@ -2847,10 +2856,10 @@
</span><span class="cx">             // Next, handle JSFunctions...
</span><span class="cx">             m_jit.link(isJSFunction, m_jit.label());
</span><span class="cx"> 
</span><del>-            // First, in the cale of a construct, allocate the new object.
</del><ins>+            // First, in the case of a construct, allocate the new object.
</ins><span class="cx">             if (opcodeID == op_construct) {
</span><span class="cx">                 emitCTICall(instruction, i, Machine::cti_op_construct_JSConstruct);
</span><del>-                emitPutResult(firstArg);
</del><ins>+                emitPutResult(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
</ins><span class="cx">                 emitGetArg(callee, X86::ecx);
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="lines">@@ -2895,7 +2904,7 @@
</span><span class="cx"> #endif
</span><span class="cx">             ++callLinkInfoIndex;
</span><span class="cx"> 
</span><del>-            i += 7;
</del><ins>+            i += (opcodeID == op_construct ? 7 : 5);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_to_jsnumber: {
</span></span></pre></div>
<a id="trunkJavaScriptCoreVMCTIh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/VM/CTI.h (38321 => 38322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/VM/CTI.h        2008-11-12 00:28:57 UTC (rev 38321)
+++ trunk/JavaScriptCore/VM/CTI.h        2008-11-12 00:32:38 UTC (rev 38322)
</span><span class="lines">@@ -365,7 +365,9 @@
</span><span class="cx"> 
</span><span class="cx">         void compileOpCall(OpcodeID, Instruction* instruction, unsigned i, unsigned callLinkInfoIndex);
</span><span class="cx">         void compileOpCallInitializeCallFrame(unsigned callee, unsigned argCount);
</span><del>-        void compileOpCallSetupArgs(Instruction* instruction, bool isConstruct, bool isEval);
</del><ins>+        void compileOpCallSetupArgs(Instruction*);
+        void compileOpCallEvalSetupArgs(Instruction*);
+        void compileOpConstructSetupArgs(Instruction*);
</ins><span class="cx">         enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq };
</span><span class="cx">         void compileOpStrictEq(Instruction* instruction, unsigned i, CompileOpStrictEqType type);
</span><span class="cx">         void putDoubleResultToJSNumberCellOrJSImmediate(X86::XMMRegisterID xmmSource, X86::RegisterID jsNumberCell, unsigned dst, X86Assembler::JmpSrc* wroteJSNumberCell,  X86::XMMRegisterID tempXmm, X86::RegisterID tempReg1, X86::RegisterID tempReg2);
</span></span></pre></div>
<a id="trunkJavaScriptCoreVMCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/VM/CodeBlock.cpp (38321 => 38322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/VM/CodeBlock.cpp        2008-11-12 00:28:57 UTC (rev 38321)
+++ trunk/JavaScriptCore/VM/CodeBlock.cpp        2008-11-12 00:32:38 UTC (rev 38322)
</span><span class="lines">@@ -812,23 +812,19 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_call: {
</span><del>-            int r0 = (++it)-&gt;u.operand;
-            int r1 = (++it)-&gt;u.operand;
-            int r2 = (++it)-&gt;u.operand;
-            int tempCount = (++it)-&gt;u.operand;
</del><ins>+            int dst = (++it)-&gt;u.operand;
+            int func = (++it)-&gt;u.operand;
</ins><span class="cx">             int argCount = (++it)-&gt;u.operand;
</span><span class="cx">             int registerOffset = (++it)-&gt;u.operand;
</span><del>-            printf(&quot;[%4d] call\t\t %s, %s, %s, %d, %d, %d\n&quot;, location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount, registerOffset);
</del><ins>+            printf(&quot;[%4d] call\t\t %s, %s, %d, %d\n&quot;, location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_call_eval: {
</span><del>-            int r0 = (++it)-&gt;u.operand;
-            int r1 = (++it)-&gt;u.operand;
-            int r2 = (++it)-&gt;u.operand;
-            int tempCount = (++it)-&gt;u.operand;
</del><ins>+            int dst = (++it)-&gt;u.operand;
+            int func = (++it)-&gt;u.operand;
</ins><span class="cx">             int argCount = (++it)-&gt;u.operand;
</span><span class="cx">             int registerOffset = (++it)-&gt;u.operand;
</span><del>-            printf(&quot;[%4d] call_eval\t\t %s, %s, %s, %d, %d, %d\n&quot;, location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount, registerOffset);
</del><ins>+            printf(&quot;[%4d] call_eval\t %s, %s, %d, %d\n&quot;, location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_tear_off_activation: {
</span><span class="lines">@@ -846,13 +842,13 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_construct: {
</span><del>-            int r0 = (++it)-&gt;u.operand;
-            int r1 = (++it)-&gt;u.operand;
-            int r2 = (++it)-&gt;u.operand;
-            int tempCount = (++it)-&gt;u.operand;
</del><ins>+            int dst = (++it)-&gt;u.operand;
+            int func = (++it)-&gt;u.operand;
</ins><span class="cx">             int argCount = (++it)-&gt;u.operand;
</span><span class="cx">             int registerOffset = (++it)-&gt;u.operand;
</span><del>-            printf(&quot;[%4d] construct\t %s, %s, %s, %d, %d, %d\n&quot;, location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount, registerOffset);
</del><ins>+            int proto = (++it)-&gt;u.operand;
+            int thisRegister = (++it)-&gt;u.operand;
+            printf(&quot;[%4d] construct\t %s, %s, %d, %d, %s, %s\n&quot;, location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset, registerName(proto).c_str(), registerName(thisRegister).c_str());
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_construct_verify: {
</span></span></pre></div>
<a id="trunkJavaScriptCoreVMMachinecpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/VM/Machine.cpp (38321 => 38322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/VM/Machine.cpp        2008-11-12 00:28:57 UTC (rev 38321)
+++ trunk/JavaScriptCore/VM/Machine.cpp        2008-11-12 00:32:38 UTC (rev 38322)
</span><span class="lines">@@ -580,24 +580,25 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-NEVER_INLINE JSValue* Machine::callEval(CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, int argv, int argc, JSValue*&amp; exceptionValue)
</del><ins>+NEVER_INLINE JSValue* Machine::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValue*&amp; exceptionValue)
</ins><span class="cx"> {
</span><span class="cx">     if (argc &lt; 2)
</span><span class="cx">         return jsUndefined();
</span><span class="cx"> 
</span><del>-    JSValue* program = callFrame[argv + 1].jsValue(callFrame);
</del><ins>+    JSValue* program = argv[1].jsValue(callFrame);
</ins><span class="cx"> 
</span><span class="cx">     if (!program-&gt;isString())
</span><span class="cx">         return program;
</span><span class="cx"> 
</span><span class="cx">     UString programSource = asString(program)-&gt;value();
</span><span class="cx"> 
</span><ins>+    ScopeChainNode* scopeChain = callFrame-&gt;scopeChain();
</ins><span class="cx">     CodeBlock* codeBlock = callFrame-&gt;codeBlock();
</span><span class="cx">     RefPtr&lt;EvalNode&gt; evalNode = codeBlock-&gt;evalCodeCache.get(callFrame, programSource, scopeChain, exceptionValue);
</span><span class="cx"> 
</span><span class="cx">     JSValue* result = jsUndefined();
</span><span class="cx">     if (evalNode)
</span><del>-        result = callFrame-&gt;globalData().machine-&gt;execute(evalNode.get(), callFrame, thisObj, callFrame-&gt;registers() - registerFile-&gt;start() + argv + 1 + RegisterFile::CallFrameHeaderSize, scopeChain, &amp;exceptionValue);
</del><ins>+        result = callFrame-&gt;globalData().machine-&gt;execute(evalNode.get(), callFrame, callFrame-&gt;thisValue()-&gt;toThisObject(callFrame), callFrame-&gt;registers() - registerFile-&gt;start() + registerOffset, scopeChain, &amp;exceptionValue);
</ins><span class="cx"> 
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="lines">@@ -655,17 +656,13 @@
</span><span class="cx"> 
</span><span class="cx"> #ifndef NDEBUG
</span><span class="cx"> 
</span><del>-void Machine::dumpCallFrame(const RegisterFile* registerFile, CallFrame* callFrame)
</del><ins>+void Machine::dumpCallFrame(CallFrame* callFrame)
</ins><span class="cx"> {
</span><del>-    JSGlobalObject* globalObject = callFrame-&gt;scopeChain()-&gt;globalObject();
-
-    CodeBlock* codeBlock = callFrame-&gt;codeBlock();
-    codeBlock-&gt;dump(globalObject-&gt;globalExec());
-
-    dumpRegisters(registerFile, callFrame);
</del><ins>+    callFrame-&gt;codeBlock()-&gt;dump(callFrame);
+    dumpRegisters(callFrame);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Machine::dumpRegisters(const RegisterFile* registerFile, CallFrame* callFrame)
</del><ins>+void Machine::dumpRegisters(CallFrame* callFrame)
</ins><span class="cx"> {
</span><span class="cx">     printf(&quot;Register frame: \n\n&quot;);
</span><span class="cx">     printf(&quot;----------------------------------------------------\n&quot;);
</span><span class="lines">@@ -673,6 +670,7 @@
</span><span class="cx">     printf(&quot;----------------------------------------------------\n&quot;);
</span><span class="cx"> 
</span><span class="cx">     CodeBlock* codeBlock = callFrame-&gt;codeBlock();
</span><ins>+    RegisterFile* registerFile = &amp;callFrame-&gt;scopeChain()-&gt;globalObject()-&gt;globalData()-&gt;machine-&gt;registerFile();
</ins><span class="cx">     const Register* it;
</span><span class="cx">     const Register* end;
</span><span class="cx"> 
</span><span class="lines">@@ -1023,7 +1021,7 @@
</span><span class="cx">     return execute(evalNode, callFrame, thisObj, m_registerFile.size() + evalNode-&gt;byteCode(scopeChain).numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSValue* Machine::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
</del><ins>+JSValue* Machine::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValue** exception)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!scopeChain-&gt;globalData-&gt;exception);
</span><span class="cx"> 
</span><span class="lines">@@ -1069,13 +1067,13 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Register* oldEnd = m_registerFile.end();
</span><del>-    Register* newEnd = m_registerFile.start() + registerOffset + codeBlock-&gt;numCalleeRegisters;
</del><ins>+    Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock-&gt;numCalleeRegisters;
</ins><span class="cx">     if (!m_registerFile.grow(newEnd)) {
</span><span class="cx">         *exception = createStackOverflowError(callFrame);
</span><span class="cx">         return jsNull();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + registerOffset);
</del><ins>+    CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset);
</ins><span class="cx"> 
</span><span class="cx">     // a 0 codeBlock indicates a built-in caller
</span><span class="cx">     newCallFrame[codeBlock-&gt;thisRegister] = thisObj;
</span><span class="lines">@@ -3264,7 +3262,7 @@
</span><span class="cx">         NEXT_OPCODE;
</span><span class="cx">     }
</span><span class="cx">     BEGIN_OPCODE(op_call_eval) {
</span><del>-        /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
</del><ins>+        /* call_eval dst(r) func(r) argCount(n) registerOffset(n)
</ins><span class="cx"> 
</span><span class="cx">            Call a function named &quot;eval&quot; with no explicit &quot;this&quot; value
</span><span class="cx">            (which may therefore be the eval operator). If register
</span><span class="lines">@@ -3277,30 +3275,28 @@
</span><span class="cx"> 
</span><span class="cx">         int dst = vPC[1].u.operand;
</span><span class="cx">         int func = vPC[2].u.operand;
</span><del>-        int thisVal = vPC[3].u.operand;
-        int firstArg = vPC[4].u.operand;
-        int argCount = vPC[5].u.operand;
</del><ins>+        int argCount = vPC[3].u.operand;
+        int registerOffset = vPC[4].u.operand;
</ins><span class="cx"> 
</span><span class="cx">         JSValue* funcVal = callFrame[func].jsValue(callFrame);
</span><del>-        JSValue* baseVal = callFrame[thisVal].jsValue(callFrame);
</del><span class="cx"> 
</span><del>-        ScopeChainNode* scopeChain = callFrame-&gt;scopeChain();
-        if (baseVal == scopeChain-&gt;globalObject() &amp;&amp; funcVal == scopeChain-&gt;globalObject()-&gt;evalFunction()) {
-            JSObject* thisObject = asObject(callFrame[callFrame-&gt;codeBlock()-&gt;thisRegister].jsValue(callFrame));
-            JSValue* result = callEval(callFrame, thisObject, scopeChain, registerFile, firstArg, argCount, exceptionValue);
</del><ins>+        Register* newCallFrame = callFrame-&gt;registers() + registerOffset;
+        Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
+        JSValue* thisValue = argv[0].jsValue(callFrame);
+        JSGlobalObject* globalObject = callFrame-&gt;scopeChain()-&gt;globalObject();
+
+        if (thisValue == globalObject &amp;&amp; funcVal == globalObject-&gt;evalFunction()) {
+            JSValue* result = callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
</ins><span class="cx">             if (exceptionValue)
</span><span class="cx">                 goto vm_throw;
</span><del>-
</del><span class="cx">             callFrame[dst] = result;
</span><span class="cx"> 
</span><del>-            vPC += 7;
</del><ins>+            vPC += 5;
</ins><span class="cx">             NEXT_OPCODE;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        // We didn't find the blessed version of eval, so reset vPC and process
-        // this instruction as a normal function call, supplying the proper 'this'
-        // value.
-        callFrame[thisVal] = baseVal-&gt;toThisObject(callFrame);
</del><ins>+        // We didn't find the blessed version of eval, so process this
+        // instruction as a normal function call.
</ins><span class="cx"> 
</span><span class="cx"> #if HAVE(COMPUTED_GOTO)
</span><span class="cx">         // Hack around gcc performance quirk by performing an indirect goto
</span><span class="lines">@@ -3311,48 +3307,20 @@
</span><span class="cx">         // fall through to op_call
</span><span class="cx">     }
</span><span class="cx">     BEGIN_OPCODE(op_call) {
</span><del>-        /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n) registerOffset(n)
</del><ins>+        /* call dst(r) func(r) argCount(n) registerOffset(n)
</ins><span class="cx"> 
</span><del>-           Perform a function call. Specifically, call register func
-           with a &quot;this&quot; value of register thisVal, and put the result
-           in register dst.
-
-           The arguments start at register firstArg and go up to
-           argCount, but the &quot;this&quot; value is considered an implicit
-           first argument, so the argCount should be one greater than
-           the number of explicit arguments passed, and the register
-           after firstArg should contain the actual first
-           argument. This opcode will copy from the thisVal register
-           to the firstArg register, unless the register index of
-           thisVal is the special missing this object marker, which is
-           2^31-1; in that case, the global object will be used as the
-           &quot;this&quot; value.
-
-           If func is a native code function, then this opcode calls
-           it and returns the value immediately. 
-
-           But if it is a JS function, then the current scope chain
-           and code block is set to the function's, and we slide the
-           register window so that the arguments would form the first
-           few local registers of the called function's register
-           window. In addition, a call frame header is written
-           immediately before the arguments; see the call frame
-           documentation for an explanation of how many registers a
-           call frame takes and what they contain. That many registers
-           before the firstArg register will be overwritten by the
-           call. In addition, any registers higher than firstArg +
-           argCount may be overwritten. Once this setup is complete,
-           execution continues from the called function's first
-           argument, and does not return until a &quot;ret&quot; opcode is
-           encountered.
</del><ins>+           Perform a function call.
+           
+           registerOffset is the distance the callFrame pointer should move
+           before the VM initializes the new call frame's header.
+           
+           dst is where op_ret should store its result.
</ins><span class="cx">          */
</span><span class="cx"> 
</span><span class="cx">         int dst = vPC[1].u.operand;
</span><span class="cx">         int func = vPC[2].u.operand;
</span><del>-        int thisVal = vPC[3].u.operand;
-        int firstArg = vPC[4].u.operand;
-        int argCount = vPC[5].u.operand;
-        int registerOffset = vPC[6].u.operand;
</del><ins>+        int argCount = vPC[3].u.operand;
+        int registerOffset = vPC[4].u.operand;
</ins><span class="cx"> 
</span><span class="cx">         JSValue* v = callFrame[func].jsValue(callFrame);
</span><span class="cx"> 
</span><span class="lines">@@ -3364,8 +3332,6 @@
</span><span class="cx">             FunctionBodyNode* functionBodyNode = callData.js.functionBody;
</span><span class="cx">             CodeBlock* newCodeBlock = &amp;functionBodyNode-&gt;byteCode(callDataScopeChain);
</span><span class="cx"> 
</span><del>-            callFrame[firstArg] = thisVal == missingThisObjectMarker() ? callFrame-&gt;globalThisValue() : callFrame[thisVal].jsValue(callFrame);
-            
</del><span class="cx">             CallFrame* previousCallFrame = callFrame;
</span><span class="cx"> 
</span><span class="cx">             callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
</span><span class="lines">@@ -3375,7 +3341,7 @@
</span><span class="cx">                 goto vm_throw;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            callFrame-&gt;init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
</del><ins>+            callFrame-&gt;init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
</ins><span class="cx">             vPC = newCodeBlock-&gt;instructions.begin();
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(OPCODE_STATS)
</span><span class="lines">@@ -3386,13 +3352,18 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (callType == CallTypeHost) {
</span><del>-            JSValue* thisValue = thisVal == missingThisObjectMarker() ? callFrame-&gt;globalThisValue() : callFrame[thisVal].jsValue(callFrame);
-            ArgList args(callFrame-&gt;registers() + firstArg + 1, argCount - 1);
-
</del><span class="cx">             ScopeChainNode* scopeChain = callFrame-&gt;scopeChain();
</span><span class="cx">             CallFrame* newCallFrame = CallFrame::create(callFrame-&gt;registers() + registerOffset);
</span><del>-            newCallFrame-&gt;init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);
</del><ins>+            newCallFrame-&gt;init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0);
</ins><span class="cx"> 
</span><ins>+            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.
+            JSValue* thisValue = thisRegister-&gt;jsValue(callFrame);
+            if (thisValue == jsNull())
+                thisValue = callFrame-&gt;globalThisValue();
+
</ins><span class="cx">             JSValue* returnValue;
</span><span class="cx">             {
</span><span class="cx">                 SamplingTool::HostCallRecord callRecord(m_sampler);
</span><span class="lines">@@ -3402,7 +3373,7 @@
</span><span class="cx"> 
</span><span class="cx">             callFrame[dst] = returnValue;
</span><span class="cx"> 
</span><del>-            vPC += 7;
</del><ins>+            vPC += 5;
</ins><span class="cx">             NEXT_OPCODE;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -3572,28 +3543,28 @@
</span><span class="cx">         NEXT_OPCODE;
</span><span class="cx">     }
</span><span class="cx">     BEGIN_OPCODE(op_construct) {
</span><del>-        /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n) registerOffset(n)
</del><ins>+        /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
</ins><span class="cx"> 
</span><del>-           Invoke register &quot;constr&quot; as a constructor. For JS
</del><ins>+           Invoke register &quot;func&quot; as a constructor. For JS
</ins><span class="cx">            functions, the calling convention is exactly as for the
</span><span class="cx">            &quot;call&quot; opcode, except that the &quot;this&quot; value is a newly
</span><del>-           created Object. For native constructors, a null &quot;this&quot;
-           value is passed. In either case, the firstArg and argCount
</del><ins>+           created Object. For native constructors, no &quot;this&quot;
+           value is passed. In either case, the argCount and registerOffset
</ins><span class="cx">            registers are interpreted as for the &quot;call&quot; opcode.
</span><span class="cx"> 
</span><del>-           Register constrProto must contain the prototype property of
-           register constsr. This is to enable polymorphic inline
</del><ins>+           Register proto must contain the prototype property of
+           register func. This is to enable polymorphic inline
</ins><span class="cx">            caching of this lookup.
</span><span class="cx">         */
</span><span class="cx"> 
</span><span class="cx">         int dst = vPC[1].u.operand;
</span><del>-        int constr = vPC[2].u.operand;
-        int constrProto = vPC[3].u.operand;
-        int firstArg = vPC[4].u.operand;
-        int argCount = vPC[5].u.operand;
-        int registerOffset = vPC[6].u.operand;
</del><ins>+        int func = vPC[2].u.operand;
+        int argCount = vPC[3].u.operand;
+        int registerOffset = vPC[4].u.operand;
+        int proto = vPC[5].u.operand;
+        int thisRegister = vPC[6].u.operand;
</ins><span class="cx"> 
</span><del>-        JSValue* v = callFrame[constr].jsValue(callFrame);
</del><ins>+        JSValue* v = callFrame[func].jsValue(callFrame);
</ins><span class="cx"> 
</span><span class="cx">         ConstructData constructData;
</span><span class="cx">         ConstructType constructType = v-&gt;getConstructData(constructData);
</span><span class="lines">@@ -3604,14 +3575,14 @@
</span><span class="cx">             CodeBlock* newCodeBlock = &amp;functionBodyNode-&gt;byteCode(callDataScopeChain);
</span><span class="cx"> 
</span><span class="cx">             StructureID* structure;
</span><del>-            JSValue* prototype = callFrame[constrProto].jsValue(callFrame);
</del><ins>+            JSValue* prototype = callFrame[proto].jsValue(callFrame);
</ins><span class="cx">             if (prototype-&gt;isObject())
</span><span class="cx">                 structure = asObject(prototype)-&gt;inheritorID();
</span><span class="cx">             else
</span><span class="cx">                 structure = callDataScopeChain-&gt;globalObject()-&gt;emptyObjectStructure();
</span><span class="cx">             JSObject* newObject = new (globalData) JSObject(structure);
</span><span class="cx"> 
</span><del>-            callFrame[firstArg] = newObject; // &quot;this&quot; value
</del><ins>+            callFrame[thisRegister] = newObject; // &quot;this&quot; value
</ins><span class="cx"> 
</span><span class="cx">             CallFrame* previousCallFrame = callFrame;
</span><span class="cx"> 
</span><span class="lines">@@ -3633,7 +3604,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (constructType == ConstructTypeHost) {
</span><del>-            ArgList args(callFrame-&gt;registers() + firstArg + 1, argCount - 1);
</del><ins>+            ArgList args(callFrame-&gt;registers() + thisRegister + 1, argCount - 1);
</ins><span class="cx"> 
</span><span class="cx">             ScopeChainNode* scopeChain = callFrame-&gt;scopeChain();
</span><span class="cx">             CallFrame* newCallFrame = CallFrame::create(callFrame-&gt;registers() + registerOffset);
</span><span class="lines">@@ -4364,6 +4335,18 @@
</span><span class="cx">         } \
</span><span class="cx">     } while (0)
</span><span class="cx"> 
</span><ins>+// This macro rewinds to the previous call frame because CTI functions that
+// throw stack overflow exceptions execute after the call frame has
+// optimistically moved forward.
+#define CTI_THROW_STACK_OVERFLOW() do { \
+    CallFrame* oldCallFrame = ARG_callFrame-&gt;callerFrame(); \
+    JSGlobalData* globalData = ARG_globalData; \
+    globalData-&gt;exception = createStackOverflowError(oldCallFrame); \
+    globalData-&gt;throwReturnAddress = CTI_RETURN_ADDRESS; \
+    ARG_setCallFrame(oldCallFrame); \
+    CTI_SET_RETURN_ADDRESS(reinterpret_cast&lt;void*&gt;(ctiVMThrowTrampoline)); \
+} while (0);
+
</ins><span class="cx"> JSObject* Machine::cti_op_convert_this(CTI_ARGS)
</span><span class="cx"> {
</span><span class="cx">     CTI_STACK_HACK();
</span><span class="lines">@@ -4452,13 +4435,6 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-NEVER_INLINE void Machine::throwStackOverflowPreviousFrame(CallFrame* callFrame, JSGlobalData* globalData, void*&amp; returnAddress)
-{
-    globalData-&gt;exception = createStackOverflowError(callFrame-&gt;callerFrame());
-    globalData-&gt;throwReturnAddress = callFrame-&gt;returnPC();
-    ctiSetReturnAddress(&amp;returnAddress, reinterpret_cast&lt;void*&gt;(ctiVMThrowTrampoline));
-}
-
</del><span class="cx"> void Machine::cti_register_file_check(CTI_ARGS)
</span><span class="cx"> {
</span><span class="cx">     CTI_STACK_HACK();
</span><span class="lines">@@ -4466,8 +4442,7 @@
</span><span class="cx">     if (LIKELY(ARG_registerFile-&gt;grow(ARG_callFrame + ARG_callFrame-&gt;codeBlock()-&gt;numCalleeRegisters)))
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    ARG_setCallFrame(ARG_callFrame-&gt;callerFrame());
-    throwStackOverflowPreviousFrame(ARG_callFrame, ARG_globalData, CTI_RETURN_ADDRESS);
</del><ins>+    CTI_THROW_STACK_OVERFLOW();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> int Machine::cti_op_loop_if_less(CTI_ARGS)
</span><span class="lines">@@ -4744,8 +4719,9 @@
</span><span class="cx">         Register* r = callFrame-&gt;registers() + omittedArgCount;
</span><span class="cx">         Register* newEnd = r + newCodeBlock-&gt;numCalleeRegisters;
</span><span class="cx">         if (!ARG_registerFile-&gt;grow(newEnd)) {
</span><del>-            ARG_globalData-&gt;exception = createStackOverflowError(oldCallFrame);
-            VM_THROW_EXCEPTION_2();
</del><ins>+            CTI_THROW_STACK_OVERFLOW();
+            VoidPtrPairValue pair = {{ 0, 0 }};
+            return pair.i;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
</span><span class="lines">@@ -4810,7 +4786,7 @@
</span><span class="cx">         {
</span><span class="cx">             SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
</span><span class="cx"> 
</span><del>-            // All host methods should be calling toThisObject, but this is not presently the case.
</del><ins>+            // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
</ins><span class="cx">             JSValue* thisValue = argv[0].jsValue(callFrame);
</span><span class="cx">             if (thisValue == jsNull())
</span><span class="cx">                 thisValue = callFrame-&gt;globalThisValue();
</span><span class="lines">@@ -4934,8 +4910,8 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     StructureID* structure;
</span><del>-    if (ARG_src5-&gt;isObject())
-        structure = asObject(ARG_src5)-&gt;inheritorID();
</del><ins>+    if (ARG_src4-&gt;isObject())
+        structure = asObject(ARG_src4)-&gt;inheritorID();
</ins><span class="cx">     else
</span><span class="cx">         structure = asFunction(ARG_src1)-&gt;m_scopeChain.node()-&gt;globalObject()-&gt;emptyObjectStructure();
</span><span class="cx">     return new (ARG_globalData) JSObject(structure);
</span><span class="lines">@@ -4949,13 +4925,13 @@
</span><span class="cx"> 
</span><span class="cx">     JSValue* constrVal = ARG_src1;
</span><span class="cx">     int argCount = ARG_int3;
</span><del>-    int firstArg = ARG_int6;
</del><ins>+    int thisRegister = ARG_int5;
</ins><span class="cx"> 
</span><span class="cx">     ConstructData constructData;
</span><span class="cx">     ConstructType constructType = constrVal-&gt;getConstructData(constructData);
</span><span class="cx"> 
</span><span class="cx">     if (constructType == ConstructTypeHost) {
</span><del>-        ArgList argList(callFrame-&gt;registers() + firstArg + 1, argCount - 1);
</del><ins>+        ArgList argList(callFrame-&gt;registers() + thisRegister + 1, argCount - 1);
</ins><span class="cx"> 
</span><span class="cx">         JSValue* returnValue;
</span><span class="cx">         {
</span><span class="lines">@@ -4969,7 +4945,7 @@
</span><span class="cx"> 
</span><span class="cx">     ASSERT(constructType == ConstructTypeNone);
</span><span class="cx"> 
</span><del>-    ARG_globalData-&gt;exception = createNotAConstructorError(callFrame, constrVal, ARG_instr4, callFrame-&gt;codeBlock());
</del><ins>+    ARG_globalData-&gt;exception = createNotAConstructorError(callFrame, constrVal, ARG_instr6, callFrame-&gt;codeBlock());
</ins><span class="cx">     VM_THROW_EXCEPTION();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -5568,20 +5544,21 @@
</span><span class="cx"> 
</span><span class="cx">     CallFrame* callFrame = ARG_callFrame;
</span><span class="cx">     RegisterFile* registerFile = ARG_registerFile;
</span><del>-    CodeBlock* codeBlock = callFrame-&gt;codeBlock();
-    ScopeChainNode* scopeChain = callFrame-&gt;scopeChain();
</del><span class="cx"> 
</span><span class="cx">     Machine* machine = ARG_globalData-&gt;machine;
</span><span class="cx">     
</span><span class="cx">     JSValue* funcVal = ARG_src1;
</span><span class="cx">     int registerOffset = ARG_int2;
</span><span class="cx">     int argCount = ARG_int3;
</span><del>-    JSValue* baseVal = ARG_src5;
</del><span class="cx"> 
</span><del>-    if (baseVal == scopeChain-&gt;globalObject() &amp;&amp; funcVal == scopeChain-&gt;globalObject()-&gt;evalFunction()) {
-        JSObject* thisObject = callFrame[codeBlock-&gt;thisRegister].jsValue(callFrame)-&gt;toThisObject(callFrame);
</del><ins>+    Register* newCallFrame = callFrame-&gt;registers() + registerOffset;
+    Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
+    JSValue* thisValue = argv[0].jsValue(callFrame);
+    JSGlobalObject* globalObject = callFrame-&gt;scopeChain()-&gt;globalObject();
+
+    if (thisValue == globalObject &amp;&amp; funcVal == globalObject-&gt;evalFunction()) {
</ins><span class="cx">         JSValue* exceptionValue = noValue();
</span><del>-        JSValue* result = machine-&gt;callEval(callFrame, thisObject, scopeChain, registerFile, registerOffset - RegisterFile::CallFrameHeaderSize - argCount, argCount, exceptionValue);
</del><ins>+        JSValue* result = machine-&gt;callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
</ins><span class="cx">         if (UNLIKELY(exceptionValue != noValue())) {
</span><span class="cx">             ARG_globalData-&gt;exception = exceptionValue;
</span><span class="cx">             VM_THROW_EXCEPTION_AT_END();
</span><span class="lines">@@ -5944,15 +5921,16 @@
</span><span class="cx"> 
</span><span class="cx">     CallFrame* callFrame = ARG_callFrame;
</span><span class="cx">     CodeBlock* codeBlock = callFrame-&gt;codeBlock();
</span><ins>+    JSGlobalData* globalData = ARG_globalData;
</ins><span class="cx"> 
</span><del>-    ASSERT(codeBlock-&gt;ctiReturnAddressVPCMap.contains(ARG_globalData-&gt;throwReturnAddress));
-    unsigned vPCIndex = codeBlock-&gt;ctiReturnAddressVPCMap.get(ARG_globalData-&gt;throwReturnAddress);
</del><ins>+    ASSERT(codeBlock-&gt;ctiReturnAddressVPCMap.contains(globalData-&gt;throwReturnAddress));
+    unsigned vPCIndex = codeBlock-&gt;ctiReturnAddressVPCMap.get(globalData-&gt;throwReturnAddress);
</ins><span class="cx"> 
</span><del>-    JSValue* exceptionValue = ARG_globalData-&gt;exception;
</del><ins>+    JSValue* exceptionValue = globalData-&gt;exception;
</ins><span class="cx">     ASSERT(exceptionValue);
</span><del>-    ARG_globalData-&gt;exception = noValue();
</del><ins>+    globalData-&gt;exception = noValue();
</ins><span class="cx"> 
</span><del>-    Instruction* handlerVPC = ARG_globalData-&gt;machine-&gt;throwException(callFrame, exceptionValue, codeBlock-&gt;instructions.begin() + vPCIndex, false);
</del><ins>+    Instruction* handlerVPC = globalData-&gt;machine-&gt;throwException(callFrame, exceptionValue, codeBlock-&gt;instructions.begin() + vPCIndex, false);
</ins><span class="cx"> 
</span><span class="cx">     if (!handlerVPC) {
</span><span class="cx">         *ARG_exception = exceptionValue;
</span></span></pre></div>
<a id="trunkJavaScriptCoreVMMachineh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/VM/Machine.h (38321 => 38322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/VM/Machine.h        2008-11-12 00:28:57 UTC (rev 38321)
+++ trunk/JavaScriptCore/VM/Machine.h        2008-11-12 00:32:38 UTC (rev 38322)
</span><span class="lines">@@ -284,8 +284,8 @@
</span><span class="cx">     private:
</span><span class="cx">         enum ExecutionFlag { Normal, InitializeAndReturn };
</span><span class="cx"> 
</span><del>-        NEVER_INLINE JSValue* callEval(CallFrame*, JSObject* thisObject, ScopeChainNode*, RegisterFile*, int argv, int argc, JSValue*&amp; exceptionValue);
-        JSValue* execute(EvalNode*, CallFrame*, JSObject* thisObject, int registerOffset, ScopeChainNode*, JSValue** exception);
</del><ins>+        NEVER_INLINE JSValue* callEval(CallFrame*, RegisterFile*, Register* argv, int argc, int registerOffset, JSValue*&amp; exceptionValue);
+        JSValue* execute(EvalNode*, CallFrame*, JSObject* thisObject, int globalRegisterOffset, ScopeChainNode*, JSValue** exception);
</ins><span class="cx"> 
</span><span class="cx">         NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine);
</span><span class="cx"> 
</span><span class="lines">@@ -306,8 +306,8 @@
</span><span class="cx"> 
</span><span class="cx">         JSValue* privateExecute(ExecutionFlag, RegisterFile*, CallFrame*, JSValue** exception);
</span><span class="cx"> 
</span><del>-        void dumpCallFrame(const RegisterFile*, CallFrame*);
-        void dumpRegisters(const RegisterFile*, CallFrame*);
</del><ins>+        void dumpCallFrame(CallFrame*);
+        void dumpRegisters(CallFrame*);
</ins><span class="cx"> 
</span><span class="cx">         JSValue* checkTimeout(JSGlobalObject*);
</span><span class="cx">         void resetTimeoutCheck();
</span><span class="lines">@@ -320,7 +320,7 @@
</span><span class="cx">         bool isCallOpcode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval); }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CTI)
</span><del>-        static void throwStackOverflowPreviousFrame(CallFrame*, JSGlobalData*, void*&amp; returnAddress);
</del><ins>+        static void throwStackOverflowPreviousFrame(CallFrame**, JSGlobalData*, void*&amp; returnAddress);
</ins><span class="cx"> 
</span><span class="cx">         void tryCTICacheGetByID(CallFrame*, CodeBlock*, void* returnAddress, JSValue* baseValue, const Identifier&amp; propertyName, const PropertySlot&amp;);
</span><span class="cx">         void tryCTICachePutByID(CallFrame*, CodeBlock*, void* returnAddress, JSValue* baseValue, const PutPropertySlot&amp;);
</span></span></pre></div>
<a id="trunkJavaScriptCorebytecompilerCodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/bytecompiler/CodeGenerator.cpp (38321 => 38322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/bytecompiler/CodeGenerator.cpp        2008-11-12 00:28:57 UTC (rev 38321)
+++ trunk/JavaScriptCore/bytecompiler/CodeGenerator.cpp        2008-11-12 00:32:38 UTC (rev 38322)
</span><span class="lines">@@ -1219,25 +1219,24 @@
</span><span class="cx">     return r0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RegisterID* CodeGenerator::emitCall(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
</del><ins>+RegisterID* CodeGenerator::emitCall(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
</ins><span class="cx"> {
</span><del>-    return emitCall(op_call, dst, func, base, argumentsNode, divot, startOffset, endOffset);
</del><ins>+    return emitCall(op_call, dst, func, thisRegister, argumentsNode, divot, startOffset, endOffset);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-RegisterID* CodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
</del><ins>+RegisterID* CodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
</ins><span class="cx"> {
</span><del>-    return emitCall(op_call_eval, dst, func, base, argumentsNode, divot, startOffset, endOffset);
</del><ins>+    return emitCall(op_call_eval, dst, func, thisRegister, argumentsNode, divot, startOffset, endOffset);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
</del><ins>+RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(opcodeID == op_call || opcodeID == op_call_eval);
</span><span class="cx">     ASSERT(func-&gt;refCount());
</span><del>-    ASSERT(!base || base-&gt;refCount());
</del><span class="cx">     
</span><span class="cx">     // Generate code for arguments.
</span><span class="cx">     Vector&lt;RefPtr&lt;RegisterID&gt;, 16&gt; argv;
</span><del>-    argv.append(newTemporary()); // reserve space for &quot;this&quot;
</del><ins>+    argv.append(thisRegister);
</ins><span class="cx">     for (ArgumentListNode* n = argumentsNode-&gt;m_listNode.get(); n; n = n-&gt;m_next.get()) {
</span><span class="cx">         argv.append(newTemporary());
</span><span class="cx">         emitNode(argv.last().get(), n);
</span><span class="lines">@@ -1255,12 +1254,12 @@
</span><span class="cx"> 
</span><span class="cx">     emitExpressionInfo(divot, startOffset, endOffset);
</span><span class="cx">     m_codeBlock-&gt;callLinkInfos.append(CallLinkInfo());
</span><ins>+
+    // Emit call.
</ins><span class="cx">     emitOpcode(opcodeID);
</span><del>-    instructions().append(dst-&gt;index());
-    instructions().append(func-&gt;index());
-    instructions().append(base ? base-&gt;index() : missingThisObjectMarker()); // We encode the &quot;this&quot; value in the instruction stream, to avoid an explicit instruction for copying or loading it.
-    instructions().append(argv[0]-&gt;index()); // argv
-    instructions().append(argv.size()); // argc
</del><ins>+    instructions().append(dst-&gt;index()); // dst
+    instructions().append(func-&gt;index()); // func
+    instructions().append(argv.size()); // argCount
</ins><span class="cx">     instructions().append(argv[0]-&gt;index() + argv.size() + RegisterFile::CallFrameHeaderSize); // registerOffset
</span><span class="cx"> 
</span><span class="cx">     if (m_shouldEmitProfileHooks) {
</span><span class="lines">@@ -1319,13 +1318,14 @@
</span><span class="cx"> 
</span><span class="cx">     emitExpressionInfo(divot, startOffset, endOffset);
</span><span class="cx">     m_codeBlock-&gt;callLinkInfos.append(CallLinkInfo());
</span><ins>+
</ins><span class="cx">     emitOpcode(op_construct);
</span><del>-    instructions().append(dst-&gt;index());
-    instructions().append(func-&gt;index());
-    instructions().append(funcProto-&gt;index());
-    instructions().append(argv[0]-&gt;index()); // argv
-    instructions().append(argv.size()); // argc
</del><ins>+    instructions().append(dst-&gt;index()); // dst
+    instructions().append(func-&gt;index()); // func
+    instructions().append(argv.size()); // argCount
</ins><span class="cx">     instructions().append(argv[0]-&gt;index() + argv.size() + RegisterFile::CallFrameHeaderSize); // registerOffset
</span><ins>+    instructions().append(funcProto-&gt;index()); // proto
+    instructions().append(argv[0]-&gt;index()); // thisRegister
</ins><span class="cx"> 
</span><span class="cx">     emitOpcode(op_construct_verify);
</span><span class="cx">     instructions().append(dst-&gt;index());
</span></span></pre></div>
<a id="trunkJavaScriptCorebytecompilerCodeGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/bytecompiler/CodeGenerator.h (38321 => 38322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/bytecompiler/CodeGenerator.h        2008-11-12 00:28:57 UTC (rev 38321)
+++ trunk/JavaScriptCore/bytecompiler/CodeGenerator.h        2008-11-12 00:32:38 UTC (rev 38322)
</span><span class="lines">@@ -273,8 +273,8 @@
</span><span class="cx">         RegisterID* emitPutGetter(RegisterID* base, const Identifier&amp; property, RegisterID* value);
</span><span class="cx">         RegisterID* emitPutSetter(RegisterID* base, const Identifier&amp; property, RegisterID* value);
</span><span class="cx"> 
</span><del>-        RegisterID* emitCall(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
-        RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
</del><ins>+        RegisterID* emitCall(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+        RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
</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">@@ -345,7 +345,7 @@
</span><span class="cx">         typedef HashMap&lt;double, JSValue*&gt; NumberMap;
</span><span class="cx">         typedef HashMap&lt;UString::Rep*, JSString*, IdentifierRepHash&gt; IdentifierStringMap;
</span><span class="cx"> 
</span><del>-        RegisterID* emitCall(OpcodeID, RegisterID*, RegisterID*, RegisterID*, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
</del><ins>+        RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
</ins><span class="cx">         
</span><span class="cx">         RegisterID* newRegister();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkJavaScriptCoreparserNodescpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/parser/Nodes.cpp (38321 => 38322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/parser/Nodes.cpp        2008-11-12 00:28:57 UTC (rev 38321)
+++ trunk/JavaScriptCore/parser/Nodes.cpp        2008-11-12 00:32:38 UTC (rev 38322)
</span><span class="lines">@@ -585,10 +585,10 @@
</span><span class="cx"> 
</span><span class="cx"> RegisterID* EvalFunctionCallNode::emitCode(CodeGenerator&amp; generator, RegisterID* dst)
</span><span class="cx"> {
</span><del>-    RefPtr&lt;RegisterID&gt; base = generator.tempDestination(dst);
-    RefPtr&lt;RegisterID&gt; func = generator.newTemporary();
-    generator.emitResolveWithBase(base.get(), func.get(), generator.propertyNames().eval);
-    return generator.emitCallEval(generator.finalDestination(dst, base.get()), func.get(), base.get(), m_args.get(), divot(), startOffset(), endOffset());
</del><ins>+    RefPtr&lt;RegisterID&gt; func = generator.tempDestination(dst);
+    RefPtr&lt;RegisterID&gt; thisRegister = generator.newTemporary();
+    generator.emitResolveWithBase(thisRegister.get(), func.get(), generator.propertyNames().eval);
+    return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ FunctionCallValueNode ----------------------------------
</span><span class="lines">@@ -607,7 +607,8 @@
</span><span class="cx"> RegisterID* FunctionCallValueNode::emitCode(CodeGenerator&amp; generator, RegisterID* dst)
</span><span class="cx"> {
</span><span class="cx">     RefPtr&lt;RegisterID&gt; func = generator.emitNode(m_expr.get());
</span><del>-    return generator.emitCall(generator.finalDestination(dst), func.get(), 0, m_args.get(), divot(), startOffset(), endOffset());
</del><ins>+    RefPtr&lt;RegisterID&gt; thisRegister = generator.emitLoad(generator.newTemporary(), jsNull());
+    return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ FunctionCallResolveNode ----------------------------------
</span><span class="lines">@@ -624,23 +625,26 @@
</span><span class="cx"> 
</span><span class="cx"> RegisterID* FunctionCallResolveNode::emitCode(CodeGenerator&amp; generator, RegisterID* dst)
</span><span class="cx"> {
</span><del>-    if (RefPtr&lt;RegisterID&gt; local = generator.registerFor(m_ident))
-        return generator.emitCall(generator.finalDestination(dst), local.get(), 0, m_args.get(), divot(), startOffset(), endOffset());
</del><ins>+    if (RefPtr&lt;RegisterID&gt; local = generator.registerFor(m_ident)) {
+        RefPtr&lt;RegisterID&gt; thisRegister = generator.emitLoad(generator.newTemporary(), jsNull());
+        return generator.emitCall(generator.finalDestination(dst, thisRegister.get()), local.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset());
+    }
</ins><span class="cx"> 
</span><span class="cx">     int index = 0;
</span><span class="cx">     size_t depth = 0;
</span><span class="cx">     JSObject* globalObject = 0;
</span><span class="cx">     if (generator.findScopedProperty(m_ident, index, depth, false, globalObject) &amp;&amp; index != missingSymbolMarker()) {
</span><span class="cx">         RefPtr&lt;RegisterID&gt; func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject);
</span><del>-        return generator.emitCall(generator.finalDestination(dst), func.get(), 0, m_args.get(), divot(), startOffset(), endOffset());
</del><ins>+        RefPtr&lt;RegisterID&gt; thisRegister = generator.emitLoad(generator.newTemporary(), jsNull());
+        return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    RefPtr&lt;RegisterID&gt; base = generator.tempDestination(dst);
-    RefPtr&lt;RegisterID&gt; func = generator.newTemporary();
</del><ins>+    RefPtr&lt;RegisterID&gt; func = generator.tempDestination(dst);
+    RefPtr&lt;RegisterID&gt; thisRegister = generator.newTemporary();
</ins><span class="cx">     int identifierStart = divot() - startOffset();
</span><span class="cx">     generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0);
</span><del>-    generator.emitResolveFunction(base.get(), func.get(), m_ident);
-    return generator.emitCall(generator.finalDestination(dst, base.get()), func.get(), base.get(), m_args.get(), divot(), startOffset(), endOffset());
</del><ins>+    generator.emitResolveFunction(thisRegister.get(), func.get(), m_ident);
+    return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ FunctionCallBracketNode ----------------------------------
</span><span class="lines">@@ -662,8 +666,9 @@
</span><span class="cx">     RefPtr&lt;RegisterID&gt; base = generator.emitNode(m_base.get());
</span><span class="cx">     RegisterID* property = generator.emitNode(m_subscript.get());
</span><span class="cx">     generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset);
</span><del>-    RefPtr&lt;RegisterID&gt; function = generator.emitGetByVal(generator.newTemporary(), base.get(), property);
-    return generator.emitCall(generator.finalDestination(dst, base.get()), function.get(), base.get(), m_args.get(), divot(), startOffset(), endOffset());
</del><ins>+    RefPtr&lt;RegisterID&gt; function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property);
+    RefPtr&lt;RegisterID&gt; thisRegister = generator.emitMove(generator.newTemporary(), base.get());
+    return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ FunctionCallDotNode ----------------------------------
</span><span class="lines">@@ -683,8 +688,9 @@
</span><span class="cx"> {
</span><span class="cx">     RefPtr&lt;RegisterID&gt; base = generator.emitNode(m_base.get());
</span><span class="cx">     generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset);
</span><del>-    RefPtr&lt;RegisterID&gt; function = generator.emitGetById(generator.newTemporary(), base.get(), m_ident);
-    return generator.emitCall(generator.finalDestination(dst, base.get()), function.get(), base.get(), m_args.get(), divot(), startOffset(), endOffset());
</del><ins>+    RefPtr&lt;RegisterID&gt; function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
+    RefPtr&lt;RegisterID&gt; thisRegister = generator.emitMove(generator.newTemporary(), base.get());
+    return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ PostfixResolveNode ----------------------------------
</span></span></pre></div>
<a id="trunkJavaScriptCoreparserNodesh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/parser/Nodes.h (38321 => 38322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/parser/Nodes.h        2008-11-12 00:28:57 UTC (rev 38321)
+++ trunk/JavaScriptCore/parser/Nodes.h        2008-11-12 00:32:38 UTC (rev 38322)
</span><span class="lines">@@ -2078,9 +2078,9 @@
</span><span class="cx"> 
</span><span class="cx">         int neededConstants()
</span><span class="cx">         {
</span><del>-            // We may need 1 more constant than the count given by the parser,
-            // because of the various uses of jsUndefined().
-            return m_numConstants + 1;
</del><ins>+            // We may need 2 more constants than the count given by the parser,
+            // because of the various uses of jsUndefined() and jsNull().
+            return m_numConstants + 2;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">     protected:
</span></span></pre></div>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (38321 => 38322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2008-11-12 00:28:57 UTC (rev 38321)
+++ trunk/LayoutTests/ChangeLog        2008-11-12 00:32:38 UTC (rev 38322)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2008-11-10  Geoffrey Garen  &lt;ggaren@apple.com&gt;
+
+        Reviewed by Darin Adler.
+        
+        Updated a test after fixing https://bugs.webkit.org/show_bug.cgi?id=22174
+        Simplified op_call by nixing its responsibility for moving the value of
+        &quot;this&quot; into the first argument slot.
+
+        * fast/js/global-recursion-on-full-stack-expected.txt: This test passes
+        a little differently now, because the register layout has changed.
+        Specifically, the stack overflow now happens in the call to f() instead
+        of the initiation of the &lt;script&gt; tag, so it is caught, and it does not
+        log an exception to the console.
+
</ins><span class="cx"> 2008-11-11  Pierre-Olivier Latour  &lt;pol@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Reviewed by Mark Rowe.
</span></span></pre></div>
<a id="trunkLayoutTestsfastjsglobalrecursiononfullstackexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/js/global-recursion-on-full-stack-expected.txt (38321 => 38322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/js/global-recursion-on-full-stack-expected.txt        2008-11-12 00:28:57 UTC (rev 38321)
+++ trunk/LayoutTests/fast/js/global-recursion-on-full-stack-expected.txt        2008-11-12 00:32:38 UTC (rev 38322)
</span><span class="lines">@@ -1,3 +1,2 @@
</span><del>-CONSOLE MESSAGE: line 0: RangeError: Maximum call stack size exceeded.
</del><span class="cx"> This tests global code recursion when the JS stack is full.
</span><span class="cx"> PASS: Entering global code with a full JS stack did not crash, and did not allow continued recursion.
</span></span></pre>
</div>
</div>

</body>
</html>