<!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>[159943] 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/159943">159943</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2013-12-02 11:49:43 -0800 (Mon, 02 Dec 2013)</dd>
</dl>

<h3>Log Message</h3>
<pre>Stores to local captured variables should be intercepted
https://bugs.webkit.org/show_bug.cgi?id=124883

Source/JavaScriptCore: 

Reviewed by Mark Hahnenberg.
        
Previously, in bytecode, you could assign to a captured variable just as you would
assign to any other kind of variable. This complicates closure variable constant
inference because we don't have any place where we can intercept stores to captured
variables in the LLInt.
        
This patch institutes a policy that only certain instructions can store to captured
variables. If you interpret those instructions and you are required to notifyWrite()
then you need to check if the relevant variable is captured. Those instructions are
tracked in CodeBlock.cpp's VerifyCapturedDef. The main one is simply op_captured_mov.
In the future, we'll probably modify those instructions to have a pointer directly to
the VariableWatchpointSet; but for now we just introduce the captured instructions as
placeholders.
        
In order to validate that the placeholders are inserted correctly, this patch improves
the CodeBlock validation to be able to inspect every def in the bytecode. To do that,
this patch refactors the liveness analysis' use/def calculator to be reusable; it now
takes a functor for each use or def.
        
In the process of refactoring the liveness analysis, I noticed that op_enter was
claiming to def all callee registers. That's wrong; it only defs the non-temporary
variables. Making that change revealed preexisting bugs in the liveness analysis, since
now the validator would pick up cases where the bytecode claimed to use a temporary and
the def calculator never noticed the definition (or the converse - where the bytecode
was actually not using a temporary but the liveness analysis thought that it was a
use). This patch fixes a few of those bugs.

* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeLivenessAnalysis.cpp:
(JSC::stepOverInstruction):
* bytecode/BytecodeUseDef.h: Added.
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::isCaptured):
(JSC::CodeBlock::validate):
* bytecode/CodeBlock.h:
* bytecode/Opcode.h:
(JSC::padOpcodeName):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::resolveCallee):
(JSC::BytecodeGenerator::emitMove):
(JSC::BytecodeGenerator::isCaptured):
(JSC::BytecodeGenerator::local):
(JSC::BytecodeGenerator::constLocal):
(JSC::BytecodeGenerator::emitNewFunction):
(JSC::BytecodeGenerator::emitLazyNewFunction):
(JSC::BytecodeGenerator::emitNewFunctionInternal):
* bytecompiler/BytecodeGenerator.h:
(JSC::Local::Local):
(JSC::Local::isCaptured):
(JSC::Local::captureMode):
(JSC::BytecodeGenerator::captureMode):
(JSC::BytecodeGenerator::emitNode):
(JSC::BytecodeGenerator::pushOptimisedForIn):
* bytecompiler/NodesCodegen.cpp:
(JSC::PostfixNode::emitResolve):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::ConstDeclNode::emitCodeSingle):
(JSC::ForInNode::emitBytecode):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/SymbolTable.h:
(JSC::SymbolTable::isCaptured):

LayoutTests: 

Reviewed by Mark Hahnenberg.

* js/regress/captured-assignments-expected.txt: Added.
* js/regress/captured-assignments.html: Added.
* js/regress/script-tests/captured-assignments.js: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreGNUmakefilelistam">trunk/Source/JavaScriptCore/GNUmakefile.list.am</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj">trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeBytecodeLivenessAnalysiscpp">trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockh">trunk/Source/JavaScriptCore/bytecode/CodeBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeOpcodeh">trunk/Source/JavaScriptCore/bytecode/Opcode.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerNodesCodegencpp">trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCapabilitiescpp">trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITcpp">trunk/Source/JavaScriptCore/jit/JIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeSymbolTableh">trunk/Source/JavaScriptCore/runtime/SymbolTable.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsregresscapturedassignmentsexpectedtxt">trunk/LayoutTests/js/regress/captured-assignments-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregresscapturedassignmentshtml">trunk/LayoutTests/js/regress/captured-assignments.html</a></li>
<li><a href="#trunkLayoutTestsjsregressscripttestscapturedassignmentsjs">trunk/LayoutTests/js/regress/script-tests/captured-assignments.js</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeBytecodeUseDefh">trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/LayoutTests/ChangeLog        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2013-12-01  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Stores to local captured variables should be intercepted
+        https://bugs.webkit.org/show_bug.cgi?id=124883
+
+        Reviewed by Mark Hahnenberg.
+
+        * js/regress/captured-assignments-expected.txt: Added.
+        * js/regress/captured-assignments.html: Added.
+        * js/regress/script-tests/captured-assignments.js: Added.
+
</ins><span class="cx"> 2013-12-02  Lauro Neto  &lt;lauro.neto@openbossa.org&gt;
</span><span class="cx"> 
</span><span class="cx">         [MediaStream] Update layout tests to newer spec.
</span></span></pre></div>
<a id="trunkLayoutTestsjsregresscapturedassignmentsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/captured-assignments-expected.txt (0 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/captured-assignments-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/captured-assignments-expected.txt        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/captured-assignments
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregresscapturedassignmentshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/captured-assignments.html (0 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/captured-assignments.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/captured-assignments.html        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/captured-assignments.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;resources/regress-post.js&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="trunkLayoutTestsjsregressscripttestscapturedassignmentsjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/captured-assignments.js (0 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/captured-assignments.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/captured-assignments.js        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+function foo() {
+    var x = 0;
+    ++x;
+    for (var x in [1, 2, 3]) {
+    }
+    x = 1;
+    x++;
+    var y = x++;
+    var z = y++;
+    z = x++;
+    x += 2;
+    z -= 1;
+    x *= 2;
+    z &lt;&lt;= 1;
+    x |= 5;
+    return function() { return x++ + z; }
+}
+
+for (var i = 0; i &lt; 100; ++i) {
+    if (foo()() != 17)
+        throw &quot;Error&quot;;
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/ChangeLog        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -1,3 +1,86 @@
</span><ins>+2013-12-01  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Stores to local captured variables should be intercepted
+        https://bugs.webkit.org/show_bug.cgi?id=124883
+
+        Reviewed by Mark Hahnenberg.
+        
+        Previously, in bytecode, you could assign to a captured variable just as you would
+        assign to any other kind of variable. This complicates closure variable constant
+        inference because we don't have any place where we can intercept stores to captured
+        variables in the LLInt.
+        
+        This patch institutes a policy that only certain instructions can store to captured
+        variables. If you interpret those instructions and you are required to notifyWrite()
+        then you need to check if the relevant variable is captured. Those instructions are
+        tracked in CodeBlock.cpp's VerifyCapturedDef. The main one is simply op_captured_mov.
+        In the future, we'll probably modify those instructions to have a pointer directly to
+        the VariableWatchpointSet; but for now we just introduce the captured instructions as
+        placeholders.
+        
+        In order to validate that the placeholders are inserted correctly, this patch improves
+        the CodeBlock validation to be able to inspect every def in the bytecode. To do that,
+        this patch refactors the liveness analysis' use/def calculator to be reusable; it now
+        takes a functor for each use or def.
+        
+        In the process of refactoring the liveness analysis, I noticed that op_enter was
+        claiming to def all callee registers. That's wrong; it only defs the non-temporary
+        variables. Making that change revealed preexisting bugs in the liveness analysis, since
+        now the validator would pick up cases where the bytecode claimed to use a temporary and
+        the def calculator never noticed the definition (or the converse - where the bytecode
+        was actually not using a temporary but the liveness analysis thought that it was a
+        use). This patch fixes a few of those bugs.
+
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/BytecodeLivenessAnalysis.cpp:
+        (JSC::stepOverInstruction):
+        * bytecode/BytecodeUseDef.h: Added.
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        (JSC::CodeBlock::isCaptured):
+        (JSC::CodeBlock::validate):
+        * bytecode/CodeBlock.h:
+        * bytecode/Opcode.h:
+        (JSC::padOpcodeName):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::resolveCallee):
+        (JSC::BytecodeGenerator::emitMove):
+        (JSC::BytecodeGenerator::isCaptured):
+        (JSC::BytecodeGenerator::local):
+        (JSC::BytecodeGenerator::constLocal):
+        (JSC::BytecodeGenerator::emitNewFunction):
+        (JSC::BytecodeGenerator::emitLazyNewFunction):
+        (JSC::BytecodeGenerator::emitNewFunctionInternal):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::Local::Local):
+        (JSC::Local::isCaptured):
+        (JSC::Local::captureMode):
+        (JSC::BytecodeGenerator::captureMode):
+        (JSC::BytecodeGenerator::emitNode):
+        (JSC::BytecodeGenerator::pushOptimisedForIn):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::PostfixNode::emitResolve):
+        (JSC::PrefixNode::emitResolve):
+        (JSC::ReadModifyResolveNode::emitBytecode):
+        (JSC::AssignResolveNode::emitBytecode):
+        (JSC::ConstDeclNode::emitCodeSingle):
+        (JSC::ForInNode::emitBytecode):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/SymbolTable.h:
+        (JSC::SymbolTable::isCaptured):
+
</ins><span class="cx"> 2013-12-02  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Instead of watchpointing activation allocation, we should watchpoint entry into functions that have captured variables
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreGNUmakefilelistam"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/GNUmakefile.list.am (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/GNUmakefile.list.am        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/GNUmakefile.list.am        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -102,10 +102,11 @@
</span><span class="cx">         Source/JavaScriptCore/bytecode/ByValInfo.h \
</span><span class="cx">         Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp \
</span><span class="cx">         Source/JavaScriptCore/bytecode/BytecodeBasicBlock.h \
</span><ins>+        Source/JavaScriptCore/bytecode/BytecodeConventions.h \
</ins><span class="cx">         Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp \
</span><span class="cx">         Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.h \
</span><span class="cx">         Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysisInlines.h \
</span><del>-        Source/JavaScriptCore/bytecode/BytecodeConventions.h \
</del><ins>+        Source/JavaScriptCore/bytecode/BytecodeUseDef.h \
</ins><span class="cx">         Source/JavaScriptCore/bytecode/CallLinkInfo.cpp \
</span><span class="cx">         Source/JavaScriptCore/bytecode/CallLinkInfo.h \
</span><span class="cx">         Source/JavaScriptCore/bytecode/CallLinkStatus.cpp \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -751,6 +751,7 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\BytecodeBasicBlock.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\BytecodeLivenessAnalysis.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\BytecodeLivenessAnalysisInline.h&quot; /&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\bytecode\BytecodeUseDef.h&quot; /&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\CallLinkInfo.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\CallLinkStatus.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\CallReturnOffsetToBytecodeOffset.h&quot; /&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -289,6 +289,7 @@
</span><span class="cx">                 0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */; };
</span><span class="cx">                 0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F8364B7164B0C110053329A /* DFGBranchDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                0F885E111849A3BE00F1E3FA /* BytecodeUseDef.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F885E101849A3BE00F1E3FA /* BytecodeUseDef.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 0F8F2B95172E04A0007DBDA5 /* FTLLink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F2B93172E049E007DBDA5 /* FTLLink.cpp */; };
</span><span class="cx">                 0F8F2B96172E04A3007DBDA5 /* FTLLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8F2B94172E049E007DBDA5 /* FTLLink.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F8F2B99172F04FF007DBDA5 /* DFGDesiredIdentifiers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F2B97172F04FD007DBDA5 /* DFGDesiredIdentifiers.cpp */; };
</span><span class="lines">@@ -1583,6 +1584,7 @@
</span><span class="cx">                 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayAllocationProfile.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBranchDirection.h; path = dfg/DFGBranchDirection.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F85A31E16AB76AE0077571E /* DFGVariadicFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariadicFunction.h; path = dfg/DFGVariadicFunction.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0F885E101849A3BE00F1E3FA /* BytecodeUseDef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeUseDef.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0F8F2B93172E049E007DBDA5 /* FTLLink.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FTLLink.cpp; path = ftl/FTLLink.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F8F2B94172E049E007DBDA5 /* FTLLink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FTLLink.h; path = ftl/FTLLink.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F8F2B97172F04FD007DBDA5 /* DFGDesiredIdentifiers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDesiredIdentifiers.cpp; path = dfg/DFGDesiredIdentifiers.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -4058,6 +4060,7 @@
</span><span class="cx">                                 C2FCAE0E17A9C24E0034C735 /* BytecodeLivenessAnalysis.cpp */,
</span><span class="cx">                                 C2FCAE0F17A9C24E0034C735 /* BytecodeLivenessAnalysis.h */,
</span><span class="cx">                                 0F666EBE183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h */,
</span><ins>+                                0F885E101849A3BE00F1E3FA /* BytecodeUseDef.h */,
</ins><span class="cx">                                 0F8023E91613832300A0BA45 /* ByValInfo.h */,
</span><span class="cx">                                 0F0B83AE14BCF71400885B4F /* CallLinkInfo.cpp */,
</span><span class="cx">                                 0F0B83AF14BCF71400885B4F /* CallLinkInfo.h */,
</span><span class="lines">@@ -4269,6 +4272,7 @@
</span><span class="cx">                                 BC3135640F302FA3003DFD3A /* DebuggerActivation.h in Headers */,
</span><span class="cx">                                 BC18C3FB0E16F5CD00B34460 /* DebuggerCallFrame.h in Headers */,
</span><span class="cx">                                 0F136D4D174AD69E0075B354 /* DeferGC.h in Headers */,
</span><ins>+                                0F885E111849A3BE00F1E3FA /* BytecodeUseDef.h in Headers */,
</ins><span class="cx">                                 0FC712DF17CD877C008CC93C /* DeferredCompilationCallback.h in Headers */,
</span><span class="cx">                                 A77A423E17A0BBFD00A8DB81 /* DFGAbstractHeap.h in Headers */,
</span><span class="cx">                                 A704D90317A0BAA8006BA554 /* DFGAbstractInterpreter.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeBytecodeLivenessAnalysiscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> #include &quot;BytecodeLivenessAnalysis.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #include &quot;BytecodeLivenessAnalysisInlines.h&quot;
</span><ins>+#include &quot;BytecodeUseDef.h&quot;
</ins><span class="cx"> #include &quot;CodeBlock.h&quot;
</span><span class="cx"> #include &quot;FullBytecodeLiveness.h&quot;
</span><span class="cx"> #include &quot;PreciseJumpTargets.h&quot;
</span><span class="lines">@@ -67,427 +68,27 @@
</span><span class="cx">         bits.set(virtualReg.toLocal() - codeBlock-&gt;captureCount());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void computeUsesForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset, FastBitVector&amp; uses)
-{
-    Interpreter* interpreter = codeBlock-&gt;vm()-&gt;interpreter;
-    Instruction* instructionsBegin = codeBlock-&gt;instructions().begin();
-    Instruction* instruction = &amp;instructionsBegin[bytecodeOffset];
-    OpcodeID opcodeID = interpreter-&gt;getOpcodeID(instruction-&gt;u.opcode);
-    switch (opcodeID) {
-    // No uses.
-    case op_new_regexp:
-    case op_new_array_buffer:
-    case op_throw_static_error:
-    case op_debug:
-    case op_resolve_scope:
-    case op_pop_scope:
-    case op_jneq_ptr:
-    case op_new_func_exp:
-    case op_loop_hint:
-    case op_jmp:
-    case op_new_object:
-    case op_init_lazy_reg:
-    case op_get_callee:
-    case op_enter:
-    case op_touch_entry:
-    case op_catch:
-        return;
-    // First argument.
-    case op_new_func:
-    case op_create_activation: 
-    case op_create_arguments:
-    case op_to_this:
-    case op_tear_off_activation:
-    case op_profile_will_call:
-    case op_profile_did_call:
-    case op_throw:
-    case op_push_with_scope:
-    case op_end:
-    case op_ret:
-    case op_jtrue:
-    case op_jfalse:
-    case op_jeq_null:
-    case op_jneq_null:
-    case op_dec:
-    case op_inc: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[1].u.operand))
-            setForOperand(codeBlock, uses, instruction[1].u.operand);
-        return;
-    }
-    // First and second arguments.
-    case op_del_by_id:
-    case op_ret_object_or_this:
-    case op_jlesseq:
-    case op_jgreater:
-    case op_jgreatereq:
-    case op_jnless:
-    case op_jnlesseq:
-    case op_jngreater:
-    case op_jngreatereq:
-    case op_jless: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[1].u.operand))
-            setForOperand(codeBlock, uses, instruction[1].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[2].u.operand))
-            setForOperand(codeBlock, uses, instruction[2].u.operand);
-        return;
-    }
-    // First, second, and third arguments.
-    case op_del_by_val:
-    case op_put_by_val_direct:
-    case op_put_by_val: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[1].u.operand))
-            setForOperand(codeBlock, uses, instruction[1].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[2].u.operand))
-            setForOperand(codeBlock, uses, instruction[2].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[3].u.operand))
-            setForOperand(codeBlock, uses, instruction[3].u.operand);
-        return;
-    }
-    // First and third arguments.
-    case op_put_by_index:
-    case op_put_by_id_replace:
-    case op_put_by_id_transition:
-    case op_put_by_id_transition_direct:
-    case op_put_by_id_transition_direct_out_of_line:
-    case op_put_by_id_transition_normal:
-    case op_put_by_id_transition_normal_out_of_line:
-    case op_put_by_id_generic:
-    case op_put_by_id_out_of_line:
-    case op_put_by_id:
-    case op_put_to_scope: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[1].u.operand))
-            setForOperand(codeBlock, uses, instruction[1].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[3].u.operand))
-            setForOperand(codeBlock, uses, instruction[3].u.operand);
-        return;
-    }
-    // First, third, and fourth arguments.
-    case op_put_getter_setter: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[1].u.operand))
-            setForOperand(codeBlock, uses, instruction[1].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[3].u.operand))
-            setForOperand(codeBlock, uses, instruction[3].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[4].u.operand))
-            setForOperand(codeBlock, uses, instruction[4].u.operand);
-        return;
-    }
-    // Second argument.
-    case op_init_global_const_nop:
-    case op_init_global_const:
-    case op_push_name_scope:
-    case op_get_from_scope:
-    case op_to_primitive:
-    case op_get_by_id:
-    case op_get_by_id_out_of_line:
-    case op_get_by_id_self:
-    case op_get_by_id_proto:
-    case op_get_by_id_chain:
-    case op_get_by_id_getter_self:
-    case op_get_by_id_getter_proto:
-    case op_get_by_id_getter_chain:
-    case op_get_by_id_custom_self:
-    case op_get_by_id_custom_proto:
-    case op_get_by_id_custom_chain:
-    case op_get_by_id_generic:
-    case op_get_array_length:
-    case op_get_string_length:
-    case op_get_arguments_length:
-    case op_typeof:
-    case op_is_undefined:
-    case op_is_boolean:
-    case op_is_number:
-    case op_is_string:
-    case op_is_object:
-    case op_is_function:
-    case op_to_number:
-    case op_negate:
-    case op_neq_null:
-    case op_eq_null:
-    case op_not:
-    case op_mov:
-    case op_new_array_with_size:
-    case op_create_this: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[2].u.operand))
-            setForOperand(codeBlock, uses, instruction[2].u.operand);
-        return;
-    }
-    // Second and third arguments.
-    case op_get_by_val:
-    case op_get_argument_by_val:
-    case op_in:
-    case op_instanceof:
-    case op_check_has_instance:
-    case op_add:
-    case op_mul:
-    case op_div:
-    case op_mod:
-    case op_sub:
-    case op_lshift:
-    case op_rshift:
-    case op_urshift:
-    case op_bitand:
-    case op_bitxor:
-    case op_bitor:
-    case op_less:
-    case op_lesseq:
-    case op_greater:
-    case op_greatereq:
-    case op_nstricteq:
-    case op_stricteq:
-    case op_neq:
-    case op_eq: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[2].u.operand))
-            setForOperand(codeBlock, uses, instruction[2].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[3].u.operand))
-            setForOperand(codeBlock, uses, instruction[3].u.operand);
-        return;
-    }
-    // Second, third, and fourth arguments.
-    case op_call_varargs:
-    case op_get_pnames: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[2].u.operand))
-            setForOperand(codeBlock, uses, instruction[2].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[3].u.operand))
-            setForOperand(codeBlock, uses, instruction[3].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[4].u.operand))
-            setForOperand(codeBlock, uses, instruction[4].u.operand);
-        return;
-    }
-    // Second, third, fourth, and fifth arguments.
-    case op_next_pname: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[2].u.operand))
-            setForOperand(codeBlock, uses, instruction[2].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[3].u.operand))
-            setForOperand(codeBlock, uses, instruction[3].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[4].u.operand))
-            setForOperand(codeBlock, uses, instruction[4].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[5].u.operand))
-            setForOperand(codeBlock, uses, instruction[5].u.operand);
-        return;
-    }
-    // Second, third, fourth, fifth, and sixth arguments. 
-    case op_get_by_pname: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[2].u.operand))
-            setForOperand(codeBlock, uses, instruction[2].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[3].u.operand))
-            setForOperand(codeBlock, uses, instruction[3].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[4].u.operand))
-            setForOperand(codeBlock, uses, instruction[4].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[5].u.operand))
-            setForOperand(codeBlock, uses, instruction[5].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, instruction[6].u.operand))
-            setForOperand(codeBlock, uses, instruction[6].u.operand);
-        return;
-    }
-    // Third argument.
-    case op_switch_string:
-    case op_switch_char:
-    case op_switch_imm: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[3].u.operand))
-            setForOperand(codeBlock, uses, instruction[3].u.operand);
-        return;
-    }
-    // Variable number of arguments.
-    case op_new_array:
-    case op_strcat: {
-        int base = instruction[2].u.operand;
-        int count = instruction[3].u.operand;
-        for (int i = 0; i &lt; count; i++) {
-            if (isValidRegisterForLiveness(codeBlock, base - i))
-                setForOperand(codeBlock, uses, base - i);
-        }
-        return;
-    }
-    // Crazy stuff for calls.
-    case op_construct:
-    case op_call_eval:
-    case op_call: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[2].u.operand))
-            setForOperand(codeBlock, uses, instruction[2].u.operand);
-        int argCount = instruction[3].u.operand;
-        int registerOffset = -instruction[4].u.operand;
-        int lastArg = registerOffset + CallFrame::thisArgumentOffset();
-        for (int i = opcodeID == op_construct ? 1 : 0; i &lt; argCount; i++) {
-            if (isValidRegisterForLiveness(codeBlock, lastArg + i))
-                setForOperand(codeBlock, uses, lastArg + i);
-        }
-        return;
-    }
-    // Special stuff for tear off arguments.
-    case op_tear_off_arguments: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[1].u.operand))
-            setForOperand(codeBlock, uses, instruction[1].u.operand);
-        if (isValidRegisterForLiveness(codeBlock, unmodifiedArgumentsRegister(VirtualRegister(instruction[1].u.operand)).offset()))
-            setForOperand(codeBlock, uses, unmodifiedArgumentsRegister(VirtualRegister(instruction[1].u.operand)).offset());
-        if (isValidRegisterForLiveness(codeBlock, instruction[2].u.operand))
-            setForOperand(codeBlock, uses, instruction[2].u.operand);
-        return;
-    }
-    default:
-        RELEASE_ASSERT_NOT_REACHED();
-        break;
-    }
-}
</del><ins>+namespace {
</ins><span class="cx"> 
</span><del>-static void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset, FastBitVector&amp; defs)
-{
-    Interpreter* interpreter = codeBlock-&gt;vm()-&gt;interpreter;
-    Instruction* instructionsBegin = codeBlock-&gt;instructions().begin();
-    Instruction* instruction = &amp;instructionsBegin[bytecodeOffset];
-    OpcodeID opcodeID = interpreter-&gt;getOpcodeID(instruction-&gt;u.opcode);
-    switch (opcodeID) {
-    // These don't define anything.
-    case op_init_global_const:
-    case op_init_global_const_nop:
-    case op_push_name_scope:
-    case op_push_with_scope:
-    case op_put_to_scope:
-    case op_pop_scope:
-    case op_end:
-    case op_profile_will_call:
-    case op_profile_did_call:
-    case op_throw:
-    case op_throw_static_error:
-    case op_debug:
-    case op_ret:
-    case op_ret_object_or_this:
-    case op_jmp:
-    case op_jtrue:
-    case op_jfalse:
-    case op_jeq_null:
-    case op_jneq_null:
-    case op_jneq_ptr:
-    case op_jless:
-    case op_jlesseq:
-    case op_jgreater:
-    case op_jgreatereq:
-    case op_jnless:
-    case op_jnlesseq:
-    case op_jngreater:
-    case op_jngreatereq:
-    case op_loop_hint:
-    case op_switch_imm:
-    case op_switch_char:
-    case op_switch_string:
-    case op_put_by_id:
-    case op_put_by_id_out_of_line:
-    case op_put_by_id_replace:
-    case op_put_by_id_transition:
-    case op_put_by_id_transition_direct:
-    case op_put_by_id_transition_direct_out_of_line:
-    case op_put_by_id_transition_normal:
-    case op_put_by_id_transition_normal_out_of_line:
-    case op_put_by_id_generic:
-    case op_put_getter_setter:
-    case op_put_by_val:
-    case op_put_by_val_direct:
-    case op_put_by_index:
-    case op_del_by_id:
-    case op_del_by_val:
-    case op_touch_entry:
-#define LLINT_HELPER_OPCODES(opcode, length) case opcode:
-        FOR_EACH_LLINT_OPCODE_EXTENSION(LLINT_HELPER_OPCODES);
-#undef LLINT_HELPER_OPCODES
-        return;
-    // These all have a single destination for the first argument.
-    case op_next_pname:
-    case op_get_pnames:
-    case op_resolve_scope:
-    case op_strcat:
-    case op_tear_off_activation:
-    case op_to_primitive:
-    case op_catch:
-    case op_create_this:
-    case op_new_array:
-    case op_new_array_buffer:
-    case op_new_array_with_size:
-    case op_new_regexp:
-    case op_new_func:
-    case op_new_func_exp:
-    case op_call_varargs:
-    case op_get_from_scope:
-    case op_call:
-    case op_call_eval:
-    case op_construct:
-    case op_get_by_id:
-    case op_get_by_id_out_of_line:
-    case op_get_by_id_self:
-    case op_get_by_id_proto:
-    case op_get_by_id_chain:
-    case op_get_by_id_getter_self:
-    case op_get_by_id_getter_proto:
-    case op_get_by_id_getter_chain:
-    case op_get_by_id_custom_self:
-    case op_get_by_id_custom_proto:
-    case op_get_by_id_custom_chain:
-    case op_get_by_id_generic:
-    case op_get_array_length:
-    case op_get_string_length:
-    case op_check_has_instance:
-    case op_instanceof:
-    case op_get_by_val:
-    case op_get_argument_by_val:
-    case op_get_by_pname:
-    case op_get_arguments_length:
-    case op_typeof:
-    case op_is_undefined:
-    case op_is_boolean:
-    case op_is_number:
-    case op_is_string:
-    case op_is_object:
-    case op_is_function:
-    case op_in:
-    case op_to_number:
-    case op_negate:
-    case op_add:
-    case op_mul:
-    case op_div:
-    case op_mod:
-    case op_sub:
-    case op_lshift:
-    case op_rshift:
-    case op_urshift:
-    case op_bitand:
-    case op_bitxor:
-    case op_bitor:
-    case op_inc:
-    case op_dec:
-    case op_eq:
-    case op_neq:
-    case op_stricteq:
-    case op_nstricteq:
-    case op_less:
-    case op_lesseq:
-    case op_greater:
-    case op_greatereq:
-    case op_neq_null:
-    case op_eq_null:
-    case op_not:
-    case op_mov:
-    case op_new_object:
-    case op_to_this:
-    case op_get_callee:
-    case op_init_lazy_reg:
-    case op_create_activation:
-    case op_create_arguments: {
-        if (isValidRegisterForLiveness(codeBlock, instruction[1].u.operand))
-            setForOperand(codeBlock, defs, instruction[1].u.operand);
-        return;
</del><ins>+class SetBit {
+public:
+    SetBit(FastBitVector&amp; bits)
+        : m_bits(bits)
+    {
</ins><span class="cx">     }
</span><del>-    case op_tear_off_arguments: {
-        int operand = unmodifiedArgumentsRegister(
-            VirtualRegister(instruction[1].u.operand)).offset();
</del><ins>+    
+    void operator()(CodeBlock* codeBlock, Instruction*, OpcodeID, int operand)
+    {
</ins><span class="cx">         if (isValidRegisterForLiveness(codeBlock, operand))
</span><del>-            setForOperand(codeBlock, defs, operand);
-        return;
</del><ins>+            setForOperand(codeBlock, m_bits, operand);
</ins><span class="cx">     }
</span><del>-    case op_enter: {
-        defs.setAll();
-        return;
-    } }
-    RELEASE_ASSERT_NOT_REACHED();
-}
</del><ins>+    
+private:
+    FastBitVector&amp; m_bits;
+};
</ins><span class="cx"> 
</span><ins>+} // anonymous namespace
+
</ins><span class="cx"> static unsigned getLeaderOffsetForBasicBlock(RefPtr&lt;BytecodeBasicBlock&gt;* basicBlock)
</span><span class="cx"> {
</span><span class="cx">     return (*basicBlock)-&gt;leaderBytecodeOffset();
</span><span class="lines">@@ -537,8 +138,10 @@
</span><span class="cx">     uses.clearAll();
</span><span class="cx">     defs.clearAll();
</span><span class="cx">     
</span><del>-    computeUsesForBytecodeOffset(codeBlock, bytecodeOffset, uses);
-    computeDefsForBytecodeOffset(codeBlock, bytecodeOffset, defs);
</del><ins>+    SetBit setUses(uses);
+    SetBit setDefs(defs);
+    computeUsesForBytecodeOffset(codeBlock, bytecodeOffset, setUses);
+    computeDefsForBytecodeOffset(codeBlock, bytecodeOffset, setDefs);
</ins><span class="cx">     
</span><span class="cx">     out.exclude(defs);
</span><span class="cx">     out.merge(uses);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeBytecodeUseDefh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h (0 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -0,0 +1,413 @@
</span><ins>+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BytecodeUseDef_h
+#define BytecodeUseDef_h
+
+#include &quot;CodeBlock.h&quot;
+
+namespace JSC {
+
+template&lt;typename Functor&gt;
+void computeUsesForBytecodeOffset(
+    CodeBlock* codeBlock, unsigned bytecodeOffset, Functor&amp; functor)
+{
+    Interpreter* interpreter = codeBlock-&gt;vm()-&gt;interpreter;
+    Instruction* instructionsBegin = codeBlock-&gt;instructions().begin();
+    Instruction* instruction = &amp;instructionsBegin[bytecodeOffset];
+    OpcodeID opcodeID = interpreter-&gt;getOpcodeID(instruction-&gt;u.opcode);
+    switch (opcodeID) {
+    // No uses.
+    case op_new_regexp:
+    case op_new_array_buffer:
+    case op_throw_static_error:
+    case op_debug:
+    case op_resolve_scope:
+    case op_pop_scope:
+    case op_jneq_ptr:
+    case op_new_func_exp:
+    case op_loop_hint:
+    case op_jmp:
+    case op_new_object:
+    case op_init_lazy_reg:
+    case op_get_callee:
+    case op_enter:
+    case op_catch:
+    case op_touch_entry:
+        return;
+    case op_new_func:
+    case op_new_captured_func:
+    case op_create_activation: 
+    case op_create_arguments:
+    case op_to_this:
+    case op_tear_off_activation:
+    case op_profile_will_call:
+    case op_profile_did_call:
+    case op_throw:
+    case op_push_with_scope:
+    case op_end:
+    case op_ret:
+    case op_jtrue:
+    case op_jfalse:
+    case op_jeq_null:
+    case op_jneq_null:
+    case op_dec:
+    case op_inc: {
+        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+        return;
+    }
+    case op_ret_object_or_this:
+    case op_jlesseq:
+    case op_jgreater:
+    case op_jgreatereq:
+    case op_jnless:
+    case op_jnlesseq:
+    case op_jngreater:
+    case op_jngreatereq:
+    case op_jless: {
+        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        return;
+    }
+    case op_put_by_val_direct:
+    case op_put_by_val: {
+        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+        return;
+    }
+    case op_put_by_index:
+    case op_put_by_id_replace:
+    case op_put_by_id_transition:
+    case op_put_by_id_transition_direct:
+    case op_put_by_id_transition_direct_out_of_line:
+    case op_put_by_id_transition_normal:
+    case op_put_by_id_transition_normal_out_of_line:
+    case op_put_by_id_generic:
+    case op_put_by_id_out_of_line:
+    case op_put_by_id:
+    case op_put_to_scope: {
+        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+        return;
+    }
+    case op_put_getter_setter: {
+        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
+        return;
+    }
+    case op_init_global_const_nop:
+    case op_init_global_const:
+    case op_push_name_scope:
+    case op_get_from_scope:
+    case op_to_primitive:
+    case op_get_by_id:
+    case op_get_by_id_out_of_line:
+    case op_get_by_id_self:
+    case op_get_by_id_proto:
+    case op_get_by_id_chain:
+    case op_get_by_id_getter_self:
+    case op_get_by_id_getter_proto:
+    case op_get_by_id_getter_chain:
+    case op_get_by_id_custom_self:
+    case op_get_by_id_custom_proto:
+    case op_get_by_id_custom_chain:
+    case op_get_by_id_generic:
+    case op_get_array_length:
+    case op_get_string_length:
+    case op_get_arguments_length:
+    case op_typeof:
+    case op_is_undefined:
+    case op_is_boolean:
+    case op_is_number:
+    case op_is_string:
+    case op_is_object:
+    case op_is_function:
+    case op_to_number:
+    case op_negate:
+    case op_neq_null:
+    case op_eq_null:
+    case op_not:
+    case op_mov:
+    case op_captured_mov:
+    case op_new_array_with_size:
+    case op_create_this:
+    case op_get_pnames:
+    case op_del_by_id: {
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        return;
+    }
+    case op_get_by_val:
+    case op_get_argument_by_val:
+    case op_in:
+    case op_instanceof:
+    case op_check_has_instance:
+    case op_add:
+    case op_mul:
+    case op_div:
+    case op_mod:
+    case op_sub:
+    case op_lshift:
+    case op_rshift:
+    case op_urshift:
+    case op_bitand:
+    case op_bitxor:
+    case op_bitor:
+    case op_less:
+    case op_lesseq:
+    case op_greater:
+    case op_greatereq:
+    case op_nstricteq:
+    case op_stricteq:
+    case op_neq:
+    case op_eq:
+    case op_del_by_val: {
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+        return;
+    }
+    case op_call_varargs: {
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
+        return;
+    }
+    case op_next_pname: {
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[5].u.operand);
+        return;
+    }
+    case op_get_by_pname: {
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[5].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[6].u.operand);
+        return;
+    }
+    case op_switch_string:
+    case op_switch_char:
+    case op_switch_imm: {
+        functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+        return;
+    }
+    case op_new_array:
+    case op_strcat: {
+        int base = instruction[2].u.operand;
+        int count = instruction[3].u.operand;
+        for (int i = 0; i &lt; count; i++)
+            functor(codeBlock, instruction, opcodeID, base - i);
+        return;
+    }
+    case op_construct:
+    case op_call_eval:
+    case op_call: {
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        int argCount = instruction[3].u.operand;
+        int registerOffset = -instruction[4].u.operand;
+        int lastArg = registerOffset + CallFrame::thisArgumentOffset();
+        for (int i = opcodeID == op_construct ? 1 : 0; i &lt; argCount; i++)
+            functor(codeBlock, instruction, opcodeID, lastArg + i);
+        return;
+    }
+    case op_tear_off_arguments: {
+        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+        functor(codeBlock, instruction, opcodeID, unmodifiedArgumentsRegister(VirtualRegister(instruction[1].u.operand)).offset());
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        return;
+    }
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+template&lt;typename Functor&gt;
+void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset, Functor&amp; functor)
+{
+    Interpreter* interpreter = codeBlock-&gt;vm()-&gt;interpreter;
+    Instruction* instructionsBegin = codeBlock-&gt;instructions().begin();
+    Instruction* instruction = &amp;instructionsBegin[bytecodeOffset];
+    OpcodeID opcodeID = interpreter-&gt;getOpcodeID(instruction-&gt;u.opcode);
+    switch (opcodeID) {
+    // These don't define anything.
+    case op_init_global_const:
+    case op_init_global_const_nop:
+    case op_push_name_scope:
+    case op_push_with_scope:
+    case op_put_to_scope:
+    case op_pop_scope:
+    case op_end:
+    case op_profile_will_call:
+    case op_profile_did_call:
+    case op_throw:
+    case op_throw_static_error:
+    case op_debug:
+    case op_ret:
+    case op_ret_object_or_this:
+    case op_jmp:
+    case op_jtrue:
+    case op_jfalse:
+    case op_jeq_null:
+    case op_jneq_null:
+    case op_jneq_ptr:
+    case op_jless:
+    case op_jlesseq:
+    case op_jgreater:
+    case op_jgreatereq:
+    case op_jnless:
+    case op_jnlesseq:
+    case op_jngreater:
+    case op_jngreatereq:
+    case op_loop_hint:
+    case op_switch_imm:
+    case op_switch_char:
+    case op_switch_string:
+    case op_put_by_id:
+    case op_put_by_id_out_of_line:
+    case op_put_by_id_replace:
+    case op_put_by_id_transition:
+    case op_put_by_id_transition_direct:
+    case op_put_by_id_transition_direct_out_of_line:
+    case op_put_by_id_transition_normal:
+    case op_put_by_id_transition_normal_out_of_line:
+    case op_put_by_id_generic:
+    case op_put_getter_setter:
+    case op_put_by_val:
+    case op_put_by_val_direct:
+    case op_put_by_index:
+    case op_tear_off_arguments:
+    case op_touch_entry:
+#define LLINT_HELPER_OPCODES(opcode, length) case opcode:
+        FOR_EACH_LLINT_OPCODE_EXTENSION(LLINT_HELPER_OPCODES);
+#undef LLINT_HELPER_OPCODES
+        return;
+    // These all have a single destination for the first argument.
+    case op_next_pname:
+    case op_resolve_scope:
+    case op_strcat:
+    case op_tear_off_activation:
+    case op_to_primitive:
+    case op_catch:
+    case op_create_this:
+    case op_new_array:
+    case op_new_array_buffer:
+    case op_new_array_with_size:
+    case op_new_regexp:
+    case op_new_func:
+    case op_new_captured_func:
+    case op_new_func_exp:
+    case op_call_varargs:
+    case op_get_from_scope:
+    case op_call:
+    case op_call_eval:
+    case op_construct:
+    case op_get_by_id:
+    case op_get_by_id_out_of_line:
+    case op_get_by_id_self:
+    case op_get_by_id_proto:
+    case op_get_by_id_chain:
+    case op_get_by_id_getter_self:
+    case op_get_by_id_getter_proto:
+    case op_get_by_id_getter_chain:
+    case op_get_by_id_custom_self:
+    case op_get_by_id_custom_proto:
+    case op_get_by_id_custom_chain:
+    case op_get_by_id_generic:
+    case op_get_array_length:
+    case op_get_string_length:
+    case op_check_has_instance:
+    case op_instanceof:
+    case op_get_by_val:
+    case op_get_argument_by_val:
+    case op_get_by_pname:
+    case op_get_arguments_length:
+    case op_typeof:
+    case op_is_undefined:
+    case op_is_boolean:
+    case op_is_number:
+    case op_is_string:
+    case op_is_object:
+    case op_is_function:
+    case op_in:
+    case op_to_number:
+    case op_negate:
+    case op_add:
+    case op_mul:
+    case op_div:
+    case op_mod:
+    case op_sub:
+    case op_lshift:
+    case op_rshift:
+    case op_urshift:
+    case op_bitand:
+    case op_bitxor:
+    case op_bitor:
+    case op_inc:
+    case op_dec:
+    case op_eq:
+    case op_neq:
+    case op_stricteq:
+    case op_nstricteq:
+    case op_less:
+    case op_lesseq:
+    case op_greater:
+    case op_greatereq:
+    case op_neq_null:
+    case op_eq_null:
+    case op_not:
+    case op_mov:
+    case op_captured_mov:
+    case op_new_object:
+    case op_to_this:
+    case op_get_callee:
+    case op_init_lazy_reg:
+    case op_create_activation:
+    case op_create_arguments:
+    case op_del_by_id:
+    case op_del_by_val: {
+        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+        return;
+    }
+    case op_get_pnames: {
+        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
+        return;
+    }
+    case op_enter: {
+        for (unsigned i = codeBlock-&gt;m_numVars; i--;)
+            functor(codeBlock, instruction, opcodeID, virtualRegisterForLocal(i).offset());
+        return;
+    } }
+}
+
+} // namespace JSC
+
+#endif // BytecodeUseDef_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include &quot;CodeBlock.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #include &quot;BytecodeGenerator.h&quot;
</span><ins>+#include &quot;BytecodeUseDef.h&quot;
</ins><span class="cx"> #include &quot;CallLinkStatus.h&quot;
</span><span class="cx"> #include &quot;DFGCapabilities.h&quot;
</span><span class="cx"> #include &quot;DFGCommon.h&quot;
</span><span class="lines">@@ -762,6 +763,13 @@
</span><span class="cx">             out.printf(&quot;%s, %s&quot;, registerName(r0).data(), registerName(r1).data());
</span><span class="cx">             break;
</span><span class="cx">         }
</span><ins>+        case op_captured_mov: {
+            int r0 = (++it)-&gt;u.operand;
+            int r1 = (++it)-&gt;u.operand;
+            printLocationAndOp(out, exec, location, it, &quot;captured_mov&quot;);
+            out.printf(&quot;%s, %s&quot;, registerName(r0).data(), registerName(r1).data());
+            break;
+        }
</ins><span class="cx">         case op_not: {
</span><span class="cx">             printUnaryOp(out, exec, location, it, &quot;not&quot;);
</span><span class="cx">             break;
</span><span class="lines">@@ -1213,6 +1221,14 @@
</span><span class="cx">             out.printf(&quot;%s, f%d, %s&quot;, registerName(r0).data(), f0, shouldCheck ? &quot;&lt;Checked&gt;&quot; : &quot;&lt;Unchecked&gt;&quot;);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><ins>+        case op_new_captured_func: {
+            int r0 = (++it)-&gt;u.operand;
+            int f0 = (++it)-&gt;u.operand;
+            int shouldCheck = (++it)-&gt;u.operand;
+            printLocationAndOp(out, exec, location, it, &quot;new_captured_func&quot;);
+            out.printf(&quot;%s, f%d, %s&quot;, registerName(r0).data(), f0, shouldCheck ? &quot;&lt;Checked&gt;&quot; : &quot;&lt;Unchecked&gt;&quot;);
+            break;
+        }
</ins><span class="cx">         case op_new_func_exp: {
</span><span class="cx">             int r0 = (++it)-&gt;u.operand;
</span><span class="cx">             int f0 = (++it)-&gt;u.operand;
</span><span class="lines">@@ -2472,8 +2488,7 @@
</span><span class="cx">     if (!symbolTable())
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    return operand.offset() &lt;= symbolTable()-&gt;captureStart()
-        &amp;&amp; operand.offset() &gt; symbolTable()-&gt;captureEnd();
</del><ins>+    return symbolTable()-&gt;isCaptured(operand.offset());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> int CodeBlock::framePointerOffsetToGetActivationRegisters(int machineCaptureStart)
</span><span class="lines">@@ -3430,6 +3445,48 @@
</span><span class="cx">     return &quot;&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+namespace {
+
+struct VerifyCapturedDef {
+    void operator()(CodeBlock* codeBlock, Instruction* instruction, OpcodeID opcodeID, int operand)
+    {
+        unsigned bytecodeOffset = instruction - codeBlock-&gt;instructions().begin();
+        
+        if (codeBlock-&gt;isConstantRegisterIndex(operand)) {
+            codeBlock-&gt;beginValidationDidFail();
+            dataLog(&quot;    At bc#&quot;, bytecodeOffset, &quot; encountered a definition of a constant.\n&quot;);
+            codeBlock-&gt;endValidationDidFail();
+            return;
+        }
+
+        switch (opcodeID) {
+        case op_enter:
+        case op_captured_mov:
+        case op_init_lazy_reg:
+        case op_create_arguments:
+        case op_new_captured_func:
+            return;
+        default:
+            break;
+        }
+        
+        VirtualRegister virtualReg(operand);
+        if (!virtualReg.isLocal())
+            return;
+        
+        if (codeBlock-&gt;captureCount() &amp;&amp; codeBlock-&gt;symbolTable()-&gt;isCaptured(operand)) {
+            codeBlock-&gt;beginValidationDidFail();
+            dataLog(&quot;    At bc#&quot;, bytecodeOffset, &quot; encountered invalid assignment to captured variable loc&quot;, virtualReg.toLocal(), &quot;.\n&quot;);
+            codeBlock-&gt;endValidationDidFail();
+            return;
+        }
+        
+        return;
+    }
+};
+
+} // anonymous namespace
+
</ins><span class="cx"> void CodeBlock::validate()
</span><span class="cx"> {
</span><span class="cx">     BytecodeLivenessAnalysis liveness(this); // Compute directly from scratch so it doesn't effect CodeBlock footprint.
</span><span class="lines">@@ -3467,6 +3524,16 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+    
+    for (unsigned bytecodeOffset = 0; bytecodeOffset &lt; instructions().size();) {
+        Instruction* currentInstruction = instructions().begin() + bytecodeOffset;
+        OpcodeID opcodeID = m_vm-&gt;interpreter-&gt;getOpcodeID(currentInstruction-&gt;u.opcode);
+        
+        VerifyCapturedDef verifyCapturedDef;
+        computeDefsForBytecodeOffset(this, bytecodeOffset, verifyCapturedDef);
+        
+        bytecodeOffset += opcodeLength(opcodeID);
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void CodeBlock::beginValidationDidFail()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.h (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -930,7 +930,12 @@
</span><span class="cx">     bool m_allTransitionsHaveBeenMarked; // Initialized and used on every GC.
</span><span class="cx">     
</span><span class="cx">     bool m_didFailFTLCompilation;
</span><del>-    
</del><ins>+
+    // Internal methods for use by validation code. It would be private if it wasn't
+    // for the fact that we use it from anonymous namespaces.
+    void beginValidationDidFail();
+    NO_RETURN_DUE_TO_CRASH void endValidationDidFail();
+
</ins><span class="cx"> protected:
</span><span class="cx">     virtual void visitWeakReferences(SlotVisitor&amp;) OVERRIDE;
</span><span class="cx">     virtual void finalizeUnconditionally() OVERRIDE;
</span><span class="lines">@@ -1031,9 +1036,6 @@
</span><span class="cx">             m_rareData = adoptPtr(new RareData);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void beginValidationDidFail();
-    NO_RETURN_DUE_TO_CRASH void endValidationDidFail();
-
</del><span class="cx"> #if ENABLE(JIT)
</span><span class="cx">     void resetStubInternal(RepatchBuffer&amp;, StructureStubInfo&amp;);
</span><span class="cx">     void resetStubDuringGCInternal(RepatchBuffer&amp;, StructureStubInfo&amp;);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeOpcodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/Opcode.h (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/Opcode.h        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/bytecode/Opcode.h        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -55,6 +55,7 @@
</span><span class="cx">     macro(op_new_array_buffer, 5) \
</span><span class="cx">     macro(op_new_regexp, 3) \
</span><span class="cx">     macro(op_mov, 3) \
</span><ins>+    macro(op_captured_mov, 3) \
</ins><span class="cx">     \
</span><span class="cx">     macro(op_not, 3) \
</span><span class="cx">     macro(op_eq, 4) \
</span><span class="lines">@@ -154,6 +155,7 @@
</span><span class="cx">     macro(op_switch_string, 4) \
</span><span class="cx">     \
</span><span class="cx">     macro(op_new_func, 4) \
</span><ins>+    macro(op_new_captured_func, 4) \
</ins><span class="cx">     macro(op_new_func_exp, 3) \
</span><span class="cx">     macro(op_call, 8) /* has value profiling */ \
</span><span class="cx">     macro(op_call_eval, 8) /* has value profiling */ \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -307,7 +307,7 @@
</span><span class="cx">                     instructions().append(m_activationRegister-&gt;index());
</span><span class="cx">                 }
</span><span class="cx">                 m_functions.add(ident.impl());
</span><del>-                emitNewFunction(addVar(ident, false), function);
</del><ins>+                emitNewFunction(addVar(ident, false), IsCaptured, function);
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         for (size_t i = 0; i &lt; varStack.size(); ++i) {
</span><span class="lines">@@ -335,7 +335,7 @@
</span><span class="cx">             // Don't lazily create functions that override the name 'arguments'
</span><span class="cx">             // as this would complicate lazy instantiation of actual arguments.
</span><span class="cx">             if (!canLazilyCreateFunctions || ident == propertyNames().arguments)
</span><del>-                emitNewFunction(reg.get(), function);
</del><ins>+                emitNewFunction(reg.get(), NotCaptured, function);
</ins><span class="cx">             else {
</span><span class="cx">                 emitInitLazyRegister(reg.get());
</span><span class="cx">                 m_lazyFunctions.set(reg-&gt;virtualRegister().toLocal(), function);
</span><span class="lines">@@ -475,7 +475,7 @@
</span><span class="cx">         return &amp;m_calleeRegister;
</span><span class="cx"> 
</span><span class="cx">     // Move the callee into the captured section of the stack.
</span><del>-    return emitMove(addVar(), &amp;m_calleeRegister);
</del><ins>+    return emitMove(addVar(), IsCaptured, &amp;m_calleeRegister);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void BytecodeGenerator::addCallee(FunctionBodyNode* functionBodyNode, RegisterID* calleeRegister)
</span><span class="lines">@@ -1000,16 +1000,21 @@
</span><span class="cx">     return m_codeBlock-&gt;addRegExp(r);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, RegisterID* src)
</del><ins>+RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, CaptureMode captureMode, RegisterID* src)
</ins><span class="cx"> {
</span><span class="cx">     m_staticPropertyAnalyzer.mov(dst-&gt;index(), src-&gt;index());
</span><span class="cx"> 
</span><del>-    emitOpcode(op_mov);
</del><ins>+    emitOpcode(captureMode == IsCaptured ? op_captured_mov : op_mov);
</ins><span class="cx">     instructions().append(dst-&gt;index());
</span><span class="cx">     instructions().append(src-&gt;index());
</span><span class="cx">     return dst;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, RegisterID* src)
+{
+    return emitMove(dst, captureMode(dst-&gt;index()), src);
+}
+
</ins><span class="cx"> RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src)
</span><span class="cx"> {
</span><span class="cx">     emitOpcode(opcodeID);
</span><span class="lines">@@ -1160,11 +1165,16 @@
</span><span class="cx">     return m_globalObjectRegister;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool BytecodeGenerator::isCaptured(int operand)
+{
+    return m_symbolTable &amp;&amp; m_symbolTable-&gt;isCaptured(operand);
+}
+
</ins><span class="cx"> Local BytecodeGenerator::local(const Identifier&amp; property)
</span><span class="cx"> {
</span><span class="cx">     if (property == propertyNames().thisIdentifier)
</span><del>-        return Local(thisRegister(), ReadOnly);
-
</del><ins>+        return Local(thisRegister(), ReadOnly, NotCaptured);
+    
</ins><span class="cx">     if (property == propertyNames().arguments)
</span><span class="cx">         createArgumentsIfNecessary();
</span><span class="cx"> 
</span><span class="lines">@@ -1176,7 +1186,7 @@
</span><span class="cx">         return Local();
</span><span class="cx"> 
</span><span class="cx">     RegisterID* local = createLazyRegisterIfNecessary(&amp;registerFor(entry.getIndex()));
</span><del>-    return Local(local, entry.getAttributes());
</del><ins>+    return Local(local, entry.getAttributes(), captureMode(local-&gt;index()));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Local BytecodeGenerator::constLocal(const Identifier&amp; property)
</span><span class="lines">@@ -1189,7 +1199,7 @@
</span><span class="cx">         return Local();
</span><span class="cx"> 
</span><span class="cx">     RegisterID* local = createLazyRegisterIfNecessary(&amp;registerFor(entry.getIndex()));
</span><del>-    return Local(local, entry.getAttributes());
</del><ins>+    return Local(local, entry.getAttributes(), captureMode(local-&gt;index()));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void BytecodeGenerator::emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target)
</span><span class="lines">@@ -1550,9 +1560,9 @@
</span><span class="cx">     return dst;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function)
</del><ins>+RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, CaptureMode captureMode, FunctionBodyNode* function)
</ins><span class="cx"> {
</span><del>-    return emitNewFunctionInternal(dst, m_codeBlock-&gt;addFunctionDecl(makeFunction(function)), false);
</del><ins>+    return emitNewFunctionInternal(dst, captureMode, m_codeBlock-&gt;addFunctionDecl(makeFunction(function)), false);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> RegisterID* BytecodeGenerator::emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* function)
</span><span class="lines">@@ -1560,13 +1570,13 @@
</span><span class="cx">     FunctionOffsetMap::AddResult ptr = m_functionOffsets.add(function, 0);
</span><span class="cx">     if (ptr.isNewEntry)
</span><span class="cx">         ptr.iterator-&gt;value = m_codeBlock-&gt;addFunctionDecl(makeFunction(function));
</span><del>-    return emitNewFunctionInternal(dst, ptr.iterator-&gt;value, true);
</del><ins>+    return emitNewFunctionInternal(dst, NotCaptured, ptr.iterator-&gt;value, true);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-RegisterID* BytecodeGenerator::emitNewFunctionInternal(RegisterID* dst, unsigned index, bool doNullCheck)
</del><ins>+RegisterID* BytecodeGenerator::emitNewFunctionInternal(RegisterID* dst, CaptureMode captureMode, unsigned index, bool doNullCheck)
</ins><span class="cx"> {
</span><span class="cx">     createActivationIfNecessary();
</span><del>-    emitOpcode(op_new_func);
</del><ins>+    emitOpcode(captureMode == IsCaptured ? op_new_captured_func : op_new_func);
</ins><span class="cx">     instructions().append(dst-&gt;index());
</span><span class="cx">     instructions().append(index);
</span><span class="cx">     instructions().append(doNullCheck);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -114,6 +114,11 @@
</span><span class="cx">         TryData* tryData;
</span><span class="cx">     };
</span><span class="cx"> 
</span><ins>+    enum CaptureMode {
+        NotCaptured,
+        IsCaptured
+    };
+
</ins><span class="cx">     class Local {
</span><span class="cx">     public:
</span><span class="cx">         Local()
</span><span class="lines">@@ -122,9 +127,10 @@
</span><span class="cx">         {
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        Local(RegisterID* local, unsigned attributes)
</del><ins>+        Local(RegisterID* local, unsigned attributes, CaptureMode captureMode)
</ins><span class="cx">             : m_local(local)
</span><span class="cx">             , m_attributes(attributes)
</span><ins>+            , m_isCaptured(captureMode == IsCaptured)
</ins><span class="cx">         {
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -133,10 +139,14 @@
</span><span class="cx">         RegisterID* get() { return m_local; }
</span><span class="cx"> 
</span><span class="cx">         bool isReadOnly() { return m_attributes &amp; ReadOnly; }
</span><ins>+        
+        bool isCaptured() { return m_isCaptured; }
+        CaptureMode captureMode() { return isCaptured() ? IsCaptured : NotCaptured; }
</ins><span class="cx"> 
</span><span class="cx">     private:
</span><span class="cx">         RegisterID* m_local;
</span><span class="cx">         unsigned m_attributes;
</span><ins>+        bool m_isCaptured;
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     struct TryRange {
</span><span class="lines">@@ -171,6 +181,9 @@
</span><span class="cx">         bool willResolveToArguments(const Identifier&amp;);
</span><span class="cx">         RegisterID* uncheckedRegisterForArguments();
</span><span class="cx"> 
</span><ins>+        bool isCaptured(int operand);
+        CaptureMode captureMode(int operand) { return isCaptured(operand) ? IsCaptured : NotCaptured; }
+        
</ins><span class="cx">         Local local(const Identifier&amp;);
</span><span class="cx">         Local constLocal(const Identifier&amp;);
</span><span class="cx"> 
</span><span class="lines">@@ -231,6 +244,8 @@
</span><span class="cx">         {
</span><span class="cx">             // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary.
</span><span class="cx">             ASSERT(!dst || dst == ignoredResult() || !dst-&gt;isTemporary() || dst-&gt;refCount());
</span><ins>+            // Should never store directly into a captured variable.
+            ASSERT(!dst || dst == ignoredResult() || !isCaptured(dst-&gt;index()));
</ins><span class="cx">             if (!m_vm-&gt;isSafeToRecurse()) {
</span><span class="cx">                 emitThrowExpressionTooDeepException();
</span><span class="cx">                 return;
</span><span class="lines">@@ -247,6 +262,8 @@
</span><span class="cx">         {
</span><span class="cx">             // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary.
</span><span class="cx">             ASSERT(!dst || dst == ignoredResult() || !dst-&gt;isTemporary() || dst-&gt;refCount());
</span><ins>+            // Should never store directly into a captured variable.
+            ASSERT(!dst || dst == ignoredResult() || !isCaptured(dst-&gt;index()));
</ins><span class="cx">             if (!m_vm-&gt;isSafeToRecurse())
</span><span class="cx">                 return emitThrowExpressionTooDeepException();
</span><span class="cx">             return n-&gt;emitBytecode(*this, dst);
</span><span class="lines">@@ -329,12 +346,13 @@
</span><span class="cx">         RegisterID* emitNewObject(RegisterID* dst);
</span><span class="cx">         RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision
</span><span class="cx"> 
</span><del>-        RegisterID* emitNewFunction(RegisterID* dst, FunctionBodyNode* body);
</del><ins>+        RegisterID* emitNewFunction(RegisterID* dst, CaptureMode, FunctionBodyNode*);
</ins><span class="cx">         RegisterID* emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* body);
</span><del>-        RegisterID* emitNewFunctionInternal(RegisterID* dst, unsigned index, bool shouldNullCheck);
</del><ins>+        RegisterID* emitNewFunctionInternal(RegisterID* dst, CaptureMode, unsigned index, bool shouldNullCheck);
</ins><span class="cx">         RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func);
</span><span class="cx">         RegisterID* emitNewRegExp(RegisterID* dst, RegExp*);
</span><span class="cx"> 
</span><ins>+        RegisterID* emitMove(RegisterID* dst, CaptureMode, RegisterID* src);
</ins><span class="cx">         RegisterID* emitMove(RegisterID* dst, RegisterID* src);
</span><span class="cx"> 
</span><span class="cx">         RegisterID* emitToNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_number, dst, src); }
</span><span class="lines">@@ -420,9 +438,9 @@
</span><span class="cx">         void pushFinallyContext(StatementNode* finallyBlock);
</span><span class="cx">         void popFinallyContext();
</span><span class="cx"> 
</span><del>-        void pushOptimisedForIn(RegisterID* expectedBase, RegisterID* iter, RegisterID* index, RegisterID* propertyRegister)
</del><ins>+        void pushOptimisedForIn(RegisterID* expectedSubscript, RegisterID* iter, RegisterID* index, RegisterID* propertyRegister)
</ins><span class="cx">         {
</span><del>-            ForInContext context = { expectedBase, iter, index, propertyRegister };
</del><ins>+            ForInContext context = { expectedSubscript, iter, index, propertyRegister };
</ins><span class="cx">             m_forInContextStack.append(context);
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerNodesCodegencpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -673,11 +673,22 @@
</span><span class="cx">     const Identifier&amp; ident = resolve-&gt;identifier();
</span><span class="cx"> 
</span><span class="cx">     if (Local local = generator.local(ident)) {
</span><ins>+        RegisterID* localReg = local.get();
</ins><span class="cx">         if (local.isReadOnly()) {
</span><span class="cx">             generator.emitReadOnlyExceptionIfNeeded();
</span><del>-            local = Local(generator.emitMove(generator.tempDestination(dst), local.get()), 0);
</del><ins>+            localReg = generator.emitMove(generator.tempDestination(dst), localReg);
</ins><span class="cx">         }
</span><del>-        return emitPostIncOrDec(generator, generator.finalDestination(dst), local.get(), m_operator);
</del><ins>+        if (local.isCaptured()) {
+            RefPtr&lt;RegisterID&gt; tempDst = generator.finalDestination(dst);
+            ASSERT(dst != localReg);
+            RefPtr&lt;RegisterID&gt; tempDstSrc = generator.newTemporary();
+            generator.emitToNumber(tempDst.get(), localReg);
+            generator.emitMove(tempDstSrc.get(), localReg);
+            emitIncOrDec(generator, tempDstSrc.get(), m_operator);
+            generator.emitMove(localReg, tempDstSrc.get());
+            return tempDst.get();
+        }
+        return emitPostIncOrDec(generator, generator.finalDestination(dst), localReg, m_operator);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><span class="lines">@@ -838,12 +849,20 @@
</span><span class="cx">     const Identifier&amp; ident = resolve-&gt;identifier();
</span><span class="cx"> 
</span><span class="cx">     if (Local local = generator.local(ident)) {
</span><ins>+        RegisterID* localReg = local.get();
</ins><span class="cx">         if (local.isReadOnly()) {
</span><span class="cx">             generator.emitReadOnlyExceptionIfNeeded();
</span><del>-            local = Local(generator.emitMove(generator.tempDestination(dst), local.get()), 0);
</del><ins>+            localReg = generator.emitMove(generator.tempDestination(dst), localReg);
</ins><span class="cx">         }
</span><del>-        emitIncOrDec(generator, local.get(), m_operator);
-        return generator.moveToDestinationIfNeeded(dst, local.get());
</del><ins>+        if (local.isCaptured()) {
+            RefPtr&lt;RegisterID&gt; tempDst = generator.tempDestination(dst);
+            generator.emitMove(tempDst.get(), localReg);
+            emitIncOrDec(generator, tempDst.get(), m_operator);
+            generator.emitMove(localReg, tempDst.get());
+            return generator.moveToDestinationIfNeeded(dst, tempDst.get());
+        }
+        emitIncOrDec(generator, localReg, m_operator);
+        return generator.moveToDestinationIfNeeded(dst, localReg);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><span class="lines">@@ -1327,7 +1346,8 @@
</span><span class="cx">             return emitReadModifyAssignment(generator, generator.finalDestination(dst), local.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right-&gt;resultDescriptor()));
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right-&gt;isPure(generator))) {
</del><ins>+        if (local.isCaptured()
+            || generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right-&gt;isPure(generator))) {
</ins><span class="cx">             RefPtr&lt;RegisterID&gt; result = generator.newTemporary();
</span><span class="cx">             generator.emitMove(result.get(), local.get());
</span><span class="cx">             emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right-&gt;resultDescriptor()));
</span><span class="lines">@@ -1356,6 +1376,12 @@
</span><span class="cx">             generator.emitReadOnlyExceptionIfNeeded();
</span><span class="cx">             return generator.emitNode(dst, m_right);
</span><span class="cx">         }
</span><ins>+        if (local.isCaptured()) {
+            RefPtr&lt;RegisterID&gt; tempDst = generator.tempDestination(dst);
+            generator.emitNode(tempDst.get(), m_right);
+            generator.emitMove(local.get(), tempDst.get());
+            return generator.moveToDestinationIfNeeded(dst, tempDst.get());
+        }
</ins><span class="cx">         RegisterID* result = generator.emitNode(local.get(), m_right);
</span><span class="cx">         return generator.moveToDestinationIfNeeded(dst, result);
</span><span class="cx">     }
</span><span class="lines">@@ -1451,11 +1477,17 @@
</span><span class="cx"> RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator&amp; generator)
</span><span class="cx"> {
</span><span class="cx">     // FIXME: This code does not match the behavior of const in Firefox.
</span><del>-    if (RegisterID* local = generator.constLocal(m_ident).get()) {
</del><ins>+    if (Local local = generator.constLocal(m_ident)) {
</ins><span class="cx">         if (!m_init)
</span><del>-            return local;
</del><ins>+            return local.get();
</ins><span class="cx"> 
</span><del>-        return generator.emitNode(local, m_init);
</del><ins>+        if (local.isCaptured()) {
+            RefPtr&lt;RegisterID&gt; tempDst = generator.newTemporary();
+            generator.emitNode(tempDst.get(), m_init);
+            return generator.emitMove(local.get(), tempDst.get());
+        }
+        
+        return generator.emitNode(local.get(), m_init);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     RefPtr&lt;RegisterID&gt; value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined());
</span><span class="lines">@@ -1730,8 +1762,7 @@
</span><span class="cx">     if (m_lexpr-&gt;isResolveNode()) {
</span><span class="cx">         const Identifier&amp; ident = static_cast&lt;ResolveNode*&gt;(m_lexpr)-&gt;identifier();
</span><span class="cx">         Local local = generator.local(ident);
</span><del>-        propertyName = local.get();
-        if (!propertyName) {
</del><ins>+        if (!local.get()) {
</ins><span class="cx">             propertyName = generator.newTemporary();
</span><span class="cx">             RefPtr&lt;RegisterID&gt; protect = propertyName;
</span><span class="cx">             if (generator.isStrictMode())
</span><span class="lines">@@ -1740,8 +1771,10 @@
</span><span class="cx">             generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><span class="cx">             generator.emitPutToScope(scope, ident, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
</span><span class="cx">         } else {
</span><del>-            expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName);
-            generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName);
</del><ins>+            expectedSubscript = generator.newTemporary();
+            propertyName = expectedSubscript.get();
+            generator.emitMove(local.get(), propertyName);
+            generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), local.get());
</ins><span class="cx">             optimizedForinAccess = true;
</span><span class="cx">         }
</span><span class="cx">     } else if (m_lexpr-&gt;isDotAccessorNode()) {
</span><span class="lines">@@ -1771,7 +1804,7 @@
</span><span class="cx">             Identifier ident = simpleBinding-&gt;boundProperty();
</span><span class="cx">             Local local = generator.local(ident);
</span><span class="cx">             propertyName = local.get();
</span><del>-            if (!propertyName)
</del><ins>+            if (!propertyName || local.isCaptured())
</ins><span class="cx">                 goto genericBinding;
</span><span class="cx">             expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName);
</span><span class="cx">             generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -2146,7 +2146,8 @@
</span><span class="cx">             addToGraph(Breakpoint);
</span><span class="cx">             NEXT_OPCODE(op_debug);
</span><span class="cx"> #endif
</span><del>-        case op_mov: {
</del><ins>+        case op_mov:
+        case op_captured_mov: {
</ins><span class="cx">             Node* op = get(VirtualRegister(currentInstruction[2].u.operand));
</span><span class="cx">             set(VirtualRegister(currentInstruction[1].u.operand), op);
</span><span class="cx">             NEXT_OPCODE(op_mov);
</span><span class="lines">@@ -3226,7 +3227,8 @@
</span><span class="cx">             NEXT_OPCODE(op_get_argument_by_val);
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        case op_new_func: {
</del><ins>+        case op_new_func:
+        case op_new_captured_func: {
</ins><span class="cx">             if (!currentInstruction[3].u.operand) {
</span><span class="cx">                 set(VirtualRegister(currentInstruction[1].u.operand),
</span><span class="cx">                     addToGraph(NewFunctionNoCheck, OpInfo(currentInstruction[2].u.operand)));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -103,6 +103,7 @@
</span><span class="cx">     case op_debug:
</span><span class="cx"> #endif
</span><span class="cx">     case op_mov:
</span><ins>+    case op_captured_mov:
</ins><span class="cx">     case op_check_has_instance:
</span><span class="cx">     case op_instanceof:
</span><span class="cx">     case op_is_undefined:
</span><span class="lines">@@ -202,6 +203,7 @@
</span><span class="cx">     case op_create_activation:
</span><span class="cx">     case op_tear_off_activation:
</span><span class="cx">     case op_new_func:
</span><ins>+    case op_new_captured_func:
</ins><span class="cx">     case op_new_func_exp:
</span><span class="cx">     case op_switch_string: // Don't inline because we don't want to copy string tables in the concurrent JIT.
</span><span class="cx">         return CanCompile;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JIT.cpp (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JIT.cpp        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/jit/JIT.cpp        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -226,6 +226,7 @@
</span><span class="cx">         DEFINE_OP(op_loop_hint)
</span><span class="cx">         DEFINE_OP(op_lshift)
</span><span class="cx">         DEFINE_OP(op_mod)
</span><ins>+        case op_captured_mov:
</ins><span class="cx">         DEFINE_OP(op_mov)
</span><span class="cx">         DEFINE_OP(op_mul)
</span><span class="cx">         DEFINE_OP(op_negate)
</span><span class="lines">@@ -234,6 +235,7 @@
</span><span class="cx">         DEFINE_OP(op_new_array)
</span><span class="cx">         DEFINE_OP(op_new_array_with_size)
</span><span class="cx">         DEFINE_OP(op_new_array_buffer)
</span><ins>+        case op_new_captured_func:
</ins><span class="cx">         DEFINE_OP(op_new_func)
</span><span class="cx">         DEFINE_OP(op_new_func_exp)
</span><span class="cx">         DEFINE_OP(op_new_object)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -542,6 +542,16 @@
</span><span class="cx">     dispatch(3)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+_llint_op_captured_mov:
+    traceExecution()
+    loadi 8[PC], t1
+    loadi 4[PC], t0
+    loadConstantOrVariable(t1, t2, t3)
+    storei t2, TagOffset[cfr, t0, 8]
+    storei t3, PayloadOffset[cfr, t0, 8]
+    dispatch(3)
+
+
</ins><span class="cx"> _llint_op_not:
</span><span class="cx">     traceExecution()
</span><span class="cx">     loadi 8[PC], t0
</span><span class="lines">@@ -1662,6 +1672,17 @@
</span><span class="cx">     dispatch(4)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+_llint_op_new_captured_func:
+    traceExecution()
+    btiz 12[PC], .opNewCapturedFuncUnchecked
+    loadi 4[PC], t1
+    bineq TagOffset[cfr, t1, 8], EmptyValueTag, .opNewCapturedFuncDone
+.opNewCapturedFuncUnchecked:
+    callSlowPath(_llint_slow_path_new_func)
+.opNewCapturedFuncDone:
+    dispatch(4)
+
+
</ins><span class="cx"> macro arrayProfileForCall()
</span><span class="cx">     if VALUE_PROFILER
</span><span class="cx">         loadi 16[PC], t3
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -418,6 +418,15 @@
</span><span class="cx">     dispatch(3)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+_llint_op_captured_mov:
+    traceExecution()
+    loadisFromInstruction(2, t1)
+    loadisFromInstruction(1, t0)
+    loadConstantOrVariable(t1, t2)
+    storeq t2, [cfr, t0, 8]
+    dispatch(3)
+
+
</ins><span class="cx"> _llint_op_not:
</span><span class="cx">     traceExecution()
</span><span class="cx">     loadisFromInstruction(2, t0)
</span><span class="lines">@@ -1514,6 +1523,18 @@
</span><span class="cx">     dispatch(4)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+_llint_op_new_captured_func:
+    traceExecution()
+    loadisFromInstruction(3, t2)
+    btiz t2, .opNewCapturedFuncUnchecked
+    loadisFromInstruction(1, t1)
+    btqnz [cfr, t1, 8], .opNewCapturedFuncDone
+.opNewCapturedFuncUnchecked:
+    callSlowPath(_llint_slow_path_new_func)
+.opNewCapturedFuncDone:
+    dispatch(4)
+
+
</ins><span class="cx"> macro arrayProfileForCall()
</span><span class="cx">     if VALUE_PROFILER
</span><span class="cx">         loadisFromInstruction(4, t3)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeSymbolTableh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/SymbolTable.h (159942 => 159943)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/SymbolTable.h        2013-12-02 19:09:15 UTC (rev 159942)
+++ trunk/Source/JavaScriptCore/runtime/SymbolTable.h        2013-12-02 19:49:43 UTC (rev 159943)
</span><span class="lines">@@ -453,6 +453,11 @@
</span><span class="cx">     void setCaptureEnd(int captureEnd) { m_captureEnd = captureEnd; }
</span><span class="cx"> 
</span><span class="cx">     int captureCount() const { return -(m_captureEnd - m_captureStart); }
</span><ins>+    
+    bool isCaptured(int operand)
+    {
+        return operand &lt;= captureStart() &amp;&amp; operand &gt; captureEnd();
+    }
</ins><span class="cx"> 
</span><span class="cx">     int parameterCount() { return m_parameterCountIncludingThis - 1; }
</span><span class="cx">     int parameterCountIncludingThis() { return m_parameterCountIncludingThis; }
</span></span></pre>
</div>
</div>

</body>
</html>