<!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>[188624] 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/188624">188624</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2015-08-18 21:09:12 -0700 (Tue, 18 Aug 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[JSC] Optimize more cases of something-compared-to-null/undefined
https://bugs.webkit.org/show_bug.cgi?id=148157

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2015-08-18
Reviewed by Geoffrey Garen and Filip Pizlo.

Source/JavaScriptCore:

CompareEq is fairly trivial if you assert one of the operands is either
null or undefined. Under those conditions, the only way to have &quot;true&quot;
is to have the other operand be null/undefined or have an object
that masquerades to undefined.

JSC already had a fast path in CompareEqConstant.
With this patch, I generalize this fast path to more cases and try
to eliminate the checks whenever possible.

CompareEq now does the job of CompareEqConstant. If any operand can
be proved to be undefined/other, its edge is set to OtherUse. Whenever
any edge is OtherUse, we generate the fast code we had for CompareEqConstant.

The AbstractInterpreter has additional checks to reduce the node to a constant
whenever possible.

There are two additional changes in this patch:
-The Fixup Phase tries to set edges to OtherUse early. This is done correctly
 in ConstantFoldingPhase but setting it up early helps the phases relying
 on Clobberize.
-The codegen for CompareEqConstant was improved. The reason is the comparison
 for ObjectOrOther could be faster just because the codegen was better.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize): Deleted.
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC): Deleted.
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::isUndefinedOrNullConstant):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate): Deleted.
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute): Deleted.
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compilePeepHoleBranch):
(JSC::DFG::SpeculativeJIT::compare):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::isKnownNotOther):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNullOrUndefined):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNullOrUndefined):
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): Deleted.
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): Deleted.
(JSC::DFG::SpeculativeJIT::nonSpeculativeCompareNull): Deleted.
(JSC::DFG::SpeculativeJIT::compile): Deleted.
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNullOrUndefined):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNullOrUndefined):
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): Deleted.
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): Deleted.
(JSC::DFG::SpeculativeJIT::nonSpeculativeCompareNull): Deleted.
(JSC::DFG::SpeculativeJIT::compile): Deleted.
* dfg/DFGValidate.cpp:
(JSC::DFG::Validate::validate): Deleted.
* dfg/DFGWatchpointCollectionPhase.cpp:
(JSC::DFG::WatchpointCollectionPhase::handle):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::compileCompareEq):
(JSC::FTL::DFG::LowerDFGToLLVM::compileNode): Deleted.
(JSC::FTL::DFG::LowerDFGToLLVM::compileCompareEqConstant): Deleted.
* tests/stress/compare-eq-on-null-and-undefined-non-peephole.js: Added.
(string_appeared_here.useForMath):
(testUseForMath):
* tests/stress/compare-eq-on-null-and-undefined-optimized-in-constant-folding.js: Added.
(string_appeared_here.unreachableCodeTest):
(inlinedCompareToNull):
(inlinedComparedToUndefined):
(warmupInlineFunctions):
(testInlineFunctions):
* tests/stress/compare-eq-on-null-and-undefined.js: Added.
(string_appeared_here.compareConstants):
(opaqueNull):
(opaqueUndefined):
(compareConstantsAndDynamicValues):
(compareDynamicValues):
(compareDynamicValueToItself):
(arrayTesting):
(opaqueCompare1):
(testNullComparatorUpdate):
(opaqueCompare2):
(testUndefinedComparatorUpdate):
(opaqueCompare3):
(testNullAndUndefinedComparatorUpdate):

LayoutTests:

* js/dom/document-all-watchpoint-covers-eliminated-compare-eq-expected.txt: Added.
* js/dom/document-all-watchpoint-covers-eliminated-compare-eq.html: Added.
* js/dom/script-tests/document-all-watchpoint-covers-eliminated-compare-eq.js: Added.
(compareFunction):</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="#trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDoesGCcpp">trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeh">trunk/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeTypeh">trunk/Source/JavaScriptCore/dfg/DFGNodeType.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSafeToExecuteh">trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITh">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGValidatecpp">trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGWatchpointCollectionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsdomdocumentallwatchpointcoverseliminatedcompareeqexpectedtxt">trunk/LayoutTests/js/dom/document-all-watchpoint-covers-eliminated-compare-eq-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsdomdocumentallwatchpointcoverseliminatedcompareeqhtml">trunk/LayoutTests/js/dom/document-all-watchpoint-covers-eliminated-compare-eq.html</a></li>
<li><a href="#trunkLayoutTestsjsdomscripttestsdocumentallwatchpointcoverseliminatedcompareeqjs">trunk/LayoutTests/js/dom/script-tests/document-all-watchpoint-covers-eliminated-compare-eq.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresscompareeqonnullandundefinednonpeepholejs">trunk/Source/JavaScriptCore/tests/stress/compare-eq-on-null-and-undefined-non-peephole.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresscompareeqonnullandundefinedoptimizedinconstantfoldingjs">trunk/Source/JavaScriptCore/tests/stress/compare-eq-on-null-and-undefined-optimized-in-constant-folding.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresscompareeqonnullandundefinedjs">trunk/Source/JavaScriptCore/tests/stress/compare-eq-on-null-and-undefined.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/LayoutTests/ChangeLog        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2015-08-18  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Optimize more cases of something-compared-to-null/undefined
+        https://bugs.webkit.org/show_bug.cgi?id=148157
+
+        Reviewed by Geoffrey Garen and Filip Pizlo.
+
+        * js/dom/document-all-watchpoint-covers-eliminated-compare-eq-expected.txt: Added.
+        * js/dom/document-all-watchpoint-covers-eliminated-compare-eq.html: Added.
+        * js/dom/script-tests/document-all-watchpoint-covers-eliminated-compare-eq.js: Added.
+        (compareFunction):
+
</ins><span class="cx"> 2015-08-18  Wenson Hsieh  &lt;wenson_hsieh@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Attempt to fix the failing search-padding-cancel-results-buttons.html test by making
</span></span></pre></div>
<a id="trunkLayoutTestsjsdomdocumentallwatchpointcoverseliminatedcompareeqexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/dom/document-all-watchpoint-covers-eliminated-compare-eq-expected.txt (0 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/dom/document-all-watchpoint-covers-eliminated-compare-eq-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/dom/document-all-watchpoint-covers-eliminated-compare-eq-expected.txt        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+Test to make sure that document.all works correctly with elminated CompareEq in DFG.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS documentAllCompare.isNull is true
+PASS documentAllCompare.isUndefined is true
+PASS documentAllCompare.length is 13
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsdomdocumentallwatchpointcoverseliminatedcompareeqhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/dom/document-all-watchpoint-covers-eliminated-compare-eq.html (0 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/dom/document-all-watchpoint-covers-eliminated-compare-eq.html                                (rev 0)
+++ trunk/LayoutTests/js/dom/document-all-watchpoint-covers-eliminated-compare-eq.html        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+&lt;!DOCTYPE HTML&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;script-tests/document-all-watchpoint-covers-eliminated-compare-eq.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="trunkLayoutTestsjsdomscripttestsdocumentallwatchpointcoverseliminatedcompareeqjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/dom/script-tests/document-all-watchpoint-covers-eliminated-compare-eq.js (0 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/dom/script-tests/document-all-watchpoint-covers-eliminated-compare-eq.js                                (rev 0)
+++ trunk/LayoutTests/js/dom/script-tests/document-all-watchpoint-covers-eliminated-compare-eq.js        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -0,0 +1,49 @@
</span><ins>+description(&quot;Test to make sure that document.all works correctly with elminated CompareEq in DFG.&quot;);
+
+function compareFunction(a)
+{
+    var length = a.length;
+
+    var aIsNull = (a == null) || (null == a);
+    var aIsUndefined = (a == undefined) || (undefined == a);
+
+    if (a == null || undefined == a)
+        return { isNull: aIsNull, isUndefined: aIsUndefined, length: length };
+    else
+        return { isNull: aIsNull, isUndefined: aIsUndefined };
+}
+
+// Warmup with sane objects.
+for (let i = 0; i &lt; 1e4; ++i) {
+    let result = compareFunction({ length: 5});
+    if (result.isNull || result.isUndefined)
+        debug(&quot;Failed warmup with compareFunction({ length: 5}).&quot;);
+
+    let object = new Object;
+    object.length = 1;
+    result = compareFunction(object);
+    if (result.isNull || result.isUndefined)
+        debug(&quot;Failed warmup with compareFunction(object).&quot;);
+}
+
+let documentAll = document.all;
+var documentAllCompare = compareFunction(documentAll);
+shouldBeTrue(&quot;documentAllCompare.isNull&quot;);
+shouldBeTrue(&quot;documentAllCompare.isUndefined&quot;);
+shouldBe(&quot;documentAllCompare.length&quot;, &quot;13&quot;);
+
+for (let i = 0; i &lt; 1e3; ++i) {
+    let result = compareFunction({ length: 5});
+    if (result.isNull || result.isUndefined)
+        debug(&quot;Failed tail with compareFunction({ length: 5}).&quot;);
+
+    result = compareFunction(documentAll);
+    if (!result.isNull || !result.isUndefined)
+        debug(&quot;Failed tail with compareFunction(documentAll).&quot;);
+
+    let object = new Object;
+    object.length = 1;
+    result = compareFunction(object);
+    if (result.isNull || result.isUndefined)
+        debug(&quot;Failed tail with compareFunction(object).&quot;);
+}
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -1,3 +1,105 @@
</span><ins>+2015-08-18  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Optimize more cases of something-compared-to-null/undefined
+        https://bugs.webkit.org/show_bug.cgi?id=148157
+
+        Reviewed by Geoffrey Garen and Filip Pizlo.
+
+        CompareEq is fairly trivial if you assert one of the operands is either
+        null or undefined. Under those conditions, the only way to have &quot;true&quot;
+        is to have the other operand be null/undefined or have an object
+        that masquerades to undefined.
+
+        JSC already had a fast path in CompareEqConstant.
+        With this patch, I generalize this fast path to more cases and try
+        to eliminate the checks whenever possible.
+
+        CompareEq now does the job of CompareEqConstant. If any operand can
+        be proved to be undefined/other, its edge is set to OtherUse. Whenever
+        any edge is OtherUse, we generate the fast code we had for CompareEqConstant.
+
+        The AbstractInterpreter has additional checks to reduce the node to a constant
+        whenever possible.
+
+        There are two additional changes in this patch:
+        -The Fixup Phase tries to set edges to OtherUse early. This is done correctly
+         in ConstantFoldingPhase but setting it up early helps the phases relying
+         on Clobberize.
+        -The codegen for CompareEqConstant was improved. The reason is the comparison
+         for ObjectOrOther could be faster just because the codegen was better.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize): Deleted.
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC): Deleted.
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::isUndefinedOrNullConstant):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate): Deleted.
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute): Deleted.
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleBranch):
+        (JSC::DFG::SpeculativeJIT::compare):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::isKnownNotOther):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNullOrUndefined):
+        (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNullOrUndefined):
+        (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): Deleted.
+        (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): Deleted.
+        (JSC::DFG::SpeculativeJIT::nonSpeculativeCompareNull): Deleted.
+        (JSC::DFG::SpeculativeJIT::compile): Deleted.
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNullOrUndefined):
+        (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNullOrUndefined):
+        (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): Deleted.
+        (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): Deleted.
+        (JSC::DFG::SpeculativeJIT::nonSpeculativeCompareNull): Deleted.
+        (JSC::DFG::SpeculativeJIT::compile): Deleted.
+        * dfg/DFGValidate.cpp:
+        (JSC::DFG::Validate::validate): Deleted.
+        * dfg/DFGWatchpointCollectionPhase.cpp:
+        (JSC::DFG::WatchpointCollectionPhase::handle):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileCompareEq):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileNode): Deleted.
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileCompareEqConstant): Deleted.
+        * tests/stress/compare-eq-on-null-and-undefined-non-peephole.js: Added.
+        (string_appeared_here.useForMath):
+        (testUseForMath):
+        * tests/stress/compare-eq-on-null-and-undefined-optimized-in-constant-folding.js: Added.
+        (string_appeared_here.unreachableCodeTest):
+        (inlinedCompareToNull):
+        (inlinedComparedToUndefined):
+        (warmupInlineFunctions):
+        (testInlineFunctions):
+        * tests/stress/compare-eq-on-null-and-undefined.js: Added.
+        (string_appeared_here.compareConstants):
+        (opaqueNull):
+        (opaqueUndefined):
+        (compareConstantsAndDynamicValues):
+        (compareDynamicValues):
+        (compareDynamicValueToItself):
+        (arrayTesting):
+        (opaqueCompare1):
+        (testNullComparatorUpdate):
+        (opaqueCompare2):
+        (testUndefinedComparatorUpdate):
+        (opaqueCompare3):
+        (testNullAndUndefinedComparatorUpdate):
+
</ins><span class="cx"> 2015-08-18  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Introduce non-user-observable Promise functions to use Promises internally
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -1139,8 +1139,7 @@
</span><span class="cx">     case CompareLessEq:
</span><span class="cx">     case CompareGreater:
</span><span class="cx">     case CompareGreaterEq:
</span><del>-    case CompareEq:
-    case CompareEqConstant: {
</del><ins>+    case CompareEq: {
</ins><span class="cx">         JSValue leftConst = forNode(node-&gt;child1()).value();
</span><span class="cx">         JSValue rightConst = forNode(node-&gt;child2()).value();
</span><span class="cx">         if (leftConst &amp;&amp; rightConst) {
</span><span class="lines">@@ -1180,13 +1179,40 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        if (node-&gt;op() == CompareEqConstant || node-&gt;op() == CompareEq) {
</del><ins>+        if (node-&gt;op() == CompareEq) {
</ins><span class="cx">             SpeculatedType leftType = forNode(node-&gt;child1()).m_type;
</span><span class="cx">             SpeculatedType rightType = forNode(node-&gt;child2()).m_type;
</span><span class="cx">             if (!valuesCouldBeEqual(leftType, rightType)) {
</span><span class="cx">                 setConstant(node, jsBoolean(false));
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><ins>+
+            if (leftType == SpecOther)
+                std::swap(leftType, rightType);
+            if (rightType == SpecOther) {
+                // Undefined and Null are always equal when compared to eachother.
+                if (!(leftType &amp; ~SpecOther)) {
+                    setConstant(node, jsBoolean(true));
+                    break;
+                }
+
+                // Any other type compared to Null or Undefined is always false
+                // as long as the MasqueradesAsUndefined watchpoint is valid.
+                //
+                // MasqueradesAsUndefined only matters for SpecObjectOther, other
+                // cases are always &quot;false&quot;.
+                if (!(leftType &amp; (SpecObjectOther | SpecOther))) {
+                    setConstant(node, jsBoolean(false));
+                    break;
+                }
+
+                if (!(leftType &amp; SpecOther) &amp;&amp; m_graph.masqueradesAsUndefinedWatchpointIsStillValid(node-&gt;origin.semantic)) {
+                    JSGlobalObject* globalObject = m_graph.globalObjectFor(node-&gt;origin.semantic);
+                    m_graph.watchpoints().addLazily(globalObject-&gt;masqueradesAsUndefinedWatchpoint());
+                    setConstant(node, jsBoolean(false));
+                    break;
+                }
+            }
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         if (node-&gt;child1() == node-&gt;child2()) {
</span><span class="lines">@@ -1206,7 +1232,6 @@
</span><span class="cx">                 case CompareLessEq:
</span><span class="cx">                 case CompareGreaterEq:
</span><span class="cx">                 case CompareEq:
</span><del>-                case CompareEqConstant:
</del><span class="cx">                     setConstant(node, jsBoolean(true));
</span><span class="cx">                     break;
</span><span class="cx">                 default:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -3356,7 +3356,8 @@
</span><span class="cx"> 
</span><span class="cx">         case op_eq_null: {
</span><span class="cx">             Node* value = get(VirtualRegister(currentInstruction[2].u.operand));
</span><del>-            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareEqConstant, value, addToGraph(JSConstant, OpInfo(m_constantNull))));
</del><ins>+            Node* nullConstant = addToGraph(JSConstant, OpInfo(m_constantNull));
+            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareEq, value, nullConstant));
</ins><span class="cx">             NEXT_OPCODE(op_eq_null);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -3376,7 +3377,8 @@
</span><span class="cx"> 
</span><span class="cx">         case op_neq_null: {
</span><span class="cx">             Node* value = get(VirtualRegister(currentInstruction[2].u.operand));
</span><del>-            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(LogicalNot, addToGraph(CompareEqConstant, value, addToGraph(JSConstant, OpInfo(m_constantNull)))));
</del><ins>+            Node* nullConstant = addToGraph(JSConstant, OpInfo(m_constantNull));
+            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(LogicalNot, addToGraph(CompareEq, value, nullConstant)));
</ins><span class="cx">             NEXT_OPCODE(op_neq_null);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -3523,7 +3525,8 @@
</span><span class="cx">         case op_jeq_null: {
</span><span class="cx">             unsigned relativeOffset = currentInstruction[2].u.operand;
</span><span class="cx">             Node* value = get(VirtualRegister(currentInstruction[1].u.operand));
</span><del>-            Node* condition = addToGraph(CompareEqConstant, value, addToGraph(JSConstant, OpInfo(m_constantNull)));
</del><ins>+            Node* nullConstant = addToGraph(JSConstant, OpInfo(m_constantNull));
+            Node* condition = addToGraph(CompareEq, value, nullConstant);
</ins><span class="cx">             addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jeq_null))), condition);
</span><span class="cx">             LAST_OPCODE(op_jeq_null);
</span><span class="cx">         }
</span><span class="lines">@@ -3531,7 +3534,8 @@
</span><span class="cx">         case op_jneq_null: {
</span><span class="cx">             unsigned relativeOffset = currentInstruction[2].u.operand;
</span><span class="cx">             Node* value = get(VirtualRegister(currentInstruction[1].u.operand));
</span><del>-            Node* condition = addToGraph(CompareEqConstant, value, addToGraph(JSConstant, OpInfo(m_constantNull)));
</del><ins>+            Node* nullConstant = addToGraph(JSConstant, OpInfo(m_constantNull));
+            Node* condition = addToGraph(CompareEq, value, nullConstant);
</ins><span class="cx">             addToGraph(Branch, OpInfo(branchData(m_currentIndex + OPCODE_LENGTH(op_jneq_null), m_currentIndex + relativeOffset)), condition);
</span><span class="cx">             LAST_OPCODE(op_jneq_null);
</span><span class="cx">         }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -143,7 +143,6 @@
</span><span class="cx">     case SkipScope:
</span><span class="cx">     case StringCharCodeAt:
</span><span class="cx">     case StringFromCharCode:
</span><del>-    case CompareEqConstant:
</del><span class="cx">     case CompareStrictEq:
</span><span class="cx">     case IsUndefined:
</span><span class="cx">     case IsBoolean:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -97,6 +97,14 @@
</span><span class="cx">                     node-&gt;child1().setUseKind(BooleanUse);
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><ins>+
+            case CompareEq: {
+                if (!m_interpreter.needsTypeCheck(node-&gt;child1(), SpecOther))
+                    node-&gt;child1().setUseKind(OtherUse);
+                if (!m_interpreter.needsTypeCheck(node-&gt;child2(), SpecOther))
+                    node-&gt;child2().setUseKind(OtherUse);
+                break;
+            }
</ins><span class="cx">                 
</span><span class="cx">             case CheckStructure:
</span><span class="cx">             case ArrayifyToStructure: {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -116,7 +116,6 @@
</span><span class="cx">     case CompareGreater:
</span><span class="cx">     case CompareGreaterEq:
</span><span class="cx">     case CompareEq:
</span><del>-    case CompareEqConstant:
</del><span class="cx">     case CompareStrictEq:
</span><span class="cx">     case Call:
</span><span class="cx">     case Construct:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -368,10 +368,6 @@
</span><span class="cx">                 fixEdge&lt;StringUse&gt;(node-&gt;child1());
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-            
-        case CompareEqConstant: {
-            break;
-        }
</del><span class="cx"> 
</span><span class="cx">         case CompareEq:
</span><span class="cx">         case CompareLess:
</span><span class="lines">@@ -424,6 +420,32 @@
</span><span class="cx">                 node-&gt;clearFlags(NodeMustGenerate);
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><ins>+
+            // If either child can be proved to be Null or Undefined, comparing them is greatly simplified.
+            bool oneArgumentIsUsedAsSpecOther = false;
+            if (node-&gt;child1()-&gt;isUndefinedOrNullConstant()) {
+                fixEdge&lt;OtherUse&gt;(node-&gt;child1());
+                oneArgumentIsUsedAsSpecOther = true;
+            } else if (node-&gt;child1()-&gt;shouldSpeculateOther()) {
+                m_insertionSet.insertNode(m_indexInBlock, SpecNone, Check, node-&gt;origin,
+                    Edge(node-&gt;child1().node(), OtherUse));
+                fixEdge&lt;OtherUse&gt;(node-&gt;child1());
+                oneArgumentIsUsedAsSpecOther = true;
+            }
+            if (node-&gt;child2()-&gt;isUndefinedOrNullConstant()) {
+                fixEdge&lt;OtherUse&gt;(node-&gt;child2());
+                oneArgumentIsUsedAsSpecOther = true;
+            } else if (node-&gt;child2()-&gt;shouldSpeculateOther()) {
+                m_insertionSet.insertNode(m_indexInBlock, SpecNone, Check, node-&gt;origin,
+                    Edge(node-&gt;child2().node(), OtherUse));
+                fixEdge&lt;OtherUse&gt;(node-&gt;child2());
+                oneArgumentIsUsedAsSpecOther = true;
+            }
+            if (oneArgumentIsUsedAsSpecOther) {
+                node-&gt;clearFlags(NodeMustGenerate);
+                break;
+            }
+
</ins><span class="cx">             if (node-&gt;child1()-&gt;shouldSpeculateObject() &amp;&amp; node-&gt;child2()-&gt;shouldSpeculateObjectOrOther()) {
</span><span class="cx">                 fixEdge&lt;ObjectUse&gt;(node-&gt;child1());
</span><span class="cx">                 fixEdge&lt;ObjectOrOtherUse&gt;(node-&gt;child2());
</span><span class="lines">@@ -436,6 +458,7 @@
</span><span class="cx">                 node-&gt;clearFlags(NodeMustGenerate);
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><ins>+
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.h (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.h        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.h        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -690,7 +690,12 @@
</span><span class="cx">     {
</span><span class="cx">         return constant()-&gt;value().asBoolean();
</span><span class="cx">     }
</span><del>-     
</del><ins>+
+    bool isUndefinedOrNullConstant()
+    {
+        return isConstant() &amp;&amp; constant()-&gt;value().isUndefinedOrNull();
+    }
+
</ins><span class="cx">     bool isCellConstant()
</span><span class="cx">     {
</span><span class="cx">         return isConstant() &amp;&amp; constant()-&gt;value() &amp;&amp; constant()-&gt;value().isCell();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -231,7 +231,6 @@
</span><span class="cx">     macro(CompareGreater, NodeResultBoolean | NodeMustGenerate) \
</span><span class="cx">     macro(CompareGreaterEq, NodeResultBoolean | NodeMustGenerate) \
</span><span class="cx">     macro(CompareEq, NodeResultBoolean | NodeMustGenerate) \
</span><del>-    macro(CompareEqConstant, NodeResultBoolean) \
</del><span class="cx">     macro(CompareStrictEq, NodeResultBoolean) \
</span><span class="cx">     \
</span><span class="cx">     /* Calls. */\
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -371,7 +371,6 @@
</span><span class="cx">         case CompareGreater:
</span><span class="cx">         case CompareGreaterEq:
</span><span class="cx">         case CompareEq:
</span><del>-        case CompareEqConstant:
</del><span class="cx">         case CompareStrictEq:
</span><span class="cx">         case InstanceOf:
</span><span class="cx">         case IsUndefined:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -198,7 +198,6 @@
</span><span class="cx">     case CompareGreater:
</span><span class="cx">     case CompareGreaterEq:
</span><span class="cx">     case CompareEq:
</span><del>-    case CompareEqConstant:
</del><span class="cx">     case CompareStrictEq:
</span><span class="cx">     case Call:
</span><span class="cx">     case Construct:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -1369,6 +1369,10 @@
</span><span class="cx">                 compilePeepHoleObjectToObjectOrOtherEquality(node-&gt;child1(), node-&gt;child2(), branchNode);
</span><span class="cx">             else if (node-&gt;isBinaryUseKind(ObjectOrOtherUse, ObjectUse))
</span><span class="cx">                 compilePeepHoleObjectToObjectOrOtherEquality(node-&gt;child2(), node-&gt;child1(), branchNode);
</span><ins>+            else if (!needsTypeCheck(node-&gt;child1(), SpecOther))
+                nonSpeculativePeepholeBranchNullOrUndefined(node-&gt;child2(), branchNode);
+            else if (!needsTypeCheck(node-&gt;child2(), SpecOther))
+                nonSpeculativePeepholeBranchNullOrUndefined(node-&gt;child1(), branchNode);
</ins><span class="cx">             else {
</span><span class="cx">                 nonSpeculativePeepholeBranch(node, branchNode, condition, operation);
</span><span class="cx">                 return true;
</span><span class="lines">@@ -3900,8 +3904,18 @@
</span><span class="cx">             compileObjectToObjectOrOtherEquality(node-&gt;child2(), node-&gt;child1());
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><ins>+
+        if (!needsTypeCheck(node-&gt;child1(), SpecOther)) {
+            nonSpeculativeNonPeepholeCompareNullOrUndefined(node-&gt;child2());
+            return false;
+        }
+
+        if (!needsTypeCheck(node-&gt;child2(), SpecOther)) {
+            nonSpeculativeNonPeepholeCompareNullOrUndefined(node-&gt;child1());
+            return false;
+        }
</ins><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     nonSpeculativeNonPeepholeCompare(node, condition, operation);
</span><span class="cx">     return false;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -556,6 +556,7 @@
</span><span class="cx">     bool isKnownNotInteger(Node* node) { return !(m_state.forNode(node).m_type &amp; SpecInt32); }
</span><span class="cx">     bool isKnownNotNumber(Node* node) { return !(m_state.forNode(node).m_type &amp; SpecFullNumber); }
</span><span class="cx">     bool isKnownNotCell(Node* node) { return !(m_state.forNode(node).m_type &amp; SpecCell); }
</span><ins>+    bool isKnownNotOther(Node* node) { return !(m_state.forNode(node).m_type &amp; SpecOther); }
</ins><span class="cx">     
</span><span class="cx">     UniquedStringImpl* identifierUID(unsigned index)
</span><span class="cx">     {
</span><span class="lines">@@ -701,9 +702,8 @@
</span><span class="cx">     
</span><span class="cx">     void compileBaseValueStoreBarrier(Edge&amp; baseEdge, Edge&amp; valueEdge);
</span><span class="cx"> 
</span><del>-    void nonSpeculativeNonPeepholeCompareNull(Edge operand, bool invert = false);
-    void nonSpeculativePeepholeBranchNull(Edge operand, Node* branchNode, bool invert = false);
-    bool nonSpeculativeCompareNull(Node*, Edge operand, bool invert = false);
</del><ins>+    void nonSpeculativeNonPeepholeCompareNullOrUndefined(Edge operand);
+    void nonSpeculativePeepholeBranchNullOrUndefined(Edge operand, Node* branchNode);
</ins><span class="cx">     
</span><span class="cx">     void nonSpeculativePeepholeBranch(Node*, Node* branchNode, MacroAssembler::RelationalCondition, S_JITOperation_EJJ helperFunction);
</span><span class="cx">     void nonSpeculativeNonPeepholeCompare(Node*, MacroAssembler::RelationalCondition, S_JITOperation_EJJ helperFunction);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -234,9 +234,9 @@
</span><span class="cx">     addSlowPathGenerator(WTF::move(slowPath));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool invert)
</del><ins>+void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNullOrUndefined(Edge operand)
</ins><span class="cx"> {
</span><del>-    JSValueOperand arg(this, operand);
</del><ins>+    JSValueOperand arg(this, operand, ManualOperandSpeculation);
</ins><span class="cx">     GPRReg argTagGPR = arg.tagGPR();
</span><span class="cx">     GPRReg argPayloadGPR = arg.payloadGPR();
</span><span class="cx"> 
</span><span class="lines">@@ -249,7 +249,7 @@
</span><span class="cx">         if (!isKnownCell(operand.node()))
</span><span class="cx">             notCell = m_jit.branchIfNotCell(arg.jsValueRegs());
</span><span class="cx">         
</span><del>-        m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR);
</del><ins>+        m_jit.move(TrustedImm32(0), resultPayloadGPR);
</ins><span class="cx">         notMasqueradesAsUndefined = m_jit.jump();
</span><span class="cx">     } else {
</span><span class="cx">         GPRTemporary localGlobalObject(this);
</span><span class="lines">@@ -263,7 +263,7 @@
</span><span class="cx">             JITCompiler::Address(argPayloadGPR, JSCell::typeInfoFlagsOffset()), 
</span><span class="cx">             JITCompiler::TrustedImm32(MasqueradesAsUndefined));
</span><span class="cx">         
</span><del>-        m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR);
</del><ins>+        m_jit.move(TrustedImm32(0), resultPayloadGPR);
</ins><span class="cx">         notMasqueradesAsUndefined = m_jit.jump();
</span><span class="cx"> 
</span><span class="cx">         isMasqueradesAsUndefined.link(&amp;m_jit);
</span><span class="lines">@@ -272,7 +272,7 @@
</span><span class="cx">         m_jit.move(JITCompiler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode-&gt;origin.semantic)), localGlobalObjectGPR);
</span><span class="cx">         m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureIDOffset()), resultPayloadGPR);
</span><span class="cx">         m_jit.loadPtr(JITCompiler::Address(resultPayloadGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
</span><del>-        m_jit.compare32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, resultPayloadGPR);
</del><ins>+        m_jit.compare32(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, resultPayloadGPR);
</ins><span class="cx">     }
</span><span class="cx">  
</span><span class="cx">     if (!isKnownCell(operand.node())) {
</span><span class="lines">@@ -282,7 +282,7 @@
</span><span class="cx">         // null or undefined?
</span><span class="cx">         COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
</span><span class="cx">         m_jit.or32(TrustedImm32(1), argTagGPR, resultPayloadGPR);
</span><del>-        m_jit.compare32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultPayloadGPR, TrustedImm32(JSValue::NullTag), resultPayloadGPR);
</del><ins>+        m_jit.compare32(JITCompiler::Equal, resultPayloadGPR, TrustedImm32(JSValue::NullTag), resultPayloadGPR);
</ins><span class="cx"> 
</span><span class="cx">         done.link(&amp;m_jit);
</span><span class="cx">     }
</span><span class="lines">@@ -292,11 +292,12 @@
</span><span class="cx">     booleanResult(resultPayloadGPR, m_currentNode);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branchNode, bool invert)
</del><ins>+void SpeculativeJIT::nonSpeculativePeepholeBranchNullOrUndefined(Edge operand, Node* branchNode)
</ins><span class="cx"> {
</span><span class="cx">     BasicBlock* taken = branchNode-&gt;branchData()-&gt;taken.block;
</span><span class="cx">     BasicBlock* notTaken = branchNode-&gt;branchData()-&gt;notTaken.block;
</span><del>-    
</del><ins>+
+    bool invert = false;
</ins><span class="cx">     if (taken == nextBlock()) {
</span><span class="cx">         invert = !invert;
</span><span class="cx">         BasicBlock* tmp = taken;
</span><span class="lines">@@ -304,7 +305,7 @@
</span><span class="cx">         notTaken = tmp;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    JSValueOperand arg(this, operand);
</del><ins>+    JSValueOperand arg(this, operand, ManualOperandSpeculation);
</ins><span class="cx">     GPRReg argTagGPR = arg.tagGPR();
</span><span class="cx">     GPRReg argPayloadGPR = arg.payloadGPR();
</span><span class="cx">     
</span><span class="lines">@@ -351,29 +352,6 @@
</span><span class="cx">     jump(notTaken);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool SpeculativeJIT::nonSpeculativeCompareNull(Node* node, Edge operand, bool invert)
-{
-    unsigned branchIndexInBlock = detectPeepHoleBranch();
-    if (branchIndexInBlock != UINT_MAX) {
-        Node* branchNode = m_block-&gt;at(branchIndexInBlock);
-
-        ASSERT(node-&gt;adjustedRefCount() == 1);
-        
-        nonSpeculativePeepholeBranchNull(operand, branchNode, invert);
-    
-        use(node-&gt;child1());
-        use(node-&gt;child2());
-        m_indexInBlock = branchIndexInBlock;
-        m_currentNode = branchNode;
-        
-        return true;
-    }
-    
-    nonSpeculativeNonPeepholeCompareNull(operand, invert);
-    
-    return false;
-}
-
</del><span class="cx"> void SpeculativeJIT::nonSpeculativePeepholeBranch(Node* node, Node* branchNode, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
</span><span class="cx"> {
</span><span class="cx">     BasicBlock* taken = branchNode-&gt;branchData()-&gt;taken.block;
</span><span class="lines">@@ -2278,12 +2256,6 @@
</span><span class="cx">         if (compare(node, JITCompiler::GreaterThanOrEqual, JITCompiler::DoubleGreaterThanOrEqual, operationCompareGreaterEq))
</span><span class="cx">             return;
</span><span class="cx">         break;
</span><del>-        
-    case CompareEqConstant:
-        ASSERT(node-&gt;child2()-&gt;asJSValue().isNull());
-        if (nonSpeculativeCompareNull(node, node-&gt;child1()))
-            return;
-        break;
</del><span class="cx"> 
</span><span class="cx">     case CompareEq:
</span><span class="cx">         if (compare(node, JITCompiler::Equal, JITCompiler::DoubleEqual, operationCompareEq))
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -192,148 +192,120 @@
</span><span class="cx">     addSlowPathGenerator(WTF::move(slowPath));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool invert)
</del><ins>+void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNullOrUndefined(Edge operand)
</ins><span class="cx"> {
</span><del>-    JSValueOperand arg(this, operand);
</del><ins>+    ASSERT_WITH_MESSAGE(!masqueradesAsUndefinedWatchpointIsStillValid() || !isKnownCell(operand.node()), &quot;The Compare should have been eliminated, it is known to be always false.&quot;);
+
+    JSValueOperand arg(this, operand, ManualOperandSpeculation);
</ins><span class="cx">     GPRReg argGPR = arg.gpr();
</span><span class="cx">     
</span><del>-    GPRTemporary result(this, Reuse, arg);
</del><ins>+    GPRTemporary result(this);
</ins><span class="cx">     GPRReg resultGPR = result.gpr();
</span><del>-    
-    JITCompiler::Jump notCell;
-    
-    JITCompiler::Jump notMasqueradesAsUndefined;
-    if (masqueradesAsUndefinedWatchpointIsStillValid()) {
-        if (!isKnownCell(operand.node()))
-            notCell = m_jit.branchIfNotCell(JSValueRegs(argGPR));
</del><span class="cx"> 
</span><del>-        m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultGPR);
-        notMasqueradesAsUndefined = m_jit.jump();
</del><ins>+    m_jit.move(TrustedImm32(0), resultGPR);
+
+    JITCompiler::JumpList done;
+    if (masqueradesAsUndefinedWatchpointIsStillValid()) {
+        if (!isKnownNotCell(operand.node()))
+            done.append(m_jit.branchIfCell(JSValueRegs(argGPR)));
</ins><span class="cx">     } else {
</span><span class="cx">         GPRTemporary localGlobalObject(this);
</span><span class="cx">         GPRTemporary remoteGlobalObject(this);
</span><span class="cx">         GPRTemporary scratch(this);
</span><span class="cx"> 
</span><ins>+        JITCompiler::Jump notCell;
</ins><span class="cx">         if (!isKnownCell(operand.node()))
</span><span class="cx">             notCell = m_jit.branchIfNotCell(JSValueRegs(argGPR));
</span><span class="cx">         
</span><del>-        JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8(
-            JITCompiler::NonZero, 
</del><ins>+        JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8(
+            JITCompiler::Zero,
</ins><span class="cx">             JITCompiler::Address(argGPR, JSCell::typeInfoFlagsOffset()), 
</span><span class="cx">             JITCompiler::TrustedImm32(MasqueradesAsUndefined));
</span><ins>+        done.append(isNotMasqueradesAsUndefined);
</ins><span class="cx"> 
</span><del>-        m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultGPR);
-        notMasqueradesAsUndefined = m_jit.jump();
-
-        isMasqueradesAsUndefined.link(&amp;m_jit);
</del><span class="cx">         GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
</span><span class="cx">         GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
</span><span class="cx">         m_jit.move(JITCompiler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode-&gt;origin.semantic)), localGlobalObjectGPR);
</span><span class="cx">         m_jit.emitLoadStructure(argGPR, resultGPR, scratch.gpr());
</span><span class="cx">         m_jit.loadPtr(JITCompiler::Address(resultGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
</span><del>-        m_jit.comparePtr(invert ? JITCompiler::NotEqual : JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, resultGPR);
</del><ins>+        m_jit.comparePtr(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, resultGPR);
+        done.append(m_jit.jump());
+        if (!isKnownCell(operand.node()))
+            notCell.link(&amp;m_jit);
</ins><span class="cx">     }
</span><span class="cx">  
</span><del>-    if (!isKnownCell(operand.node())) {
-        JITCompiler::Jump done = m_jit.jump();
-        
-        notCell.link(&amp;m_jit);
-        
</del><ins>+    if (!isKnownNotOther(operand.node())) {
</ins><span class="cx">         m_jit.move(argGPR, resultGPR);
</span><span class="cx">         m_jit.and64(JITCompiler::TrustedImm32(~TagBitUndefined), resultGPR);
</span><del>-        m_jit.compare64(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultGPR, JITCompiler::TrustedImm32(ValueNull), resultGPR);
-        
-        done.link(&amp;m_jit);
</del><ins>+        m_jit.compare64(JITCompiler::Equal, resultGPR, JITCompiler::TrustedImm32(ValueNull), resultGPR);
</ins><span class="cx">     }
</span><del>-   
-    notMasqueradesAsUndefined.link(&amp;m_jit);
</del><ins>+
+    done.link(&amp;m_jit);
</ins><span class="cx">  
</span><span class="cx">     m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
</span><span class="cx">     jsValueResult(resultGPR, m_currentNode, DataFormatJSBoolean);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branchNode, bool invert)
</del><ins>+void SpeculativeJIT::nonSpeculativePeepholeBranchNullOrUndefined(Edge operand, Node* branchNode)
</ins><span class="cx"> {
</span><ins>+    ASSERT_WITH_MESSAGE(!masqueradesAsUndefinedWatchpointIsStillValid() || !isKnownCell(operand.node()), &quot;The Compare should have been eliminated, it is known to be always false.&quot;);
+
</ins><span class="cx">     BasicBlock* taken = branchNode-&gt;branchData()-&gt;taken.block;
</span><span class="cx">     BasicBlock* notTaken = branchNode-&gt;branchData()-&gt;notTaken.block;
</span><del>-    
-    if (taken == nextBlock()) {
-        invert = !invert;
-        BasicBlock* tmp = taken;
-        taken = notTaken;
-        notTaken = tmp;
-    }
</del><span class="cx"> 
</span><del>-    JSValueOperand arg(this, operand);
</del><ins>+    JSValueOperand arg(this, operand, ManualOperandSpeculation);
</ins><span class="cx">     GPRReg argGPR = arg.gpr();
</span><span class="cx">     
</span><span class="cx">     GPRTemporary result(this, Reuse, arg);
</span><span class="cx">     GPRReg resultGPR = result.gpr();
</span><del>-    
-    JITCompiler::Jump notCell;
-    
</del><ins>+
+    // First, handle the case where &quot;operand&quot; is a cell.
</ins><span class="cx">     if (masqueradesAsUndefinedWatchpointIsStillValid()) {
</span><del>-        if (!isKnownCell(operand.node()))
-            notCell = m_jit.branchIfNotCell(JSValueRegs(argGPR));
-        
-        jump(invert ? taken : notTaken, ForceJump);
</del><ins>+        if (!isKnownNotCell(operand.node())) {
+            JITCompiler::Jump isCell = m_jit.branchIfCell(JSValueRegs(argGPR));
+            addBranch(isCell, notTaken);
+        }
</ins><span class="cx">     } else {
</span><span class="cx">         GPRTemporary localGlobalObject(this);
</span><span class="cx">         GPRTemporary remoteGlobalObject(this);
</span><span class="cx">         GPRTemporary scratch(this);
</span><span class="cx"> 
</span><ins>+        JITCompiler::Jump notCell;
</ins><span class="cx">         if (!isKnownCell(operand.node()))
</span><span class="cx">             notCell = m_jit.branchIfNotCell(JSValueRegs(argGPR));
</span><span class="cx">         
</span><span class="cx">         branchTest8(JITCompiler::Zero, 
</span><span class="cx">             JITCompiler::Address(argGPR, JSCell::typeInfoFlagsOffset()), 
</span><del>-            JITCompiler::TrustedImm32(MasqueradesAsUndefined), 
-            invert ? taken : notTaken);
</del><ins>+            JITCompiler::TrustedImm32(MasqueradesAsUndefined), notTaken);
</ins><span class="cx"> 
</span><span class="cx">         GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
</span><span class="cx">         GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
</span><span class="cx">         m_jit.move(TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode-&gt;origin.semantic)), localGlobalObjectGPR);
</span><span class="cx">         m_jit.emitLoadStructure(argGPR, resultGPR, scratch.gpr());
</span><span class="cx">         m_jit.loadPtr(JITCompiler::Address(resultGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
</span><del>-        branchPtr(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, invert ? notTaken : taken);
</del><ins>+        branchPtr(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, taken);
+
+        if (!isKnownCell(operand.node())) {
+            jump(notTaken, ForceJump);
+            notCell.link(&amp;m_jit);
+        }
</ins><span class="cx">     }
</span><del>- 
-    if (!isKnownCell(operand.node())) {
-        jump(notTaken, ForceJump);
-        
-        notCell.link(&amp;m_jit);
-        
</del><ins>+
+    if (isKnownNotOther(operand.node()))
+        jump(notTaken);
+    else {
+        JITCompiler::RelationalCondition condition = JITCompiler::Equal;
+        if (taken == nextBlock()) {
+            condition = JITCompiler::NotEqual;
+            std::swap(taken, notTaken);
+        }
</ins><span class="cx">         m_jit.move(argGPR, resultGPR);
</span><span class="cx">         m_jit.and64(JITCompiler::TrustedImm32(~TagBitUndefined), resultGPR);
</span><del>-        branch64(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultGPR, JITCompiler::TrustedImm64(ValueNull), taken);
</del><ins>+        branch64(condition, resultGPR, JITCompiler::TrustedImm64(ValueNull), taken);
+        jump(notTaken);
</ins><span class="cx">     }
</span><del>-    
-    jump(notTaken);
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool SpeculativeJIT::nonSpeculativeCompareNull(Node* node, Edge operand, bool invert)
-{
-    unsigned branchIndexInBlock = detectPeepHoleBranch();
-    if (branchIndexInBlock != UINT_MAX) {
-        Node* branchNode = m_block-&gt;at(branchIndexInBlock);
-
-        DFG_ASSERT(m_jit.graph(), node, node-&gt;adjustedRefCount() == 1);
-        
-        nonSpeculativePeepholeBranchNull(operand, branchNode, invert);
-    
-        use(node-&gt;child1());
-        use(node-&gt;child2());
-        m_indexInBlock = branchIndexInBlock;
-        m_currentNode = branchNode;
-        
-        return true;
-    }
-    
-    nonSpeculativeNonPeepholeCompareNull(operand, invert);
-    
-    return false;
-}
-
</del><span class="cx"> void SpeculativeJIT::nonSpeculativePeepholeBranch(Node* node, Node* branchNode, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
</span><span class="cx"> {
</span><span class="cx">     BasicBlock* taken = branchNode-&gt;branchData()-&gt;taken.block;
</span><span class="lines">@@ -2411,12 +2383,6 @@
</span><span class="cx">         if (compare(node, JITCompiler::GreaterThanOrEqual, JITCompiler::DoubleGreaterThanOrEqual, operationCompareGreaterEq))
</span><span class="cx">             return;
</span><span class="cx">         break;
</span><del>-        
-    case CompareEqConstant:
-        ASSERT(node-&gt;child2()-&gt;asJSValue().isNull());
-        if (nonSpeculativeCompareNull(node, node-&gt;child1()))
-            return;
-        break;
</del><span class="cx"> 
</span><span class="cx">     case CompareEq:
</span><span class="cx">         if (compare(node, JITCompiler::Equal, JITCompiler::DoubleEqual, operationCompareEq))
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGValidatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -236,7 +236,6 @@
</span><span class="cx">                 case CompareGreater:
</span><span class="cx">                 case CompareGreaterEq:
</span><span class="cx">                 case CompareEq:
</span><del>-                case CompareEqConstant:
</del><span class="cx">                 case CompareStrictEq:
</span><span class="cx">                     VALIDATE((node), !!node-&gt;child1());
</span><span class="cx">                     VALIDATE((node), !!node-&gt;child2());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGWatchpointCollectionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -73,7 +73,6 @@
</span><span class="cx">     void handle()
</span><span class="cx">     {
</span><span class="cx">         switch (m_node-&gt;op()) {
</span><del>-        case CompareEqConstant:
</del><span class="cx">         case IsUndefined:
</span><span class="cx">             handleMasqueradesAsUndefined();
</span><span class="cx">             break;
</span><span class="lines">@@ -81,7 +80,8 @@
</span><span class="cx">         case CompareEq:
</span><span class="cx">             if (m_node-&gt;isBinaryUseKind(ObjectUse)
</span><span class="cx">                 || (m_node-&gt;child1().useKind() == ObjectUse &amp;&amp; m_node-&gt;child2().useKind() == ObjectOrOtherUse)
</span><del>-                || (m_node-&gt;child1().useKind() == ObjectOrOtherUse &amp;&amp; m_node-&gt;child2().useKind() == ObjectUse))
</del><ins>+                || (m_node-&gt;child1().useKind() == ObjectOrOtherUse &amp;&amp; m_node-&gt;child2().useKind() == ObjectUse)
+                || (m_node-&gt;child1().useKind() == OtherUse || m_node-&gt;child2().useKind() == OtherUse))
</ins><span class="cx">                 handleMasqueradesAsUndefined();
</span><span class="cx">             break;
</span><span class="cx">             
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -96,7 +96,6 @@
</span><span class="cx">     case ArithFRound:
</span><span class="cx">     case ArithNegate:
</span><span class="cx">     case UInt32ToNumber:
</span><del>-    case CompareEqConstant:
</del><span class="cx">     case Jump:
</span><span class="cx">     case ForceOSRExit:
</span><span class="cx">     case Phi:
</span><span class="lines">@@ -321,6 +320,8 @@
</span><span class="cx">             break;
</span><span class="cx">         if (node-&gt;isBinaryUseKind(ObjectOrOtherUse, ObjectUse))
</span><span class="cx">             break;
</span><ins>+        if (node-&gt;child1().useKind() == OtherUse || node-&gt;child2().useKind() == OtherUse)
+            break;
</ins><span class="cx">         return CannotCompile;
</span><span class="cx">     case CompareStrictEq:
</span><span class="cx">         if (node-&gt;isBinaryUseKind(Int32Use))
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (188623 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-08-19 02:09:44 UTC (rev 188623)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -701,9 +701,6 @@
</span><span class="cx">         case CompareEq:
</span><span class="cx">             compileCompareEq();
</span><span class="cx">             break;
</span><del>-        case CompareEqConstant:
-            compileCompareEqConstant();
-            break;
</del><span class="cx">         case CompareStrictEq:
</span><span class="cx">             compileCompareStrictEq();
</span><span class="cx">             break;
</span><span class="lines">@@ -4146,18 +4143,22 @@
</span><span class="cx">             nonSpeculativeCompare(LLVMIntEQ, operationCompareEq);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        
</del><ins>+
+        if (m_node-&gt;child1().useKind() == OtherUse) {
+            ASSERT(!m_interpreter.needsTypeCheck(m_node-&gt;child1(), SpecOther));
+            setBoolean(equalNullOrUndefined(m_node-&gt;child2(), AllCellsAreFalse, EqualNullOrUndefined, ManualOperandSpeculation));
+            return;
+        }
+
+        if (m_node-&gt;child2().useKind() == OtherUse) {
+            ASSERT(!m_interpreter.needsTypeCheck(m_node-&gt;child2(), SpecOther));
+            setBoolean(equalNullOrUndefined(m_node-&gt;child1(), AllCellsAreFalse, EqualNullOrUndefined, ManualOperandSpeculation));
+            return;
+        }
+
</ins><span class="cx">         DFG_CRASH(m_graph, m_node, &quot;Bad use kinds&quot;);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void compileCompareEqConstant()
-    {
-        ASSERT(m_node-&gt;child2()-&gt;asJSValue().isNull());
-        setBoolean(
-            equalNullOrUndefined(
-                m_node-&gt;child1(), AllCellsAreFalse, EqualNullOrUndefined));
-    }
-    
</del><span class="cx">     void compileCompareStrictEq()
</span><span class="cx">     {
</span><span class="cx">         if (m_node-&gt;isBinaryUseKind(Int32Use)) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresscompareeqonnullandundefinednonpeepholejs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/compare-eq-on-null-and-undefined-non-peephole.js (0 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/compare-eq-on-null-and-undefined-non-peephole.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/compare-eq-on-null-and-undefined-non-peephole.js        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+&quot;use strict&quot;
+
+function useForMath(undefinedArgument, nullArgument, polymorphicArgument) {
+    var a = (null == undefinedArgument) + (undefinedArgument == null) + (undefined == undefinedArgument) + (undefinedArgument == undefined);
+    var b = (null == nullArgument) + (nullArgument == null) + (undefined == nullArgument) + (nullArgument == undefined);
+    var c = (null == polymorphicArgument) + (polymorphicArgument == null) + (undefined == polymorphicArgument) + (polymorphicArgument == undefined);
+    var d = (5 == null) + (null == true) + (undefined == Math.LN2) + (&quot;const&quot; == undefined);
+    var e = (5 == undefinedArgument) + (nullArgument == true) + (nullArgument == Math.LN2) + (&quot;const&quot; == undefinedArgument);
+
+    return a + b - c + d - e;
+}
+noInline(useForMath);
+
+function testUseForMath() {
+    for (let i = 0; i &lt; 1e4; ++i) {
+        var value = useForMath(undefined, null, 5);
+        if (value != 8)
+            throw &quot;Failed useForMath(undefined, null, 5), value = &quot; + value + &quot; with i = &quot; + i;
+
+        var value = useForMath(undefined, null, null);
+        if (value != 4)
+            throw &quot;Failed useForMath(undefined, null, null), value = &quot; + value + &quot; with i = &quot; + i;
+
+        var value = useForMath(undefined, null, undefined);
+        if (value != 4)
+            throw &quot;Failed useForMath(undefined, null, undefined), value = &quot; + value + &quot; with i = &quot; + i;
+
+        var value = useForMath(undefined, null, { foo: &quot;bar&quot; });
+        if (value != 8)
+            throw &quot;Failed useForMath(undefined, null, { foo: \&quot;bar\&quot; }), value = &quot; + value + &quot; with i = &quot; + i;
+
+        var value = useForMath(undefined, null, true);
+        if (value != 8)
+            throw &quot;Failed useForMath(undefined, null, true), value = &quot; + value + &quot; with i = &quot; + i;
+
+        var value = useForMath(undefined, null, [1, 2, 3]);
+        if (value != 8)
+            throw &quot;Failed useForMath(undefined, null, true), value = &quot; + value + &quot; with i = &quot; + i;
+
+        var value = useForMath(undefined, null, &quot;WebKit!&quot;);
+        if (value != 8)
+            throw &quot;Failed useForMath(undefined, null, true), value = &quot; + value + &quot; with i = &quot; + i;
+    }
+}
+testUseForMath();
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresscompareeqonnullandundefinedoptimizedinconstantfoldingjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/compare-eq-on-null-and-undefined-optimized-in-constant-folding.js (0 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/compare-eq-on-null-and-undefined-optimized-in-constant-folding.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/compare-eq-on-null-and-undefined-optimized-in-constant-folding.js        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -0,0 +1,70 @@
</span><ins>+&quot;use strict&quot;
+
+function unreachableCodeTest() {
+    var a;
+
+    var b = null;
+    if (b) {
+        a = 5;
+    }
+    return a == b;
+}
+noInline(unreachableCodeTest);
+
+for (let i = 0; i &lt; 1e4; ++i) {
+    if (!unreachableCodeTest())
+        throw &quot;Failed unreachableCodeTest() with i = &quot; + i;
+}
+
+
+function inlinedCompareToNull(a) {
+    return a == null;
+}
+
+function inlinedComparedToUndefined(a) {
+    return a == undefined;
+}
+
+// Warmup. Litter the profile with every types.
+function warmupInlineFunctions() {
+    let returnValue = 0;
+    for (let i = 0; i &lt; 1e4; ++i) {
+        returnValue += inlinedCompareToNull(&quot;foo&quot;);
+        returnValue += inlinedCompareToNull(null);
+        returnValue += inlinedCompareToNull(Math);
+        returnValue += inlinedCompareToNull(5);
+        returnValue += inlinedCompareToNull(5.5);
+
+        returnValue += inlinedComparedToUndefined(&quot;foo&quot;);
+        returnValue += inlinedComparedToUndefined(null);
+        returnValue += inlinedComparedToUndefined(Math);
+        returnValue += inlinedComparedToUndefined(5);
+        returnValue += inlinedComparedToUndefined(5.5);
+    }
+    return returnValue;
+}
+noInline(warmupInlineFunctions);
+warmupInlineFunctions();
+
+function testInlineFunctions(undefinedArg, nullArg) {
+    if (inlinedCompareToNull(&quot;foo&quot;))
+        throw &quot;Failed inlinedCompareToNull(\&quot;foo\&quot;)&quot;;
+
+    if (!inlinedCompareToNull(null))
+        throw &quot;Failed !inlinedCompareToNull(null)&quot;;
+
+    if (!inlinedCompareToNull(undefined))
+        throw &quot;Failed !inlinedCompareToNull(undefined)&quot;;
+
+    if (!inlinedCompareToNull(undefinedArg))
+        throw &quot;Failed !inlinedCompareToNull(undefinedArg)&quot;;
+
+    if (!inlinedCompareToNull(nullArg))
+        throw &quot;Failed !inlinedCompareToNull(nullArg)&quot;;
+
+}
+noInline(testInlineFunctions);
+
+for (let i = 0; i &lt; 1e4; ++i) {
+    testInlineFunctions(undefined, null);
+}
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresscompareeqonnullandundefinedjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/compare-eq-on-null-and-undefined.js (0 => 188624)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/compare-eq-on-null-and-undefined.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/compare-eq-on-null-and-undefined.js        2015-08-19 04:09:12 UTC (rev 188624)
</span><span class="lines">@@ -0,0 +1,174 @@
</span><ins>+&quot;use strict&quot;
+
+// Trivial cases: everything is monomorphic and super predictable.
+function compareConstants()
+{
+    return (null == null) &amp;&amp; (null == undefined) &amp;&amp; (undefined == null);
+}
+noInline(compareConstants);
+
+for (let i = 0; i &lt; 1e4; ++i) {
+    if (!compareConstants())
+        throw &quot;Failed to compareConstants().&quot;;
+}
+
+
+function opaqueNull() {
+    return null;
+}
+noInline(opaqueNull);
+
+function opaqueUndefined() {
+    return undefined;
+}
+noInline(opaqueUndefined);
+
+function compareConstantsAndDynamicValues()
+{
+    return ((null == opaqueNull())
+        &amp;&amp; (opaqueNull() == null)
+        &amp;&amp; (undefined == opaqueNull())
+        &amp;&amp; (opaqueNull() == undefined)
+        &amp;&amp; (null == opaqueUndefined())
+        &amp;&amp; (opaqueUndefined() == null)
+        &amp;&amp; (undefined == opaqueUndefined())
+        &amp;&amp; (opaqueUndefined() == undefined));
+}
+noInline(compareConstantsAndDynamicValues);
+
+for (let i = 1e4; i--;) {
+    if (!compareConstantsAndDynamicValues())
+        throw &quot;Failed compareConstantsAndDynamicValues()&quot;;
+}
+
+
+function compareDynamicValues()
+{
+    return ((opaqueNull() == opaqueNull())
+            &amp;&amp; (opaqueUndefined() == opaqueUndefined())
+            &amp;&amp; (opaqueNull() == opaqueUndefined())
+            &amp;&amp; (opaqueUndefined() == opaqueNull()));
+}
+noInline(compareDynamicValues);
+
+for (let i = 0; i &lt; 1e4; ++i) {
+    if (!compareDynamicValues())
+        throw &quot;Failed compareDynamicValues()&quot;;
+}
+
+
+function compareDynamicValueToItself()
+{
+    const value1 = opaqueNull();
+    const value2 = opaqueUndefined();
+    return value1 == value1 &amp;&amp; value2 == value2;
+}
+noInline(compareDynamicValueToItself);
+
+for (let i = 0; i &lt; 1e4; ++i) {
+    if (!compareDynamicValueToItself())
+        throw &quot;Failed compareDynamicValueToItself()&quot;;
+}
+
+
+// The case that interested us in the first place.
+// Accessing an array with undecided shape always return undefined.
+
+function arrayTesting()
+{
+    let returnValue = true;
+
+    const array1 = new Array(2);
+    for (let i = 0; i &lt; 3; ++i) {
+        returnValue = returnValue &amp;&amp; (array1[i] == null);
+        returnValue = returnValue &amp;&amp; (null == array1[i]);
+        returnValue = returnValue &amp;&amp; (array1[i] == undefined);
+        returnValue = returnValue &amp;&amp; (undefined == array1[i]);
+    }
+
+    const array2 = new Array(2);
+    for (let i = 0; i &lt; 2; ++i) {
+        returnValue = returnValue &amp;&amp; (array2[i] == opaqueNull());
+        returnValue = returnValue &amp;&amp; (opaqueNull() == array2[i]);
+        returnValue = returnValue &amp;&amp; (array2[i] == opaqueUndefined());
+        returnValue = returnValue &amp;&amp; (opaqueUndefined() == array2[i]);
+    }
+
+    const array3 = new Array(2);
+    for (let i = 0; i &lt; 3; ++i) {
+        returnValue = returnValue &amp;&amp; (array3[i] == array3[i]);
+        returnValue = returnValue &amp;&amp; (array1[i] == array3[i]);
+        returnValue = returnValue &amp;&amp; (array3[i] == array1[i]);
+        returnValue = returnValue &amp;&amp; (array2[i] == array3[i]);
+        returnValue = returnValue &amp;&amp; (array3[i] == array2[i]);
+
+    }
+
+    return returnValue;
+}
+noInline(arrayTesting);
+
+for (let i = 0; i &lt; 1e4; ++i) {
+    if (!arrayTesting())
+        throw &quot;Failed arrayTesting()&quot;;
+}
+
+
+// Let's make it polymorphic after optimization. We should fallback to a generic compare operation.
+
+function opaqueCompare1(a, b) {
+    return a == b;
+}
+noInline(opaqueCompare1);
+
+function testNullComparatorUpdate() {
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (!opaqueCompare1(null, null))
+            throw &quot;Failed opaqueCompare1(null, null)&quot;
+    }
+
+    // Let's change types
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (opaqueCompare1(&quot;foo&quot;, null))
+            throw &quot;Failed opaqueCompare1(\&quot;foo\&quot;, null)&quot;
+    }
+}
+testNullComparatorUpdate();
+
+function opaqueCompare2(a, b) {
+    return a == b;
+}
+noInline(opaqueCompare2);
+
+function testUndefinedComparatorUpdate() {
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (!opaqueCompare2(undefined, undefined))
+            throw &quot;Failed opaqueCompare2(undefined, undefined)&quot;
+    }
+
+    // Let's change types
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (!opaqueCompare2(&quot;bar&quot;, &quot;bar&quot;))
+            throw &quot;Failed opaqueCompare2(\&quot;bar\&quot;, \&quot;bar\&quot;)&quot;
+    }
+}
+testUndefinedComparatorUpdate();
+
+function opaqueCompare3(a, b) {
+    return a == b;
+}
+noInline(opaqueCompare3);
+
+function testNullAndUndefinedComparatorUpdate() {
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (!opaqueCompare3(undefined, null) || !opaqueCompare2(null, undefined))
+            throw &quot;Failed opaqueCompare2(undefined/null, undefined/null)&quot;
+    }
+
+    // Let's change types
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (opaqueCompare3(undefined, &quot;bar&quot;))
+            throw &quot;Failed opaqueCompare3(undefined, \&quot;bar\&quot;)&quot;
+    }
+}
+testNullAndUndefinedComparatorUpdate();
</ins></span></pre>
</div>
</div>

</body>
</html>