<!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>[161465] trunk/Source/JavaScriptCore</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/161465">161465</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-01-07 16:27:06 -0800 (Tue, 07 Jan 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>DFG fixup phase should be responsible for inserting ValueToInt32's as needed and it should use Phantom to keep the original values alive in case of OSR exit
https://bugs.webkit.org/show_bug.cgi?id=126600

Reviewed by Michael Saboff.
        
This fixes an embarrassing OSR exit liveness bug. It also simplifies the code. We were
already using FixupPhase as the place where conversion nodes get inserted. ValueToInt32
was the only exception to that rule, and that was one of the reasons why we had this bug.
        
Henceforth ValueToInt32 is only inserted by FixupPhase, and only when it is necessary:
we have a BitOp that will want a ToInt32 conversion and the operand is not predicted to
already be an int32. If FixupPhase inserts any ValueToInt32's then the BitOp will no
longer appear to use the original operand, which will make OSR exit think that the
original operand is dead. We work around this they way we always do: insert a Phantom on
the original operands right after the BitOp. This ensures that any OSR exit in any of the
ValueToInt32's or in the BitOp itself will have values for the original inputs.

* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwo):
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsic):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixIntEdge):
(JSC::DFG::FixupPhase::fixBinaryIntEdges):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* tests/stress/bit-op-value-to-int32-input-liveness.js: Added.
(foo):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGBackwardsPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressbitopvaluetoint32inputlivenessjs">trunk/Source/JavaScriptCore/tests/stress/bit-op-value-to-int32-input-liveness.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (161464 => 161465)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-01-08 00:12:03 UTC (rev 161464)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-01-08 00:27:06 UTC (rev 161465)
</span><span class="lines">@@ -1,3 +1,37 @@
</span><ins>+2014-01-07  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        DFG fixup phase should be responsible for inserting ValueToInt32's as needed and it should use Phantom to keep the original values alive in case of OSR exit
+        https://bugs.webkit.org/show_bug.cgi?id=126600
+
+        Reviewed by Michael Saboff.
+        
+        This fixes an embarrassing OSR exit liveness bug. It also simplifies the code. We were
+        already using FixupPhase as the place where conversion nodes get inserted. ValueToInt32
+        was the only exception to that rule, and that was one of the reasons why we had this bug.
+        
+        Henceforth ValueToInt32 is only inserted by FixupPhase, and only when it is necessary:
+        we have a BitOp that will want a ToInt32 conversion and the operand is not predicted to
+        already be an int32. If FixupPhase inserts any ValueToInt32's then the BitOp will no
+        longer appear to use the original operand, which will make OSR exit think that the
+        original operand is dead. We work around this they way we always do: insert a Phantom on
+        the original operands right after the BitOp. This ensures that any OSR exit in any of the
+        ValueToInt32's or in the BitOp itself will have values for the original inputs.
+
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwo):
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsic):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::fixIntEdge):
+        (JSC::DFG::FixupPhase::fixBinaryIntEdges):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * tests/stress/bit-op-value-to-int32-input-liveness.js: Added.
+        (foo):
+
</ins><span class="cx"> 2014-01-07  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Repatch write barrier slow path call doesn't align the stack in the presence of saved registers
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGBackwardsPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp (161464 => 161465)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp        2014-01-08 00:12:03 UTC (rev 161464)
+++ trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp        2014-01-08 00:27:06 UTC (rev 161465)
</span><span class="lines">@@ -114,8 +114,7 @@
</span><span class="cx">             
</span><span class="cx">         case BitOr:
</span><span class="cx">         case BitXor:
</span><del>-        case BitLShift:
-        case ValueToInt32: {
</del><ins>+        case BitLShift: {
</ins><span class="cx">             return power &gt; 31;
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="lines">@@ -205,13 +204,6 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        case ValueToInt32: {
-            flags |= NodeBytecodeUsesAsInt;
-            flags &amp;= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther);
-            node-&gt;child1()-&gt;mergeFlags(flags);
-            break;
-        }
-            
</del><span class="cx">         case StringCharCodeAt: {
</span><span class="cx">             node-&gt;child1()-&gt;mergeFlags(NodeBytecodeUsesAsValue);
</span><span class="cx">             node-&gt;child2()-&gt;mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (161464 => 161465)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-01-08 00:12:03 UTC (rev 161464)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-01-08 00:27:06 UTC (rev 161465)
</span><span class="lines">@@ -505,30 +505,6 @@
</span><span class="cx">         flush(m_inlineStackTop);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Get an operand, and perform a ToInt32/ToNumber conversion on it.
-    Node* getToInt32(int operand)
-    {
-        return toInt32(get(VirtualRegister(operand)));
-    }
-
-    // Perform an ES5 ToInt32 operation - returns a node of type NodeResultInt32.
-    Node* toInt32(Node* node)
-    {
-        if (node-&gt;hasInt32Result())
-            return node;
-
-        // Check for numeric constants boxed as JSValues.
-        if (canFold(node)) {
-            JSValue v = valueOfJSConstant(node);
-            if (v.isInt32())
-                return getJSConstant(node-&gt;constantNumber());
-            if (v.isNumber())
-                return getJSConstantForValue(JSValue(JSC::toInt32(v.asNumber())));
-        }
-
-        return addToGraph(ValueToInt32, node);
-    }
-
</del><span class="cx">     // NOTE: Only use this to construct constants that arise from non-speculative
</span><span class="cx">     // constant folding. I.e. creating constants using this if we had constant
</span><span class="cx">     // field inference would be a bad idea, since the bytecode parser's folding
</span><span class="lines">@@ -1577,9 +1553,9 @@
</span><span class="cx">         if (argumentCountIncludingThis != 2)
</span><span class="cx">             return false;
</span><span class="cx"> 
</span><del>-        int thisOperand = virtualRegisterForArgument(0, registerOffset).offset();
-        int indexOperand = virtualRegisterForArgument(1, registerOffset).offset();
-        Node* charCode = addToGraph(StringCharCodeAt, OpInfo(ArrayMode(Array::String).asWord()), get(VirtualRegister(thisOperand)), getToInt32(indexOperand));
</del><ins>+        VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset);
+        VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset);
+        Node* charCode = addToGraph(StringCharCodeAt, OpInfo(ArrayMode(Array::String).asWord()), get(thisOperand), get(indexOperand));
</ins><span class="cx"> 
</span><span class="cx">         set(VirtualRegister(resultOperand), charCode);
</span><span class="cx">         return true;
</span><span class="lines">@@ -1589,9 +1565,9 @@
</span><span class="cx">         if (argumentCountIncludingThis != 2)
</span><span class="cx">             return false;
</span><span class="cx"> 
</span><del>-        int thisOperand = virtualRegisterForArgument(0, registerOffset).offset();
-        int indexOperand = virtualRegisterForArgument(1, registerOffset).offset();
-        Node* charCode = addToGraph(StringCharAt, OpInfo(ArrayMode(Array::String).asWord()), get(VirtualRegister(thisOperand)), getToInt32(indexOperand));
</del><ins>+        VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset);
+        VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset);
+        Node* charCode = addToGraph(StringCharAt, OpInfo(ArrayMode(Array::String).asWord()), get(thisOperand), get(indexOperand));
</ins><span class="cx"> 
</span><span class="cx">         set(VirtualRegister(resultOperand), charCode);
</span><span class="cx">         return true;
</span><span class="lines">@@ -1600,8 +1576,8 @@
</span><span class="cx">         if (argumentCountIncludingThis != 2)
</span><span class="cx">             return false;
</span><span class="cx"> 
</span><del>-        int indexOperand = virtualRegisterForArgument(1, registerOffset).offset();
-        Node* charCode = addToGraph(StringFromCharCode, getToInt32(indexOperand));
</del><ins>+        VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset);
+        Node* charCode = addToGraph(StringFromCharCode, get(indexOperand));
</ins><span class="cx"> 
</span><span class="cx">         set(VirtualRegister(resultOperand), charCode);
</span><span class="cx"> 
</span><span class="lines">@@ -1631,10 +1607,10 @@
</span><span class="cx">     case IMulIntrinsic: {
</span><span class="cx">         if (argumentCountIncludingThis != 3)
</span><span class="cx">             return false;
</span><del>-        int leftOperand = virtualRegisterForArgument(1, registerOffset).offset();
-        int rightOperand = virtualRegisterForArgument(2, registerOffset).offset();
-        Node* left = getToInt32(leftOperand);
-        Node* right = getToInt32(rightOperand);
</del><ins>+        VirtualRegister leftOperand = virtualRegisterForArgument(1, registerOffset);
+        VirtualRegister rightOperand = virtualRegisterForArgument(2, registerOffset);
+        Node* left = get(leftOperand);
+        Node* right = get(rightOperand);
</ins><span class="cx">         set(VirtualRegister(resultOperand), addToGraph(ArithIMul, left, right));
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="lines">@@ -2053,45 +2029,45 @@
</span><span class="cx">         // === Bitwise operations ===
</span><span class="cx"> 
</span><span class="cx">         case op_bitand: {
</span><del>-            Node* op1 = getToInt32(currentInstruction[2].u.operand);
-            Node* op2 = getToInt32(currentInstruction[3].u.operand);
</del><ins>+            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
</ins><span class="cx">             set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(BitAnd, op1, op2));
</span><span class="cx">             NEXT_OPCODE(op_bitand);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case op_bitor: {
</span><del>-            Node* op1 = getToInt32(currentInstruction[2].u.operand);
-            Node* op2 = getToInt32(currentInstruction[3].u.operand);
</del><ins>+            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
</ins><span class="cx">             set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(BitOr, op1, op2));
</span><span class="cx">             NEXT_OPCODE(op_bitor);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case op_bitxor: {
</span><del>-            Node* op1 = getToInt32(currentInstruction[2].u.operand);
-            Node* op2 = getToInt32(currentInstruction[3].u.operand);
</del><ins>+            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
</ins><span class="cx">             set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(BitXor, op1, op2));
</span><span class="cx">             NEXT_OPCODE(op_bitxor);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case op_rshift: {
</span><del>-            Node* op1 = getToInt32(currentInstruction[2].u.operand);
-            Node* op2 = getToInt32(currentInstruction[3].u.operand);
</del><ins>+            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
</ins><span class="cx">             set(VirtualRegister(currentInstruction[1].u.operand),
</span><span class="cx">                 addToGraph(BitRShift, op1, op2));
</span><span class="cx">             NEXT_OPCODE(op_rshift);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case op_lshift: {
</span><del>-            Node* op1 = getToInt32(currentInstruction[2].u.operand);
-            Node* op2 = getToInt32(currentInstruction[3].u.operand);
</del><ins>+            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
</ins><span class="cx">             set(VirtualRegister(currentInstruction[1].u.operand),
</span><span class="cx">                 addToGraph(BitLShift, op1, op2));
</span><span class="cx">             NEXT_OPCODE(op_lshift);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case op_urshift: {
</span><del>-            Node* op1 = getToInt32(currentInstruction[2].u.operand);
-            Node* op2 = getToInt32(currentInstruction[3].u.operand);
</del><ins>+            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
</ins><span class="cx">             set(VirtualRegister(currentInstruction[1].u.operand),
</span><span class="cx">                 addToGraph(BitURShift, op1, op2));
</span><span class="cx">             NEXT_OPCODE(op_urshift);
</span><span class="lines">@@ -2099,7 +2075,7 @@
</span><span class="cx">             
</span><span class="cx">         case op_unsigned: {
</span><span class="cx">             set(VirtualRegister(currentInstruction[1].u.operand),
</span><del>-                makeSafe(addToGraph(UInt32ToNumber, getToInt32(currentInstruction[2].u.operand))));
</del><ins>+                makeSafe(addToGraph(UInt32ToNumber, get(VirtualRegister(currentInstruction[2].u.operand)))));
</ins><span class="cx">             NEXT_OPCODE(op_unsigned);
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (161464 => 161465)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2014-01-08 00:12:03 UTC (rev 161464)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2014-01-08 00:27:06 UTC (rev 161465)
</span><span class="lines">@@ -94,24 +94,18 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        case BitOr: {
-            fixIntEdge(node-&gt;child1());
-            fixIntEdge(node-&gt;child2());
-            break;
-        }
</del><span class="cx">         case BitAnd:
</span><ins>+        case BitOr:
</ins><span class="cx">         case BitXor:
</span><span class="cx">         case BitRShift:
</span><span class="cx">         case BitLShift:
</span><span class="cx">         case BitURShift: {
</span><del>-            fixIntEdge(node-&gt;child1());
-            fixIntEdge(node-&gt;child2());
</del><ins>+            fixBinaryIntEdges();
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><del>-            
</del><ins>+
</ins><span class="cx">         case ArithIMul: {
</span><del>-            fixIntEdge(node-&gt;child1());
-            fixIntEdge(node-&gt;child2());
</del><ins>+            fixBinaryIntEdges();
</ins><span class="cx">             node-&gt;setOp(ArithMul);
</span><span class="cx">             node-&gt;setArithMode(Arith::Unchecked);
</span><span class="cx">             node-&gt;child1().setUseKind(Int32Use);
</span><span class="lines">@@ -120,7 +114,7 @@
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         case UInt32ToNumber: {
</span><del>-            fixEdge&lt;KnownInt32Use&gt;(node-&gt;child1());
</del><ins>+            fixIntEdge(node-&gt;child1());
</ins><span class="cx">             if (bytecodeCanTruncateInteger(node-&gt;arithNodeFlags()))
</span><span class="cx">                 node-&gt;convertToIdentity();
</span><span class="cx">             else if (nodeCanSpeculateInt32(node-&gt;arithNodeFlags()))
</span><span class="lines">@@ -130,42 +124,6 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        case DoubleAsInt32: {
-            RELEASE_ASSERT_NOT_REACHED();
-            break;
-        }
-            
-        case ValueToInt32: {
-            if (node-&gt;child1()-&gt;shouldSpeculateInt32()) {
-                fixEdge&lt;Int32Use&gt;(node-&gt;child1());
-                node-&gt;setOpAndDefaultFlags(Identity);
-                break;
-            }
-            
-            if (node-&gt;child1()-&gt;shouldSpeculateMachineInt()) {
-                fixEdge&lt;MachineIntUse&gt;(node-&gt;child1());
-                break;
-            }
-            
-            if (node-&gt;child1()-&gt;shouldSpeculateNumber()) {
-                fixEdge&lt;NumberUse&gt;(node-&gt;child1());
-                break;
-            }
-            
-            if (node-&gt;child1()-&gt;shouldSpeculateBoolean()) {
-                fixEdge&lt;BooleanUse&gt;(node-&gt;child1());
-                break;
-            }
-            
-            fixEdge&lt;NotCellUse&gt;(node-&gt;child1());
-            break;
-        }
-            
-        case Int32ToDouble: {
-            RELEASE_ASSERT_NOT_REACHED();
-            break;
-        }
-            
</del><span class="cx">         case ValueAdd: {
</span><span class="cx">             if (attemptToMakeIntegerAdd(node)) {
</span><span class="cx">                 node-&gt;setOp(ArithAdd);
</span><span class="lines">@@ -974,6 +932,9 @@
</span><span class="cx">         case CheckArray:
</span><span class="cx">         case CheckInBounds:
</span><span class="cx">         case ConstantStoragePointer:
</span><ins>+        case DoubleAsInt32:
+        case Int32ToDouble:
+        case ValueToInt32:
</ins><span class="cx">             // These are just nodes that we don't currently expect to see during fixup.
</span><span class="cx">             // If we ever wanted to insert them prior to fixup, then we just have to create
</span><span class="cx">             // fixup rules for them.
</span><span class="lines">@@ -1624,23 +1585,43 @@
</span><span class="cx">         m_insertionSet.insert(indexInBlock, barrierNode);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void fixIntEdge(Edge&amp; edge)
</del><ins>+    bool fixIntEdge(Edge&amp; edge)
</ins><span class="cx">     {
</span><span class="cx">         Node* node = edge.node();
</span><del>-        if (node-&gt;op() != ValueToInt32) {
-            fixEdge&lt;KnownInt32Use&gt;(edge);
-            return;
</del><ins>+        if (node-&gt;shouldSpeculateInt32()) {
+            fixEdge&lt;Int32Use&gt;(edge);
+            return false;
</ins><span class="cx">         }
</span><span class="cx">         
</span><del>-        Edge newEdge = node-&gt;child1();
</del><ins>+        UseKind useKind;
+        if (node-&gt;shouldSpeculateMachineInt())
+            useKind = MachineIntUse;
+        else if (node-&gt;shouldSpeculateNumber())
+            useKind = NumberUse;
+        else if (node-&gt;shouldSpeculateBoolean())
+            useKind = BooleanUse;
+        else
+            useKind = NotCellUse;
+        Node* newNode = m_insertionSet.insertNode(
+            m_indexInBlock, SpecInt32, ValueToInt32, m_currentNode-&gt;codeOrigin,
+            Edge(node, useKind));
+        observeUseKindOnNode(node, useKind);
</ins><span class="cx">         
</span><del>-        if (newEdge.useKind() != Int32Use) {
-            edge.setUseKind(KnownInt32Use);
-            return;
-        }
</del><ins>+        edge = Edge(newNode, KnownInt32Use);
+        return true;
+    }
+    
+    void fixBinaryIntEdges()
+    {
+        AdjacencyList children = m_currentNode-&gt;children;
</ins><span class="cx">         
</span><del>-        ASSERT(newEdge-&gt;shouldSpeculateInt32());
-        edge = newEdge;
</del><ins>+        // Call fixIntEdge() on both edges.
+        bool needPhantom =
+            fixIntEdge(m_currentNode-&gt;child1()) | fixIntEdge(m_currentNode-&gt;child2());
+        
+        if (!needPhantom)
+            return;
+        m_insertionSet.insertNode(m_indexInBlock + 1, SpecNone, Phantom, m_currentNode-&gt;codeOrigin, children);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void injectInt32ToDoubleNode(Edge&amp; edge, UseKind useKind = NumberUse)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (161464 => 161465)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2014-01-08 00:12:03 UTC (rev 161464)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2014-01-08 00:27:06 UTC (rev 161465)
</span><span class="lines">@@ -168,11 +168,6 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        case ValueToInt32: {
-            changed |= setPrediction(SpecInt32);
-            break;
-        }
-            
</del><span class="cx">         case ArrayPop:
</span><span class="cx">         case ArrayPush:
</span><span class="cx">         case RegExpExec:
</span><span class="lines">@@ -510,7 +505,8 @@
</span><span class="cx">         case InvalidationPoint:
</span><span class="cx">         case Int52ToValue:
</span><span class="cx">         case Int52ToDouble:
</span><del>-        case CheckInBounds: {
</del><ins>+        case CheckInBounds:
+        case ValueToInt32: {
</ins><span class="cx">             // This node should never be visible at this stage of compilation. It is
</span><span class="cx">             // inserted by fixup(), which follows this phase.
</span><span class="cx">             RELEASE_ASSERT_NOT_REACHED();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressbitopvaluetoint32inputlivenessjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/bit-op-value-to-int32-input-liveness.js (0 => 161465)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/bit-op-value-to-int32-input-liveness.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/bit-op-value-to-int32-input-liveness.js        2014-01-08 00:27:06 UTC (rev 161465)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+function foo(a, b) {
+    return a.f ^ b.f;
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var result = foo({f:5.5}, {f:6.5});
+    if (result != 3)
+        throw &quot;Error: bad result: &quot; + result;
+}
+
+var result = foo({f:&quot;5.5&quot;}, {f:6.5});
+if (result != 3)
+    throw &quot;Error: bad result: &quot; + result;
+
+var result = foo({f:5.5}, {f:&quot;6.5&quot;});
+if (result != 3)
+    throw &quot;Error: bad result: &quot; + result;
+
</ins></span></pre>
</div>
</div>

</body>
</html>