<!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>[203491] 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/203491">203491</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-07-20 23:23:10 -0700 (Wed, 20 Jul 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Switching on symbols should be fast
https://bugs.webkit.org/show_bug.cgi?id=158892

Reviewed by Keith Miller.
Source/JavaScriptCore:

        
This does two things: fixes some goofs in our lowering of symbol equality and adds a new phase
to B3 to infer switch statements from linear chains of branches.
        
This changes how we compile equality to Symbols to constant-fold the load of the Symbol's UID.
This is necessary for making switches on Symbols inferrable. This also gives us the ability to
efficiently compile strict equality comparisons of SymbolUse and UntypedUse.

This adds a new phase to B3, which finds chains of branches that test for (in)equality on the
same value and constants, and turns them into a Switch. This can turn O(n) code into
O(log n) code, or even O(1) code if the switch cases are dense.
        
This can make a big difference in JS. Say you write a switch in which the case statements are
variable resolutions. The bytecode generator cannot use a bytecode switch in this case, since
we're required to evaluate the resolutions in order. But in DFG IR, we will often turn those
variable resolutions into constants, since we do that for any immutable singleton. This means
that B3 will see a chain of Branches: the else case of one Branch will point to a basic block
that does nothing but Branch on equality on the same value as the first Branch.

The inference algorithm is quite simple. The basic building block is the ability to summarize
a block's switch behavior. For a block that ends in a switch, this is just the collection of
switch cases. For a block that ends in a branch, we recognize Branch(Equal(value, const)),
Branch(NotEqual(value, const)), and Branch(value). Each of these are summarized as if they
were one-case switches. We infer a new switch if both some block and its sole predecessor
can be described as switches on the same value, nothing shady is going on (like loops), and
the block in question does no work other than this switch. In that case, the block is killed
and its cases (which we get from the summary) are added to the predecessor's switch. This
algorithm runs to fixpoint.
        
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* b3/B3Generate.cpp:
(JSC::B3::generateToAir):
* b3/B3InferSwitches.cpp: Added.
(JSC::B3::inferSwitches):
* b3/B3InferSwitches.h: Added.
* b3/B3Procedure.h:
(JSC::B3::Procedure::cfg):
* b3/B3ReduceStrength.cpp:
* b3/B3Value.cpp:
(JSC::B3::Value::performSubstitution):
(JSC::B3::Value::isFree):
(JSC::B3::Value::dumpMeta):
* b3/B3Value.h:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileCheckIdent):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
(JSC::FTL::DFG::LowerDFGToB3::lowSymbol):
(JSC::FTL::DFG::LowerDFGToB3::lowSymbolUID):
(JSC::FTL::DFG::LowerDFGToB3::lowNonNullObject):

LayoutTests:


* js/regress/bigswitch-indirect-expected.txt: Added.
* js/regress/bigswitch-indirect-symbol-expected.txt: Added.
* js/regress/bigswitch-indirect-symbol-or-undefined-expected.txt: Added.
* js/regress/bigswitch-indirect-symbol-or-undefined.html: Added.
* js/regress/bigswitch-indirect-symbol.html: Added.
* js/regress/bigswitch-indirect.html: Added.
* js/regress/implicit-bigswitch-indirect-symbol-expected.txt: Added.
* js/regress/implicit-bigswitch-indirect-symbol.html: Added.
* js/regress/script-tests/bigswitch-indirect-symbol-or-undefined.js: Added.
(foo):
* js/regress/script-tests/bigswitch-indirect-symbol.js: Added.
(foo):
* js/regress/script-tests/bigswitch-indirect.js: Added.
(foo):
* js/regress/script-tests/implicit-bigswitch-indirect-symbol.js: Added.
(foo):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Generatecpp">trunk/Source/JavaScriptCore/b3/B3Generate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3IndexMaph">trunk/Source/JavaScriptCore/b3/B3IndexMap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ReduceStrengthcpp">trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Valuecpp">trunk/Source/JavaScriptCore/b3/B3Value.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Valueh">trunk/Source/JavaScriptCore/b3/B3Value.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</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="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsregressbigswitchindirectexpectedtxt">trunk/LayoutTests/js/regress/bigswitch-indirect-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregressbigswitchindirectsymbolexpectedtxt">trunk/LayoutTests/js/regress/bigswitch-indirect-symbol-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregressbigswitchindirectsymbolorundefinedexpectedtxt">trunk/LayoutTests/js/regress/bigswitch-indirect-symbol-or-undefined-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregressbigswitchindirectsymbolorundefinedhtml">trunk/LayoutTests/js/regress/bigswitch-indirect-symbol-or-undefined.html</a></li>
<li><a href="#trunkLayoutTestsjsregressbigswitchindirectsymbolhtml">trunk/LayoutTests/js/regress/bigswitch-indirect-symbol.html</a></li>
<li><a href="#trunkLayoutTestsjsregressbigswitchindirecthtml">trunk/LayoutTests/js/regress/bigswitch-indirect.html</a></li>
<li><a href="#trunkLayoutTestsjsregressimplicitbigswitchindirectsymbolexpectedtxt">trunk/LayoutTests/js/regress/implicit-bigswitch-indirect-symbol-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregressimplicitbigswitchindirectsymbolhtml">trunk/LayoutTests/js/regress/implicit-bigswitch-indirect-symbol.html</a></li>
<li><a href="#trunkLayoutTestsjsregressscripttestsbigswitchindirectsymbolorundefinedjs">trunk/LayoutTests/js/regress/script-tests/bigswitch-indirect-symbol-or-undefined.js</a></li>
<li><a href="#trunkLayoutTestsjsregressscripttestsbigswitchindirectsymboljs">trunk/LayoutTests/js/regress/script-tests/bigswitch-indirect-symbol.js</a></li>
<li><a href="#trunkLayoutTestsjsregressscripttestsbigswitchindirectjs">trunk/LayoutTests/js/regress/script-tests/bigswitch-indirect.js</a></li>
<li><a href="#trunkLayoutTestsjsregressscripttestsimplicitbigswitchindirectsymboljs">trunk/LayoutTests/js/regress/script-tests/implicit-bigswitch-indirect-symbol.js</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3InferSwitchescpp">trunk/Source/JavaScriptCore/b3/B3InferSwitches.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3InferSwitchesh">trunk/Source/JavaScriptCore/b3/B3InferSwitches.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/LayoutTests/ChangeLog        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -1,3 +1,27 @@
</span><ins>+2016-07-19  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Switching on symbols should be fast
+        https://bugs.webkit.org/show_bug.cgi?id=158892
+
+        Reviewed by Keith Miller.
+
+        * js/regress/bigswitch-indirect-expected.txt: Added.
+        * js/regress/bigswitch-indirect-symbol-expected.txt: Added.
+        * js/regress/bigswitch-indirect-symbol-or-undefined-expected.txt: Added.
+        * js/regress/bigswitch-indirect-symbol-or-undefined.html: Added.
+        * js/regress/bigswitch-indirect-symbol.html: Added.
+        * js/regress/bigswitch-indirect.html: Added.
+        * js/regress/implicit-bigswitch-indirect-symbol-expected.txt: Added.
+        * js/regress/implicit-bigswitch-indirect-symbol.html: Added.
+        * js/regress/script-tests/bigswitch-indirect-symbol-or-undefined.js: Added.
+        (foo):
+        * js/regress/script-tests/bigswitch-indirect-symbol.js: Added.
+        (foo):
+        * js/regress/script-tests/bigswitch-indirect.js: Added.
+        (foo):
+        * js/regress/script-tests/implicit-bigswitch-indirect-symbol.js: Added.
+        (foo):
+
</ins><span class="cx"> 2016-07-20  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fix null handling of several Document attributes
</span></span></pre></div>
<a id="trunkLayoutTestsjsregressbigswitchindirectexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/bigswitch-indirect-expected.txt (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/bigswitch-indirect-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/bigswitch-indirect-expected.txt        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/bigswitch-indirect
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressbigswitchindirectsymbolexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/bigswitch-indirect-symbol-expected.txt (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/bigswitch-indirect-symbol-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/bigswitch-indirect-symbol-expected.txt        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/bigswitch-indirect-symbol
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressbigswitchindirectsymbolorundefinedexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/bigswitch-indirect-symbol-or-undefined-expected.txt (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/bigswitch-indirect-symbol-or-undefined-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/bigswitch-indirect-symbol-or-undefined-expected.txt        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/bigswitch-indirect-symbol-or-undefined
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressbigswitchindirectsymbolorundefinedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/bigswitch-indirect-symbol-or-undefined.html (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/bigswitch-indirect-symbol-or-undefined.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/bigswitch-indirect-symbol-or-undefined.html        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/bigswitch-indirect-symbol-or-undefined.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressbigswitchindirectsymbolhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/bigswitch-indirect-symbol.html (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/bigswitch-indirect-symbol.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/bigswitch-indirect-symbol.html        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/bigswitch-indirect-symbol.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressbigswitchindirecthtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/bigswitch-indirect.html (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/bigswitch-indirect.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/bigswitch-indirect.html        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/bigswitch-indirect.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressimplicitbigswitchindirectsymbolexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/implicit-bigswitch-indirect-symbol-expected.txt (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/implicit-bigswitch-indirect-symbol-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/implicit-bigswitch-indirect-symbol-expected.txt        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/implicit-bigswitch-indirect-symbol
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressimplicitbigswitchindirectsymbolhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/implicit-bigswitch-indirect-symbol.html (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/implicit-bigswitch-indirect-symbol.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/implicit-bigswitch-indirect-symbol.html        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/implicit-bigswitch-indirect-symbol.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressscripttestsbigswitchindirectsymbolorundefinedjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/bigswitch-indirect-symbol-or-undefined.js (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/bigswitch-indirect-symbol-or-undefined.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/bigswitch-indirect-symbol-or-undefined.js        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,279 @@
</span><ins>+var thing0 = Symbol();
+var thing1 = Symbol();
+var thing2 = Symbol();
+var thing3 = Symbol();
+var thing4 = Symbol();
+var thing5 = Symbol();
+var thing6 = Symbol();
+var thing7 = Symbol();
+var thing8 = Symbol();
+var thing9 = Symbol();
+var thing10 = Symbol();
+var thing11 = Symbol();
+var thing12 = Symbol();
+var thing13 = Symbol();
+var thing14 = Symbol();
+var thing15 = Symbol();
+var thing16 = Symbol();
+var thing17 = Symbol();
+var thing18 = Symbol();
+var thing19 = Symbol();
+var thing20 = Symbol();
+var thing21 = Symbol();
+var thing22 = Symbol();
+var thing23 = Symbol();
+var thing24 = Symbol();
+var thing25 = Symbol();
+var thing26 = Symbol();
+var thing27 = Symbol();
+var thing28 = Symbol();
+var thing29 = Symbol();
+var thing30 = Symbol();
+var thing31 = Symbol();
+var thing32 = Symbol();
+var thing33 = Symbol();
+var thing34 = Symbol();
+var thing35 = Symbol();
+var thing36 = Symbol();
+var thing37 = Symbol();
+var thing38 = Symbol();
+var thing39 = Symbol();
+var thing40 = Symbol();
+var thing41 = Symbol();
+var thing42 = Symbol();
+var thing43 = Symbol();
+var thing44 = Symbol();
+var thing45 = Symbol();
+var thing46 = Symbol();
+var thing47 = Symbol();
+var thing48 = Symbol();
+var thing49 = Symbol();
+var thing50 = Symbol();
+var thing51 = Symbol();
+var thing52 = Symbol();
+var thing53 = Symbol();
+var thing54 = Symbol();
+var thing55 = Symbol();
+var thing56 = Symbol();
+var thing57 = Symbol();
+var thing58 = Symbol();
+var thing59 = Symbol();
+var thing60 = Symbol();
+var thing61 = Symbol();
+var thing62 = Symbol();
+
+var things = [];
+for (var i = 0; i &lt; 63; ++i)
+    things.push(eval(&quot;thing&quot; + i));
+
+function foo(o) {
+    var result = 0;
+    for (var i = 0; i &lt; 1000; ++i) {
+        var value = things[i &amp; 63];
+        switch (value) {
+        case thing0:
+            result += o.a;
+            break;
+        case thing1:
+            result += o.b;
+            break;
+        case thing2:
+            result += o.c;
+            break;
+        case thing3:
+            result += o.d;
+            break;
+        case thing4:
+            result += o.e;
+            break;
+        case thing5:
+            result += o.f;
+            break;
+        case thing6:
+            result += o.g;
+            break;
+        case thing7:
+            result += o.h;
+            break;
+        case thing8:
+            result += o.i;
+            break;
+        case thing9:
+            result += o.j;
+            break;
+        case thing10:
+            result += o.k;
+            break;
+        case thing11:
+            result += o.a;
+            break;
+        case thing12:
+            result += o.b;
+            break;
+        case thing13:
+            result += o.c;
+            break;
+        case thing14:
+            result += o.d;
+            break;
+        case thing15:
+            result += o.e;
+            break;
+        case thing16:
+            result += o.f;
+            break;
+        case thing17:
+            result += o.g;
+            break;
+        case thing18:
+            result += o.h;
+            break;
+        case thing19:
+            result += o.i;
+            break;
+        case thing20:
+            result += o.j;
+            break;
+        case thing21:
+            result += o.k;
+            break;
+        case thing22:
+            result += o.k;
+            break;
+        case thing23:
+            result += o.a;
+            break;
+        case thing24:
+            result += o.b;
+            break;
+        case thing25:
+            result += o.c;
+            break;
+        case thing26:
+            result += o.d;
+            break;
+        case thing27:
+            result += o.e;
+            break;
+        case thing28:
+            result += o.f;
+            break;
+        case thing29:
+            result += o.g;
+            break;
+        case thing30:
+            result += o.h;
+            break;
+        case thing31:
+            result += o.i;
+            break;
+        case thing32:
+            result += o.j;
+            break;
+        case thing33:
+            result += o.k;
+            break;
+        case thing34:
+            result += o.k;
+            break;
+        case thing35:
+            result += o.k;
+            break;
+        case thing36:
+            result += o.a;
+            break;
+        case thing37:
+            result += o.b;
+            break;
+        case thing38:
+            result += o.c;
+            break;
+        case thing39:
+            result += o.d;
+            break;
+        case thing40:
+            result += o.e;
+            break;
+        case thing41:
+            result += o.f;
+            break;
+        case thing42:
+            result += o.g;
+            break;
+        case thing43:
+            result += o.h;
+            break;
+        case thing44:
+            result += o.i;
+            break;
+        case thing45:
+            result += o.j;
+            break;
+        case thing46:
+            result += o.k;
+            break;
+        case thing47:
+            result += o.i;
+            break;
+        case thing48:
+            result += o.j;
+            break;
+        case thing49:
+            result += o.k;
+            break;
+        case thing50:
+            result += o.k;
+            break;
+        case thing51:
+            result += o.k;
+            break;
+        case thing52:
+            result += o.a;
+            break;
+        case thing53:
+            result += o.b;
+            break;
+        case thing54:
+            result += o.c;
+            break;
+        case thing55:
+            result += o.d;
+            break;
+        case thing56:
+            result += o.e;
+            break;
+        case thing57:
+            result += o.f;
+            break;
+        case thing58:
+            result += o.g;
+            break;
+        case thing59:
+            result += o.h;
+            break;
+        case thing60:
+            result += o.i;
+            break;
+        case thing61:
+            result += o.j;
+            break;
+        case thing62:
+            result += o.k;
+            break;
+        default:
+            result += o.z;
+            break;
+        }
+    }
+    return result;
+}
+
+(function() {
+    var o = {a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11, z:100};
+    var result = 0;
+    for (var i = 0; i &lt; 1000; ++i)
+        result += foo(o);
+    if (result != 7966000)
+        throw &quot;Error: bad result: &quot; + result;
+})();
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressscripttestsbigswitchindirectsymboljs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/bigswitch-indirect-symbol.js (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/bigswitch-indirect-symbol.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/bigswitch-indirect-symbol.js        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,280 @@
</span><ins>+var thing0 = Symbol();
+var thing1 = Symbol();
+var thing2 = Symbol();
+var thing3 = Symbol();
+var thing4 = Symbol();
+var thing5 = Symbol();
+var thing6 = Symbol();
+var thing7 = Symbol();
+var thing8 = Symbol();
+var thing9 = Symbol();
+var thing10 = Symbol();
+var thing11 = Symbol();
+var thing12 = Symbol();
+var thing13 = Symbol();
+var thing14 = Symbol();
+var thing15 = Symbol();
+var thing16 = Symbol();
+var thing17 = Symbol();
+var thing18 = Symbol();
+var thing19 = Symbol();
+var thing20 = Symbol();
+var thing21 = Symbol();
+var thing22 = Symbol();
+var thing23 = Symbol();
+var thing24 = Symbol();
+var thing25 = Symbol();
+var thing26 = Symbol();
+var thing27 = Symbol();
+var thing28 = Symbol();
+var thing29 = Symbol();
+var thing30 = Symbol();
+var thing31 = Symbol();
+var thing32 = Symbol();
+var thing33 = Symbol();
+var thing34 = Symbol();
+var thing35 = Symbol();
+var thing36 = Symbol();
+var thing37 = Symbol();
+var thing38 = Symbol();
+var thing39 = Symbol();
+var thing40 = Symbol();
+var thing41 = Symbol();
+var thing42 = Symbol();
+var thing43 = Symbol();
+var thing44 = Symbol();
+var thing45 = Symbol();
+var thing46 = Symbol();
+var thing47 = Symbol();
+var thing48 = Symbol();
+var thing49 = Symbol();
+var thing50 = Symbol();
+var thing51 = Symbol();
+var thing52 = Symbol();
+var thing53 = Symbol();
+var thing54 = Symbol();
+var thing55 = Symbol();
+var thing56 = Symbol();
+var thing57 = Symbol();
+var thing58 = Symbol();
+var thing59 = Symbol();
+var thing60 = Symbol();
+var thing61 = Symbol();
+var thing62 = Symbol();
+var thing63 = Symbol();
+
+var things = [];
+for (var i = 0; i &lt; 64; ++i)
+    things.push(eval(&quot;thing&quot; + i));
+
+function foo(o) {
+    var result = 0;
+    for (var i = 0; i &lt; 1000; ++i) {
+        var value = things[i &amp; 63];
+        switch (value) {
+        case thing0:
+            result += o.a;
+            break;
+        case thing1:
+            result += o.b;
+            break;
+        case thing2:
+            result += o.c;
+            break;
+        case thing3:
+            result += o.d;
+            break;
+        case thing4:
+            result += o.e;
+            break;
+        case thing5:
+            result += o.f;
+            break;
+        case thing6:
+            result += o.g;
+            break;
+        case thing7:
+            result += o.h;
+            break;
+        case thing8:
+            result += o.i;
+            break;
+        case thing9:
+            result += o.j;
+            break;
+        case thing10:
+            result += o.k;
+            break;
+        case thing11:
+            result += o.a;
+            break;
+        case thing12:
+            result += o.b;
+            break;
+        case thing13:
+            result += o.c;
+            break;
+        case thing14:
+            result += o.d;
+            break;
+        case thing15:
+            result += o.e;
+            break;
+        case thing16:
+            result += o.f;
+            break;
+        case thing17:
+            result += o.g;
+            break;
+        case thing18:
+            result += o.h;
+            break;
+        case thing19:
+            result += o.i;
+            break;
+        case thing20:
+            result += o.j;
+            break;
+        case thing21:
+            result += o.k;
+            break;
+        case thing22:
+            result += o.k;
+            break;
+        case thing23:
+            result += o.a;
+            break;
+        case thing24:
+            result += o.b;
+            break;
+        case thing25:
+            result += o.c;
+            break;
+        case thing26:
+            result += o.d;
+            break;
+        case thing27:
+            result += o.e;
+            break;
+        case thing28:
+            result += o.f;
+            break;
+        case thing29:
+            result += o.g;
+            break;
+        case thing30:
+            result += o.h;
+            break;
+        case thing31:
+            result += o.i;
+            break;
+        case thing32:
+            result += o.j;
+            break;
+        case thing33:
+            result += o.k;
+            break;
+        case thing34:
+            result += o.k;
+            break;
+        case thing35:
+            result += o.k;
+            break;
+        case thing36:
+            result += o.a;
+            break;
+        case thing37:
+            result += o.b;
+            break;
+        case thing38:
+            result += o.c;
+            break;
+        case thing39:
+            result += o.d;
+            break;
+        case thing40:
+            result += o.e;
+            break;
+        case thing41:
+            result += o.f;
+            break;
+        case thing42:
+            result += o.g;
+            break;
+        case thing43:
+            result += o.h;
+            break;
+        case thing44:
+            result += o.i;
+            break;
+        case thing45:
+            result += o.j;
+            break;
+        case thing46:
+            result += o.k;
+            break;
+        case thing47:
+            result += o.i;
+            break;
+        case thing48:
+            result += o.j;
+            break;
+        case thing49:
+            result += o.k;
+            break;
+        case thing50:
+            result += o.k;
+            break;
+        case thing51:
+            result += o.k;
+            break;
+        case thing52:
+            result += o.a;
+            break;
+        case thing53:
+            result += o.b;
+            break;
+        case thing54:
+            result += o.c;
+            break;
+        case thing55:
+            result += o.d;
+            break;
+        case thing56:
+            result += o.e;
+            break;
+        case thing57:
+            result += o.f;
+            break;
+        case thing58:
+            result += o.g;
+            break;
+        case thing59:
+            result += o.h;
+            break;
+        case thing60:
+            result += o.i;
+            break;
+        case thing61:
+            result += o.j;
+            break;
+        case thing62:
+            result += o.k;
+            break;
+        default:
+            result += o.z;
+            break;
+        }
+    }
+    return result;
+}
+
+(function() {
+    var o = {a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11, z:100};
+    var result = 0;
+    for (var i = 0; i &lt; 10000; ++i)
+        result += foo(o);
+    if (result != 79660000)
+        throw &quot;Error: bad result: &quot; + result;
+})();
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressscripttestsbigswitchindirectjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/bigswitch-indirect.js (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/bigswitch-indirect.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/bigswitch-indirect.js        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,275 @@
</span><ins>+var thing0 = 0;
+var thing1 = 1;
+var thing2 = 2;
+var thing3 = 3;
+var thing4 = 4;
+var thing5 = 5;
+var thing6 = 6;
+var thing7 = 7;
+var thing8 = 8;
+var thing9 = 9;
+var thing10 = 10;
+var thing11 = 11;
+var thing12 = 12;
+var thing13 = 13;
+var thing14 = 14;
+var thing15 = 15;
+var thing16 = 16;
+var thing17 = 17;
+var thing18 = 18;
+var thing19 = 19;
+var thing20 = 20;
+var thing21 = 21;
+var thing22 = 22;
+var thing23 = 23;
+var thing24 = 24;
+var thing25 = 25;
+var thing26 = 26;
+var thing27 = 27;
+var thing28 = 28;
+var thing29 = 29;
+var thing30 = 30;
+var thing31 = 31;
+var thing32 = 32;
+var thing33 = 33;
+var thing34 = 34;
+var thing35 = 35;
+var thing36 = 36;
+var thing37 = 37;
+var thing38 = 38;
+var thing39 = 39;
+var thing40 = 40;
+var thing41 = 41;
+var thing42 = 42;
+var thing43 = 43;
+var thing44 = 44;
+var thing45 = 45;
+var thing46 = 46;
+var thing47 = 47;
+var thing48 = 48;
+var thing49 = 49;
+var thing50 = 50;
+var thing51 = 51;
+var thing52 = 52;
+var thing53 = 53;
+var thing54 = 54;
+var thing55 = 55;
+var thing56 = 56;
+var thing57 = 57;
+var thing58 = 58;
+var thing59 = 59;
+var thing60 = 60;
+var thing61 = 61;
+var thing62 = 62;
+
+function foo(o) {
+    var result = 0;
+    for (var i = 0; i &lt; 1000; ++i) {
+        var value = i &amp; 63;
+        switch (value) {
+        case thing0:
+            result += o.a;
+            break;
+        case thing1:
+            result += o.b;
+            break;
+        case thing2:
+            result += o.c;
+            break;
+        case thing3:
+            result += o.d;
+            break;
+        case thing4:
+            result += o.e;
+            break;
+        case thing5:
+            result += o.f;
+            break;
+        case thing6:
+            result += o.g;
+            break;
+        case thing7:
+            result += o.h;
+            break;
+        case thing8:
+            result += o.i;
+            break;
+        case thing9:
+            result += o.j;
+            break;
+        case thing10:
+            result += o.k;
+            break;
+        case thing11:
+            result += o.a;
+            break;
+        case thing12:
+            result += o.b;
+            break;
+        case thing13:
+            result += o.c;
+            break;
+        case thing14:
+            result += o.d;
+            break;
+        case thing15:
+            result += o.e;
+            break;
+        case thing16:
+            result += o.f;
+            break;
+        case thing17:
+            result += o.g;
+            break;
+        case thing18:
+            result += o.h;
+            break;
+        case thing19:
+            result += o.i;
+            break;
+        case thing20:
+            result += o.j;
+            break;
+        case thing21:
+            result += o.k;
+            break;
+        case thing22:
+            result += o.k;
+            break;
+        case thing23:
+            result += o.a;
+            break;
+        case thing24:
+            result += o.b;
+            break;
+        case thing25:
+            result += o.c;
+            break;
+        case thing26:
+            result += o.d;
+            break;
+        case thing27:
+            result += o.e;
+            break;
+        case thing28:
+            result += o.f;
+            break;
+        case thing29:
+            result += o.g;
+            break;
+        case thing30:
+            result += o.h;
+            break;
+        case thing31:
+            result += o.i;
+            break;
+        case thing32:
+            result += o.j;
+            break;
+        case thing33:
+            result += o.k;
+            break;
+        case thing34:
+            result += o.k;
+            break;
+        case thing35:
+            result += o.k;
+            break;
+        case thing36:
+            result += o.a;
+            break;
+        case thing37:
+            result += o.b;
+            break;
+        case thing38:
+            result += o.c;
+            break;
+        case thing39:
+            result += o.d;
+            break;
+        case thing40:
+            result += o.e;
+            break;
+        case thing41:
+            result += o.f;
+            break;
+        case thing42:
+            result += o.g;
+            break;
+        case thing43:
+            result += o.h;
+            break;
+        case thing44:
+            result += o.i;
+            break;
+        case thing45:
+            result += o.j;
+            break;
+        case thing46:
+            result += o.k;
+            break;
+        case thing47:
+            result += o.i;
+            break;
+        case thing48:
+            result += o.j;
+            break;
+        case thing49:
+            result += o.k;
+            break;
+        case thing50:
+            result += o.k;
+            break;
+        case thing51:
+            result += o.k;
+            break;
+        case thing52:
+            result += o.a;
+            break;
+        case thing53:
+            result += o.b;
+            break;
+        case thing54:
+            result += o.c;
+            break;
+        case thing55:
+            result += o.d;
+            break;
+        case thing56:
+            result += o.e;
+            break;
+        case thing57:
+            result += o.f;
+            break;
+        case thing58:
+            result += o.g;
+            break;
+        case thing59:
+            result += o.h;
+            break;
+        case thing60:
+            result += o.i;
+            break;
+        case thing61:
+            result += o.j;
+            break;
+        case thing62:
+            result += o.k;
+            break;
+        default:
+            result += o.z;
+            break;
+        }
+    }
+    return result;
+}
+
+(function() {
+    var o = {a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11, z:100};
+    var result = 0;
+    for (var i = 0; i &lt; 5000; ++i)
+        result += foo(o);
+    if (result != 39830000)
+        throw &quot;Error: bad result: &quot; + result;
+})();
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressscripttestsimplicitbigswitchindirectsymboljs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/implicit-bigswitch-indirect-symbol.js (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/implicit-bigswitch-indirect-symbol.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/implicit-bigswitch-indirect-symbol.js        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,214 @@
</span><ins>+var thing0 = Symbol();
+var thing1 = Symbol();
+var thing2 = Symbol();
+var thing3 = Symbol();
+var thing4 = Symbol();
+var thing5 = Symbol();
+var thing6 = Symbol();
+var thing7 = Symbol();
+var thing8 = Symbol();
+var thing9 = Symbol();
+var thing10 = Symbol();
+var thing11 = Symbol();
+var thing12 = Symbol();
+var thing13 = Symbol();
+var thing14 = Symbol();
+var thing15 = Symbol();
+var thing16 = Symbol();
+var thing17 = Symbol();
+var thing18 = Symbol();
+var thing19 = Symbol();
+var thing20 = Symbol();
+var thing21 = Symbol();
+var thing22 = Symbol();
+var thing23 = Symbol();
+var thing24 = Symbol();
+var thing25 = Symbol();
+var thing26 = Symbol();
+var thing27 = Symbol();
+var thing28 = Symbol();
+var thing29 = Symbol();
+var thing30 = Symbol();
+var thing31 = Symbol();
+var thing32 = Symbol();
+var thing33 = Symbol();
+var thing34 = Symbol();
+var thing35 = Symbol();
+var thing36 = Symbol();
+var thing37 = Symbol();
+var thing38 = Symbol();
+var thing39 = Symbol();
+var thing40 = Symbol();
+var thing41 = Symbol();
+var thing42 = Symbol();
+var thing43 = Symbol();
+var thing44 = Symbol();
+var thing45 = Symbol();
+var thing46 = Symbol();
+var thing47 = Symbol();
+var thing48 = Symbol();
+var thing49 = Symbol();
+var thing50 = Symbol();
+var thing51 = Symbol();
+var thing52 = Symbol();
+var thing53 = Symbol();
+var thing54 = Symbol();
+var thing55 = Symbol();
+var thing56 = Symbol();
+var thing57 = Symbol();
+var thing58 = Symbol();
+var thing59 = Symbol();
+var thing60 = Symbol();
+var thing61 = Symbol();
+var thing62 = Symbol();
+var thing63 = Symbol();
+
+var things = [];
+for (var i = 0; i &lt; 64; ++i)
+    things.push(eval(&quot;thing&quot; + i));
+
+function foo(o) {
+    var result = 0;
+    for (var i = 0; i &lt; 1000; ++i) {
+        var value = things[i &amp; 63];
+        if (value === thing0)
+            result += o.a;
+        else if (value === thing1)
+            result += o.b;
+        else if (value === thing2)
+            result += o.c;
+        else if (value === thing3)
+            result += o.d;
+        else if (value === thing4)
+            result += o.e;
+        else if (value === thing5)
+            result += o.f;
+        else if (value === thing6)
+            result += o.g;
+        else if (value === thing7)
+            result += o.h;
+        else if (value === thing8)
+            result += o.i;
+        else if (value === thing9)
+            result += o.j;
+        else if (value === thing10)
+            result += o.k;
+        else if (value === thing11)
+            result += o.a;
+        else if (value === thing12)
+            result += o.b;
+        else if (value === thing13)
+            result += o.c;
+        else if (value === thing14)
+            result += o.d;
+        else if (value === thing15)
+            result += o.e;
+        else if (value === thing16)
+            result += o.f;
+        else if (value === thing17)
+            result += o.g;
+        else if (value === thing18)
+            result += o.h;
+        else if (value === thing19)
+            result += o.i;
+        else if (value === thing20)
+            result += o.j;
+        else if (value === thing21)
+            result += o.k;
+        else if (value === thing22)
+            result += o.k;
+        else if (value === thing23)
+            result += o.a;
+        else if (value === thing24)
+            result += o.b;
+        else if (value === thing25)
+            result += o.c;
+        else if (value === thing26)
+            result += o.d;
+        else if (value === thing27)
+            result += o.e;
+        else if (value === thing28)
+            result += o.f;
+        else if (value === thing29)
+            result += o.g;
+        else if (value === thing30)
+            result += o.h;
+        else if (value === thing31)
+            result += o.i;
+        else if (value === thing32)
+            result += o.j;
+        else if (value === thing33)
+            result += o.k;
+        else if (value === thing34)
+            result += o.k;
+        else if (value === thing35)
+            result += o.k;
+        else if (value === thing36)
+            result += o.a;
+        else if (value === thing37)
+            result += o.b;
+        else if (value === thing38)
+            result += o.c;
+        else if (value === thing39)
+            result += o.d;
+        else if (value === thing40)
+            result += o.e;
+        else if (value === thing41)
+            result += o.f;
+        else if (value === thing42)
+            result += o.g;
+        else if (value === thing43)
+            result += o.h;
+        else if (value === thing44)
+            result += o.i;
+        else if (value === thing45)
+            result += o.j;
+        else if (value === thing46)
+            result += o.k;
+        else if (value === thing47)
+            result += o.i;
+        else if (value === thing48)
+            result += o.j;
+        else if (value === thing49)
+            result += o.k;
+        else if (value === thing50)
+            result += o.k;
+        else if (value === thing51)
+            result += o.k;
+        else if (value === thing52)
+            result += o.a;
+        else if (value === thing53)
+            result += o.b;
+        else if (value === thing54)
+            result += o.c;
+        else if (value === thing55)
+            result += o.d;
+        else if (value === thing56)
+            result += o.e;
+        else if (value === thing57)
+            result += o.f;
+        else if (value === thing58)
+            result += o.g;
+        else if (value === thing59)
+            result += o.h;
+        else if (value === thing60)
+            result += o.i;
+        else if (value === thing61)
+            result += o.j;
+        else if (value === thing62)
+            result += o.k;
+        else
+            result += o.z;
+    }
+    return result;
+}
+
+(function() {
+    var o = {a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11, z:100};
+    var result = 0;
+    for (var i = 0; i &lt; 4000; ++i)
+        result += foo(o);
+    if (result != 31864000)
+        throw &quot;Error: bad result: &quot; + result;
+})();
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -128,6 +128,7 @@
</span><span class="cx">     b3/B3FrequencyClass.cpp
</span><span class="cx">     b3/B3Generate.cpp
</span><span class="cx">     b3/B3HeapRange.cpp
</span><ins>+    b3/B3InferSwitches.cpp
</ins><span class="cx">     b3/B3InsertionSet.cpp
</span><span class="cx">     b3/B3LegalizeMemoryOffsets.cpp
</span><span class="cx">     b3/B3LowerMacros.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -1,3 +1,60 @@
</span><ins>+2016-07-18  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Switching on symbols should be fast
+        https://bugs.webkit.org/show_bug.cgi?id=158892
+
+        Reviewed by Keith Miller.
+        
+        This does two things: fixes some goofs in our lowering of symbol equality and adds a new phase
+        to B3 to infer switch statements from linear chains of branches.
+        
+        This changes how we compile equality to Symbols to constant-fold the load of the Symbol's UID.
+        This is necessary for making switches on Symbols inferrable. This also gives us the ability to
+        efficiently compile strict equality comparisons of SymbolUse and UntypedUse.
+
+        This adds a new phase to B3, which finds chains of branches that test for (in)equality on the
+        same value and constants, and turns them into a Switch. This can turn O(n) code into
+        O(log n) code, or even O(1) code if the switch cases are dense.
+        
+        This can make a big difference in JS. Say you write a switch in which the case statements are
+        variable resolutions. The bytecode generator cannot use a bytecode switch in this case, since
+        we're required to evaluate the resolutions in order. But in DFG IR, we will often turn those
+        variable resolutions into constants, since we do that for any immutable singleton. This means
+        that B3 will see a chain of Branches: the else case of one Branch will point to a basic block
+        that does nothing but Branch on equality on the same value as the first Branch.
+
+        The inference algorithm is quite simple. The basic building block is the ability to summarize
+        a block's switch behavior. For a block that ends in a switch, this is just the collection of
+        switch cases. For a block that ends in a branch, we recognize Branch(Equal(value, const)),
+        Branch(NotEqual(value, const)), and Branch(value). Each of these are summarized as if they
+        were one-case switches. We infer a new switch if both some block and its sole predecessor
+        can be described as switches on the same value, nothing shady is going on (like loops), and
+        the block in question does no work other than this switch. In that case, the block is killed
+        and its cases (which we get from the summary) are added to the predecessor's switch. This
+        algorithm runs to fixpoint.
+        
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * b3/B3Generate.cpp:
+        (JSC::B3::generateToAir):
+        * b3/B3InferSwitches.cpp: Added.
+        (JSC::B3::inferSwitches):
+        * b3/B3InferSwitches.h: Added.
+        * b3/B3Procedure.h:
+        (JSC::B3::Procedure::cfg):
+        * b3/B3ReduceStrength.cpp:
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::performSubstitution):
+        (JSC::B3::Value::isFree):
+        (JSC::B3::Value::dumpMeta):
+        * b3/B3Value.h:
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileCheckIdent):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
+        (JSC::FTL::DFG::LowerDFGToB3::lowSymbol):
+        (JSC::FTL::DFG::LowerDFGToB3::lowSymbolUID):
+        (JSC::FTL::DFG::LowerDFGToB3::lowNonNullObject):
+
</ins><span class="cx"> 2016-07-20  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         FTL snippet generators should be able to request a different register for output and input
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -1999,6 +1999,8 @@
</span><span class="cx">                 DC605B5F1CE26EA500593718 /* ProfilerUID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC605B5B1CE26E9800593718 /* ProfilerUID.cpp */; };
</span><span class="cx">                 DC605B601CE26EA700593718 /* ProfilerUID.h in Headers */ = {isa = PBXBuildFile; fileRef = DC605B5C1CE26E9800593718 /* ProfilerUID.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 DC69AA661CF7A1F200C6272F /* MatchResult.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC69AA651CF7A1EF00C6272F /* MatchResult.cpp */; };
</span><ins>+                DC69B99C1D15F912002E3C00 /* B3InferSwitches.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC69B99A1D15F90F002E3C00 /* B3InferSwitches.cpp */; };
+                DC69B99D1D15F914002E3C00 /* B3InferSwitches.h in Headers */ = {isa = PBXBuildFile; fileRef = DC69B99B1D15F90F002E3C00 /* B3InferSwitches.h */; };
</ins><span class="cx">                 DC7997831CDE9FA0004D4A09 /* TagRegistersMode.h in Headers */ = {isa = PBXBuildFile; fileRef = DC7997821CDE9F9E004D4A09 /* TagRegistersMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 DC7997841CDE9FA2004D4A09 /* TagRegistersMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC7997811CDE9F9E004D4A09 /* TagRegistersMode.cpp */; };
</span><span class="cx">                 DC9A0C1F1D2D9CB10085124E /* B3CaseCollectionInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = DC9A0C1E1D2D94EF0085124E /* B3CaseCollectionInlines.h */; };
</span><span class="lines">@@ -4234,6 +4236,8 @@
</span><span class="cx">                 DC605B5B1CE26E9800593718 /* ProfilerUID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProfilerUID.cpp; path = profiler/ProfilerUID.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 DC605B5C1CE26E9800593718 /* ProfilerUID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerUID.h; path = profiler/ProfilerUID.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 DC69AA651CF7A1EF00C6272F /* MatchResult.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MatchResult.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                DC69B99A1D15F90F002E3C00 /* B3InferSwitches.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3InferSwitches.cpp; path = b3/B3InferSwitches.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                DC69B99B1D15F90F002E3C00 /* B3InferSwitches.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3InferSwitches.h; path = b3/B3InferSwitches.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 DC7997811CDE9F9E004D4A09 /* TagRegistersMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TagRegistersMode.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 DC7997821CDE9F9E004D4A09 /* TagRegistersMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TagRegistersMode.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 DC9A0C1C1D2D94EF0085124E /* B3CaseCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3CaseCollection.cpp; path = b3/B3CaseCollection.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -4755,6 +4759,8 @@
</span><span class="cx">                                 0FEC85C01BE167A00080FF74 /* B3HeapRange.h */,
</span><span class="cx">                                 0FEC84D11BDACDAC0080FF74 /* B3IndexMap.h */,
</span><span class="cx">                                 0FEC84D21BDACDAC0080FF74 /* B3IndexSet.h */,
</span><ins>+                                DC69B99A1D15F90F002E3C00 /* B3InferSwitches.cpp */,
+                                DC69B99B1D15F90F002E3C00 /* B3InferSwitches.h */,
</ins><span class="cx">                                 0FEC85B41BE1462F0080FF74 /* B3InsertionSet.cpp */,
</span><span class="cx">                                 0FEC85B51BE1462F0080FF74 /* B3InsertionSet.h */,
</span><span class="cx">                                 0FEC85B61BE1462F0080FF74 /* B3InsertionSetInlines.h */,
</span><span class="lines">@@ -7566,6 +7572,7 @@
</span><span class="cx">                                 A5EA710419F6DE720098F5EC /* generate_objc_backend_dispatcher_implementation.py in Headers */,
</span><span class="cx">                                 0F64EAF31C4ECD0600621E9B /* AirArgInlines.h in Headers */,
</span><span class="cx">                                 A5EA710519F6DE740098F5EC /* generate_objc_configuration_header.py in Headers */,
</span><ins>+                                DC69B99D1D15F914002E3C00 /* B3InferSwitches.h in Headers */,
</ins><span class="cx">                                 A5EA710619F6DE760098F5EC /* generate_objc_configuration_implementation.py in Headers */,
</span><span class="cx">                                 0F7C39FF1C90C55B00480151 /* DFGOpInfo.h in Headers */,
</span><span class="cx">                                 A5EA710719F6DE780098F5EC /* generate_objc_protocol_type_conversions_header.py in Headers */,
</span><span class="lines">@@ -8733,6 +8740,7 @@
</span><span class="cx">                                 0FEC85051BDACDAC0080FF74 /* B3CheckSpecial.cpp in Sources */,
</span><span class="cx">                                 0FEC85071BDACDAC0080FF74 /* B3CheckValue.cpp in Sources */,
</span><span class="cx">                                 0FEC85091BDACDAC0080FF74 /* B3Common.cpp in Sources */,
</span><ins>+                                DC69B99C1D15F912002E3C00 /* B3InferSwitches.cpp in Sources */,
</ins><span class="cx">                                 0FEC850B1BDACDAC0080FF74 /* B3Commutativity.cpp in Sources */,
</span><span class="cx">                                 0FEC850D1BDACDAC0080FF74 /* B3Const32Value.cpp in Sources */,
</span><span class="cx">                                 436E54541C468E7700B5AF73 /* B3LegalizeMemoryOffsets.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Generatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Generate.cpp (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Generate.cpp        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/Source/JavaScriptCore/b3/B3Generate.cpp        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -36,6 +36,7 @@
</span><span class="cx"> #include &quot;B3EliminateCommonSubexpressions.h&quot;
</span><span class="cx"> #include &quot;B3FixSSA.h&quot;
</span><span class="cx"> #include &quot;B3FoldPathConstants.h&quot;
</span><ins>+#include &quot;B3InferSwitches.h&quot;
</ins><span class="cx"> #include &quot;B3LegalizeMemoryOffsets.h&quot;
</span><span class="cx"> #include &quot;B3LowerMacros.h&quot;
</span><span class="cx"> #include &quot;B3LowerMacrosAfterOptimizations.h&quot;
</span><span class="lines">@@ -82,6 +83,7 @@
</span><span class="cx">         reduceDoubleToFloat(procedure);
</span><span class="cx">         reduceStrength(procedure);
</span><span class="cx">         eliminateCommonSubexpressions(procedure);
</span><ins>+        inferSwitches(procedure);
</ins><span class="cx">         duplicateTails(procedure);
</span><span class="cx">         fixSSA(procedure);
</span><span class="cx">         foldPathConstants(procedure);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3IndexMaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3IndexMap.h (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3IndexMap.h        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/Source/JavaScriptCore/b3/B3IndexMap.h        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3InferSwitchescpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/b3/B3InferSwitches.cpp (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3InferSwitches.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/b3/B3InferSwitches.cpp        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,337 @@
</span><ins>+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;B3InferSwitches.h&quot;
+
+#if ENABLE(B3_JIT)
+
+#include &quot;B3BasicBlockInlines.h&quot;
+#include &quot;B3CaseCollectionInlines.h&quot;
+#include &quot;B3InsertionSetInlines.h&quot;
+#include &quot;B3PhaseScope.h&quot;
+#include &quot;B3ProcedureInlines.h&quot;
+#include &quot;B3SwitchValue.h&quot;
+#include &quot;B3UseCounts.h&quot;
+#include &quot;B3ValueInlines.h&quot;
+#include &lt;wtf/ListDump.h&gt;
+
+namespace JSC { namespace B3 {
+
+namespace {
+
+const bool verbose = false;
+
+class InferSwitches {
+public:
+    InferSwitches(Procedure&amp; proc)
+        : m_proc(proc)
+        , m_insertionSet(proc)
+        , m_useCounts(proc)
+    {
+    }
+    
+    bool run()
+    {
+        if (verbose)
+            dataLog(&quot;B3 before inferSwitches:\n&quot;, m_proc);
+        
+        bool changed = true;
+        bool everChanged = false;
+        while (changed) {
+            changed = false;
+            
+            if (verbose)
+                dataLog(&quot;Performing fixpoint iteration:\n&quot;);
+            
+            for (BasicBlock* block : m_proc)
+                changed |= attemptToMergeWithPredecessor(block);
+
+            everChanged |= changed;
+        }
+        
+        if (everChanged) {
+            m_proc.resetReachability();
+            m_proc.invalidateCFG();
+            
+            m_proc.deleteOrphans();
+            
+            if (verbose)
+                dataLog(&quot;B3 after inferSwitches:\n&quot;, m_proc);
+            return true;
+        }
+        
+        return false;
+    }
+    
+private:
+    bool attemptToMergeWithPredecessor(BasicBlock* block)
+    {
+        // No point in considering the root block. We also don't consider blocks with multiple
+        // predecessors, but we could handle this if we made this code a bit more general and we were
+        // not afraid of code bloat.
+        if (block-&gt;numPredecessors() != 1)
+            return false;
+        
+        SwitchDescription description = describe(block);
+        if (verbose)
+            dataLog(&quot;Description of primary block &quot;, *block, &quot;: &quot;, description, &quot;\n&quot;);
+        if (!description) {
+            if (verbose)
+                dataLog(&quot;    Bailing because not switch-like.\n&quot;);
+            return false;
+        }
+        
+        // We know that this block behaves like a switch. But we need to verify that it doesn't also
+        // perform any effects or do expensive things. We don't want to create a switch if that will
+        // make expensive things execute unconditionally. We're very conservative about how we define
+        // &quot;expensive&quot;.
+        for (Value* value : *block) {
+            if (value-&gt;isFree())
+                continue;
+            if (value == description.extra)
+                continue;
+            if (value == description.branch)
+                continue;
+            if (verbose)
+                dataLog(&quot;    Bailing because of &quot;, deepDump(m_proc, value), &quot;\n&quot;);
+            return false;
+        }
+        
+        BasicBlock* predecessor = block-&gt;predecessor(0);
+        SwitchDescription predecessorDescription = describe(predecessor);
+        if (verbose)
+            dataLog(&quot;    Description of predecessor block &quot;, *predecessor, &quot;: &quot;, predecessorDescription, &quot;\n&quot;);
+        if (!predecessorDescription) {
+            if (verbose)
+                dataLog(&quot;    Bailing because not switch-like.\n&quot;);
+            return false;
+        }
+        
+        // Both us and the predecessor are switch-like, but that doesn't mean that we're compatible.
+        // We may be switching on different values!
+        if (description.source != predecessorDescription.source) {
+            if (verbose)
+                dataLog(&quot;    Bailing because sources don't match.\n&quot;);
+            return false;
+        }
+        
+        // We expect that we are the fall-through destination of the predecessor. This is a bit of a
+        // goofy condition. If we were not the fall-through destination then our switch is probably
+        // just totally redundant and we should be getting rid of it. But we don't handle that here,
+        // yet.
+        if (predecessorDescription.fallThrough.block() != block) {
+            if (verbose)
+                dataLog(&quot;    Bailing because fall-through of predecessor is not the primary block.\n&quot;);
+            return false;
+        }
+        
+        // Make sure that there ain't no loops.
+        if (description.fallThrough.block() == block
+            || description.fallThrough.block() == predecessor) {
+            if (verbose)
+                dataLog(&quot;    Bailing because of fall-through loop.\n&quot;);
+            return false;
+        }
+        for (SwitchCase switchCase : description.cases) {
+            if (switchCase.targetBlock() == block
+                || switchCase.targetBlock() == predecessor) {
+                if (verbose)
+                    dataLog(&quot;    Bailing because of loop in primary cases.\n&quot;);
+                return false;
+            }
+        }
+        for (SwitchCase switchCase : predecessorDescription.cases) {
+            if (switchCase.targetBlock() == block
+                || switchCase.targetBlock() == predecessor) {
+                if (verbose)
+                    dataLog(&quot;    Bailing because of loop in predecessor cases.\n&quot;);
+                return false;
+            }
+        }
+        
+        if (verbose)
+            dataLog(&quot;    Doing it!\n&quot;);
+        // We're committed to doing the thing.
+        
+        // Delete the extra value from the predecessor, since that would break downstream inference
+        // on the next fixpoint iteration. We would think that this block is too expensive to merge
+        // because of the Equal or NotEqual value even though that value is dead! We know it's dead
+        // so we kill it ourselves.
+        for (Value* value : *predecessor) {
+            if (value == predecessorDescription.extra)
+                value-&gt;replaceWithNopIgnoringType();
+        }
+        
+        // Insert all non-terminal values from our block into our predecessor. We definitely need to
+        // do this for constants. We must not do it for the extra value, since that would break
+        // downstream inference on the next fixpoint iteration. As a bonus, we don't do it for nops,
+        // so that we limit how big blocks get in this phase.
+        for (unsigned i = 0; i &lt; block-&gt;size() - 1; ++i) {
+            Value* value = block-&gt;at(i);
+            if (value != description.extra &amp;&amp; value-&gt;opcode() != Nop)
+                m_insertionSet.insertValue(predecessor-&gt;size() - 1, value);
+        }
+        m_insertionSet.execute(predecessor);
+        block-&gt;values().resize(0);
+        block-&gt;appendNew&lt;Value&gt;(m_proc, Oops, description.branch-&gt;origin());
+        block-&gt;removePredecessor(predecessor);
+        
+        for (BasicBlock* successorBlock : description.block-&gt;successorBlocks())
+            successorBlock-&gt;replacePredecessor(block, predecessor);
+
+        block-&gt;clearSuccessors();
+        
+        SwitchValue* switchValue = predecessor-&gt;replaceLastWithNew&lt;SwitchValue&gt;(
+            m_proc, predecessor-&gt;last()-&gt;origin(), description.source);
+        predecessor-&gt;clearSuccessors();
+        switchValue-&gt;setFallThrough(description.fallThrough);
+        
+        Vector&lt;int64_t&gt; predecessorCases;
+        for (SwitchCase switchCase : predecessorDescription.cases) {
+            switchValue-&gt;appendCase(switchCase);
+            predecessorCases.append(switchCase.caseValue());
+        }
+        std::sort(predecessorCases.begin(), predecessorCases.end());
+        auto isPredecessorCase = [&amp;] (int64_t value) -&gt; bool {
+            return !!tryBinarySearch&lt;int64_t&gt;(
+                predecessorCases, predecessorCases.size(), value,
+                [] (int64_t* element) -&gt; int64_t { return *element; });
+        };
+        
+        for (SwitchCase switchCase : description.cases) {
+            if (!isPredecessorCase(switchCase.caseValue()))
+                switchValue-&gt;appendCase(switchCase);
+        }
+        return true;
+    }
+
+    struct SwitchDescription {
+        SwitchDescription()
+        {
+        }
+        
+        explicit operator bool() { return !!block; }
+        
+        void dump(PrintStream&amp; out) const
+        {
+            out.print(
+                &quot;{block = &quot;, pointerDump(block),
+                &quot;, branch = &quot;, pointerDump(branch),
+                &quot;, extra = &quot;, pointerDump(extra),
+                &quot;, source = &quot;, pointerDump(source),
+                &quot;, cases = &quot;, listDump(cases),
+                &quot;, fallThrough = &quot;, fallThrough, &quot;}&quot;);
+        }
+
+        BasicBlock* block { nullptr };
+        Value* branch { nullptr };
+        Value* extra { nullptr }; // This is the Equal or NotEqual value, if applicable.
+        Value* source { nullptr };
+        Vector&lt;SwitchCase, 1&gt; cases;
+        FrequentedBlock fallThrough;
+    };
+    
+    SwitchDescription describe(BasicBlock* block)
+    {
+        SwitchDescription result;
+        result.block = block;
+        result.branch = block-&gt;last();
+        
+        switch (result.branch-&gt;opcode()) {
+        case Branch: {
+            Value* predicate = result.branch-&gt;child(0);
+            FrequentedBlock taken = result.block-&gt;taken();
+            FrequentedBlock notTaken = result.block-&gt;notTaken();
+            bool handled = false;
+            // NOTE: This uses UseCounts that we computed before any transformation. This is fine
+            // because although we may have mutated the IR, we would not have added any new
+            // predicates.
+            if (predicate-&gt;numChildren() == 2
+                &amp;&amp; predicate-&gt;child(1)-&gt;hasInt()
+                &amp;&amp; m_useCounts.numUses(predicate) == 1) {
+                switch (predicate-&gt;opcode()) {
+                case Equal:
+                    result.source = predicate-&gt;child(0);
+                    result.extra = predicate;
+                    result.cases.append(SwitchCase(predicate-&gt;child(1)-&gt;asInt(), taken));
+                    result.fallThrough = notTaken;
+                    handled = true;
+                    break;
+                case NotEqual:
+                    result.source = predicate-&gt;child(0);
+                    result.extra = predicate;
+                    result.cases.append(SwitchCase(predicate-&gt;child(1)-&gt;asInt(), notTaken));
+                    result.fallThrough = taken;
+                    handled = true;
+                    break;
+                default:
+                    break;
+                }
+            }
+            if (handled)
+                break;
+            result.source = predicate;
+            result.cases.append(SwitchCase(0, notTaken));
+            result.fallThrough = taken;
+            break;
+        }
+            
+        case Switch: {
+            SwitchValue* switchValue = result.branch-&gt;as&lt;SwitchValue&gt;();
+            result.source = switchValue-&gt;child(0);
+            for (SwitchCase switchCase : switchValue-&gt;cases(result.block))
+                result.cases.append(switchCase);
+            result.fallThrough = result.block-&gt;fallThrough();
+            break;
+        }
+            
+        default:
+            result.block = nullptr;
+            result.branch = nullptr;
+            break;
+        }
+        
+        return result;
+    }
+    
+    Procedure&amp; m_proc;
+    InsertionSet m_insertionSet;
+    UseCounts m_useCounts;
+};
+
+} // anonymous namespace
+
+bool inferSwitches(Procedure&amp; proc)
+{
+    PhaseScope phaseScope(proc, &quot;inferSwitches&quot;);
+    InferSwitches inferSwitches(proc);
+    return inferSwitches.run();
+}
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3InferSwitchesh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/b3/B3InferSwitches.h (0 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3InferSwitches.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/b3/B3InferSwitches.h        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef B3InferSwitches_h
+#define B3InferSwitches_h
+
+#if ENABLE(B3_JIT)
+
+namespace JSC { namespace B3 {
+
+class Procedure;
+
+// Fixpoints to convert chains of branches into switches.
+
+bool inferSwitches(Procedure&amp;);
+
+} } // namespace JSC::B3
+
+#endif // ENABE(B3_JIT)
+
+#endif // B3InferSwitches_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ReduceStrengthcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -417,7 +417,30 @@
</span><span class="cx">                 dataLog(&quot;B3 after iteration #&quot;, index - 1, &quot; of reduceStrength:\n&quot;);
</span><span class="cx">                 dataLog(m_proc);
</span><span class="cx">             }
</span><ins>+            
+            simplifyCFG();
</ins><span class="cx"> 
</span><ins>+            if (m_changedCFG) {
+                m_proc.resetReachability();
+                m_proc.invalidateCFG();
+                m_changed = true;
+            }
+
+            // We definitely want to do DCE before we do CSE so that we don't hoist things. For
+            // example:
+            //
+            // @dead = Mul(@a, @b)
+            // ... lots of control flow and stuff
+            // @thing = Mul(@a, @b)
+            //
+            // If we do CSE before DCE, we will remove @thing and keep @dead. Effectively, we will
+            // &quot;hoist&quot; @thing. On the other hand, if we run DCE before CSE, we will kill @dead and
+            // keep @thing. That's better, since we usually want things to stay wherever the client
+            // put them. We're not actually smart enough to move things around at random.
+            killDeadCode();
+            
+            simplifySSA();
+            
</ins><span class="cx">             m_proc.resetValueOwners();
</span><span class="cx">             m_dominators = &amp;m_proc.dominators(); // Recompute if necessary.
</span><span class="cx">             m_pureCSE.clear();
</span><span class="lines">@@ -440,23 +463,13 @@
</span><span class="cx">                 m_insertionSet.execute(m_block);
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            if (m_blockInsertionSet.execute()) {
-                m_proc.resetReachability();
-                m_proc.invalidateCFG();
-                m_dominators = &amp;m_proc.dominators(); // Recompute if necessary.
-                m_changedCFG = true;
-            }
-            
-            simplifyCFG();
-
</del><ins>+            m_changedCFG |= m_blockInsertionSet.execute();
</ins><span class="cx">             if (m_changedCFG) {
</span><span class="cx">                 m_proc.resetReachability();
</span><span class="cx">                 m_proc.invalidateCFG();
</span><ins>+                m_dominators = nullptr; // Dominators are not valid anymore, and we don't need them yet.
</ins><span class="cx">                 m_changed = true;
</span><span class="cx">             }
</span><del>-
-            killDeadCode();
-            simplifySSA();
</del><span class="cx">             
</span><span class="cx">             result |= m_changed;
</span><span class="cx">         } while (m_changed);
</span><span class="lines">@@ -2332,11 +2345,6 @@
</span><span class="cx">                     block-&gt;at(targetIndex++) = value;
</span><span class="cx">                 } else {
</span><span class="cx">                     m_proc.deleteValue(value);
</span><del>-                    
-                    // It's not entirely clear if this is needed. I think it makes sense to have
-                    // this force a rerun of the fixpoint for now, since that will make it easier
-                    // to do peephole optimizations: removing dead code will make the peephole
-                    // easier to spot.
</del><span class="cx">                     m_changed = true;
</span><span class="cx">                 }
</span><span class="cx">             }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.cpp (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.cpp        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/Source/JavaScriptCore/b3/B3Value.cpp        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -699,6 +699,21 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool Value::isFree() const
+{
+    switch (opcode()) {
+    case Const32:
+    case Const64:
+    case ConstDouble:
+    case ConstFloat:
+    case Identity:
+    case Nop:
+        return true;
+    default:
+        return false;
+    }
+}
+
</ins><span class="cx"> void Value::dumpMeta(CommaPrinter&amp;, PrintStream&amp;) const
</span><span class="cx"> {
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.h (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.h        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/Source/JavaScriptCore/b3/B3Value.h        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -188,7 +188,7 @@
</span><span class="cx">     virtual TriState aboveEqualConstant(const Value* other) const;
</span><span class="cx">     virtual TriState belowEqualConstant(const Value* other) const;
</span><span class="cx">     virtual TriState equalOrUnorderedConstant(const Value* other) const;
</span><del>-
</del><ins>+    
</ins><span class="cx">     // If the value is a comparison then this returns the inverted form of that comparison, if
</span><span class="cx">     // possible. It can be impossible for double comparisons, where for example LessThan and
</span><span class="cx">     // GreaterEqual behave differently. If this returns a value, it is a new value, which must be
</span><span class="lines">@@ -245,6 +245,11 @@
</span><span class="cx">     // repoint it at the Identity's child. For simplicity, this will follow arbitrarily long chains
</span><span class="cx">     // of Identity's.
</span><span class="cx">     void performSubstitution();
</span><ins>+    
+    // Free values are those whose presence is guaranteed not to hurt code. We consider constants,
+    // Identities, and Nops to be free. Constants are free because we hoist them to an optimal place.
+    // Identities and Nops are free because we remove them.
+    bool isFree() const;
</ins><span class="cx"> 
</span><span class="cx">     // Walk the ancestors of this value (i.e. the graph of things it transitively uses). This
</span><span class="cx">     // either walks phis or not, depending on whether PhiChildren is null. Your callback gets
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -590,6 +590,14 @@
</span><span class="cx">                 fixEdge&lt;ObjectUse&gt;(node-&gt;child2());
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><ins>+            if (node-&gt;child1()-&gt;shouldSpeculateSymbol()) {
+                fixEdge&lt;SymbolUse&gt;(node-&gt;child1());
+                break;
+            }
+            if (node-&gt;child2()-&gt;shouldSpeculateSymbol()) {
+                fixEdge&lt;SymbolUse&gt;(node-&gt;child2());
+                break;
+            }
</ins><span class="cx">             if (node-&gt;child1()-&gt;shouldSpeculateMisc()) {
</span><span class="cx">                 fixEdge&lt;MiscUse&gt;(node-&gt;child1());
</span><span class="cx">                 break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -5163,6 +5163,16 @@
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    if (node-&gt;isBinaryUseKind(SymbolUse, UntypedUse)) {
+        compileSymbolUntypedEquality(node, node-&gt;child1(), node-&gt;child2());
+        return false;
+    }
+    
+    if (node-&gt;isBinaryUseKind(UntypedUse, SymbolUse)) {
+        compileSymbolUntypedEquality(node, node-&gt;child2(), node-&gt;child1());
+        return false;
+    }
+    
</ins><span class="cx">     if (node-&gt;isBinaryUseKind(StringUse)) {
</span><span class="cx">         compileStringEquality(node);
</span><span class="cx">         return false;
</span><span class="lines">@@ -8269,6 +8279,36 @@
</span><span class="cx">     blessedBooleanResult(resultGPR, node);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SpeculativeJIT::compileSymbolUntypedEquality(Node* node, Edge symbolEdge, Edge untypedEdge)
+{
+    SpeculateCellOperand symbol(this, symbolEdge);
+    JSValueOperand untyped(this, untypedEdge);
+    GPRTemporary leftTemp(this);
+    GPRTemporary rightTemp(this);
+    
+    GPRReg symbolGPR = symbol.gpr();
+    JSValueRegs untypedRegs = untyped.jsValueRegs();
+    GPRReg leftTempGPR = leftTemp.gpr();
+    GPRReg rightTempGPR = rightTemp.gpr();
+    
+    speculateSymbol(symbolEdge, symbolGPR);
+    
+    JITCompiler::Jump notCell = m_jit.branchIfNotCell(untypedRegs);
+    JITCompiler::Jump isSymbol = m_jit.branchIfSymbol(untypedRegs.payloadGPR());
+    
+    notCell.link(&amp;m_jit);
+    m_jit.move(TrustedImm32(0), leftTempGPR);
+    JITCompiler::Jump done = m_jit.jump();
+    
+    isSymbol.link(&amp;m_jit);
+    m_jit.loadPtr(JITCompiler::Address(symbolGPR, Symbol::offsetOfPrivateName()), leftTempGPR);
+    m_jit.loadPtr(JITCompiler::Address(untypedRegs.payloadGPR(), Symbol::offsetOfPrivateName()), rightTempGPR);
+    m_jit.comparePtr(JITCompiler::Equal, leftTempGPR, rightTempGPR, leftTempGPR);
+    
+    done.link(&amp;m_jit);
+    unblessedBooleanResult(leftTempGPR, node);
+}
+
</ins><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx"> 
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -2405,6 +2405,7 @@
</span><span class="cx">     void extractStringImplFromBinarySymbols(Edge leftSymbolEdge, Edge rightSymbolEdge, const Functor&amp;);
</span><span class="cx">     void compileSymbolEquality(Node*);
</span><span class="cx">     void compilePeepHoleSymbolEquality(Node*, Node* branchNode);
</span><ins>+    void compileSymbolUntypedEquality(Node*, Edge symbolEdge, Edge untypedEdge);
</ins><span class="cx"> 
</span><span class="cx">     void emitObjectOrOtherBranch(Edge value, BasicBlock* taken, BasicBlock* notTaken);
</span><span class="cx">     void emitStringBranch(Edge value, BasicBlock* taken, BasicBlock* notTaken);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -411,6 +411,10 @@
</span><span class="cx">             break;
</span><span class="cx">         if (node-&gt;isBinaryUseKind(SymbolUse))
</span><span class="cx">             break;
</span><ins>+        if (node-&gt;isBinaryUseKind(SymbolUse, UntypedUse))
+            break;
+        if (node-&gt;isBinaryUseKind(UntypedUse, SymbolUse))
+            break;
</ins><span class="cx">         if (node-&gt;isBinaryUseKind(MiscUse, UntypedUse))
</span><span class="cx">             break;
</span><span class="cx">         if (node-&gt;isBinaryUseKind(UntypedUse, MiscUse))
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (203490 => 203491)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-07-21 06:12:13 UTC (rev 203490)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-07-21 06:23:10 UTC (rev 203491)
</span><span class="lines">@@ -2380,8 +2380,7 @@
</span><span class="cx">     {
</span><span class="cx">         UniquedStringImpl* uid = m_node-&gt;uidOperand();
</span><span class="cx">         if (uid-&gt;isSymbol()) {
</span><del>-            LValue symbol = lowSymbol(m_node-&gt;child1());
-            LValue stringImpl = m_out.loadPtr(symbol, m_heaps.Symbol_privateName);
</del><ins>+            LValue stringImpl = lowSymbolUID(m_node-&gt;child1());
</ins><span class="cx">             speculate(BadIdent, noValue(), nullptr, m_out.notEqual(stringImpl, m_out.constIntPtr(uid)));
</span><span class="cx">         } else {
</span><span class="cx">             LValue string = lowStringIdent(m_node-&gt;child1());
</span><span class="lines">@@ -4939,14 +4938,49 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (m_node-&gt;isBinaryUseKind(SymbolUse)) {
</span><del>-            LValue left = lowSymbol(m_node-&gt;child1());
-            LValue right = lowSymbol(m_node-&gt;child2());
-            LValue leftStringImpl = m_out.loadPtr(left, m_heaps.Symbol_privateName);
-            LValue rightStringImpl = m_out.loadPtr(right, m_heaps.Symbol_privateName);
</del><ins>+            LValue leftStringImpl = lowSymbolUID(m_node-&gt;child1());
+            LValue rightStringImpl = lowSymbolUID(m_node-&gt;child2());
</ins><span class="cx">             setBoolean(m_out.equal(leftStringImpl, rightStringImpl));
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         
</span><ins>+        if (m_node-&gt;isBinaryUseKind(SymbolUse, UntypedUse)
+            || m_node-&gt;isBinaryUseKind(UntypedUse, SymbolUse)) {
+            Edge symbolEdge = m_node-&gt;child1();
+            Edge untypedEdge = m_node-&gt;child2();
+            if (symbolEdge.useKind() != SymbolUse)
+                std::swap(symbolEdge, untypedEdge);
+            
+            LValue leftStringImpl = lowSymbolUID(symbolEdge);
+            LValue untypedValue = lowJSValue(untypedEdge);
+            
+            LBasicBlock isCellCase = m_out.newBlock();
+            LBasicBlock isSymbolCase = m_out.newBlock();
+            LBasicBlock continuation = m_out.newBlock();
+            
+            ValueFromBlock notSymbolResult = m_out.anchor(m_out.booleanFalse);
+            m_out.branch(
+                isCell(untypedValue, provenType(untypedEdge)),
+                unsure(isCellCase), unsure(continuation));
+            
+            LBasicBlock lastNext = m_out.appendTo(isCellCase, isSymbolCase);
+            m_out.branch(
+                isSymbol(untypedValue, provenType(untypedEdge)),
+                unsure(isSymbolCase), unsure(continuation));
+            
+            m_out.appendTo(isSymbolCase, continuation);
+            ValueFromBlock symbolResult =
+                m_out.anchor(
+                    m_out.equal(
+                        m_out.loadPtr(untypedValue, m_heaps.Symbol_privateName),
+                        leftStringImpl));
+            m_out.jump(continuation);
+            
+            m_out.appendTo(continuation, lastNext);
+            setBoolean(m_out.phi(Int32, notSymbolResult, symbolResult));
+            return;
+        }
+        
</ins><span class="cx">         if (m_node-&gt;isBinaryUseKind(MiscUse, UntypedUse)
</span><span class="cx">             || m_node-&gt;isBinaryUseKind(UntypedUse, MiscUse)) {
</span><span class="cx">             speculate(m_node-&gt;child1());
</span><span class="lines">@@ -9736,6 +9770,16 @@
</span><span class="cx">         speculateSymbol(edge, result);
</span><span class="cx">         return result;
</span><span class="cx">     }
</span><ins>+    
+    LValue lowSymbolUID(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+    {
+        if (Symbol* symbol = edge-&gt;dynamicCastConstant&lt;Symbol*&gt;())
+            return m_out.constIntPtr(symbol-&gt;privateName().uid());
+        LValue symbol = lowSymbol(edge, mode);
+        // FIXME: We could avoid this load if we had hash-consed Symbols.
+        // https://bugs.webkit.org/show_bug.cgi?id=158908
+        return m_out.loadPtr(symbol, m_heaps.Symbol_privateName);
+    }
</ins><span class="cx"> 
</span><span class="cx">     LValue lowNonNullObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
</span><span class="cx">     {
</span><span class="lines">@@ -10288,6 +10332,15 @@
</span><span class="cx">             m_out.load32(cell, m_heaps.JSCell_structureID),
</span><span class="cx">             m_out.constInt32(vm().symbolStructure-&gt;id()));
</span><span class="cx">     }
</span><ins>+    
+    LValue isSymbol(LValue cell, SpeculatedType type = SpecFullTop)
+    {
+        if (LValue proven = isProvenValue(type &amp; SpecCell, SpecSymbol))
+            return proven;
+        return m_out.equal(
+            m_out.load32(cell, m_heaps.JSCell_structureID),
+            m_out.constInt32(vm().symbolStructure-&gt;id()));
+    }
</ins><span class="cx"> 
</span><span class="cx">     LValue isArrayType(LValue cell, ArrayMode arrayMode)
</span><span class="cx">     {
</span></span></pre>
</div>
</div>

</body>
</html>